Codebase list libcommons-lang3-java / ca522c7
Imported Upstream version 3.0.1 Damien Raude-Morvan 12 years ago
265 changed file(s) with 105932 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
0 Apache Commons Lang
1 Copyright 2001-2011 The Apache Software Foundation
2
3 This product includes software developed by
4 The Apache Software Foundation (http://www.apache.org/).
5
6 This product includes software from the Spring Framework,
7 under the Apache License 2.0 (see: StringUtils.containsWhitespace())
0 $Id: RELEASE-NOTES.txt 1154104 2011-08-05 07:28:15Z bayard $
1
2 Commons Lang Package
3 Version 3.0.1
4 Release Notes
5
6
7 INTRODUCTION:
8
9 This document contains the release notes for the 3.0.1 version of Apache Commons Lang.
10 Commons Lang is a set of utility functions and reusable components that should be of use in any
11 Java environment.
12
13 Lang 3.0 and onwards now targets Java 5.0, making use of features that arrived with Java 5.0 such as generics,
14 variable arguments, autoboxing, concurrency and formatted output.
15
16 For the advice on upgrading from 2.x to 3.x, see the following page:
17
18 http://commons.apache.org/lang/article3_0.html
19
20 CHANGES IN 3.0.1
21 ================
22
23 [LANG-686] Improve exception message when StringUtils.replaceEachRepeatedly detects recursion
24 [LANG-717] Specify source encoding for Ant build
25 [LANG-721] Complement ArrayUtils.addAll() variants with by-index and by-value removal methods
26 [LANG-726] Add Range<T> Range<T>.intersectionWith(Range<T>)
27 [LANG-723] Add mode and median Comparable... methods to ObjectUtils
28 [LANG-722] Add BooleanUtils.and + or varargs methods
29 [LANG-730] EnumSet -> bit vector
30 [LANG-735] Deprecate CharUtils.toCharacterObject(char) in favor of java.lang.Character.valueOf(char)
31 [LANG-737] Missing method getRawMessage for ContextedException and ContextedRuntimeException
32
33 BUG FIXES IN 3.0.1
34 ==================
35
36 [LANG-626] SerializationUtils.clone: Fallback to context classloader if class not found in current classloader
37 [LANG-727] ToStringBuilderTest.testReflectionHierarchyArrayList fails with IBM JDK 6
38 [LANG-720] StringEscapeUtils.escapeXml(input) wrong when input contains characters in Supplementary Planes
39 [LANG-708] StringEscapeUtils.escapeEcmaScript from lang3 cuts off long unicode string
40 [LANG-734] The CHAR_ARRAY cache in CharUtils duplicates the cache in java.lang.Character
41 [LANG-738] Use internal Java's Number caches instead creating new objects
0 # Licensed to the Apache Software Foundation (ASF) under one or more
1 # contributor license agreements. See the NOTICE file distributed with
2 # this work for additional information regarding copyright ownership.
3 # The ASF licenses this file to You under the Apache License, Version 2.0
4 # (the "License"); you may not use this file except in compliance with
5 # the License. You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 ##########################################################################
15 # Sample Ant build.properties file
16 #
17 # This setup assumes dependent jars are in a local maven 2 repository.
18 # However the jars are located, the properties ending in ".jar" need
19 # expand to full paths to the jars.
20 ##########################################################################
21
22 # Repository base path - unnecessary if full jar paths are provided below
23 repository=${user.home}/.m2/repository
24 junit.home=${repository}/junit/junit/4.7/
25 easymock.home=${repository}/org/easymock/easymock/2.5.2/
26 commons-io.home=${repository}/commons-io/commons-io/2.0.1/
0 <!--
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 -->
20 <!--
21 "Lang" component of the Apache Commons Subproject
22 $Id: build.xml 1148152 2011-07-19 04:32:56Z bayard $
23 -->
24 <project name="Lang" default="compile" basedir=".">
25
26 <!-- ========== Initialize Properties ===================================== -->
27 <property file="${user.home}/${component.name}.build.properties"/>
28 <property file="${user.home}/build.properties"/>
29 <property file="${basedir}/build.properties"/>
30 <property file="${basedir}/default.properties"/>
31 <property name="jdk.javadoc" value="http://download.oracle.com/javase/1.5.0/docs/api/"/>
32
33 <!-- ========== Construct compile classpath =============================== -->
34 <path id="compile.classpath">
35 <pathelement location="${build.home}/classes"/>
36 </path>
37
38 <!-- ========== Construct unit test classpath ============================= -->
39 <path id="test.classpath">
40 <pathelement location="${build.home}/classes"/>
41 <pathelement location="${build.home}/tests"/>
42 <pathelement location="${junit.jar}"/>
43 <pathelement location="${easymock.jar}"/>
44 <pathelement location="${commons-io.jar}"/>
45 </path>
46
47 <!-- ========== Executable Targets ======================================== -->
48 <target name="init" description="Initialize and evaluate conditionals">
49 <echo message="-------- ${component.name} ${component.version} --------"/>
50 <filter token="name" value="${component.name}"/>
51 <filter token="package" value="${component.package}"/>
52 <filter token="version" value="${component.version}"/>
53 <filter token="compile.source" value="${compile.source}"/>
54 <filter token="compile.target" value="${compile.target}"/>
55 <mkdir dir="${build.home}"/>
56 </target>
57
58 <!-- ========== Compile Targets ========================================= -->
59 <target name="compile" depends="init" description="Compile shareable components">
60 <mkdir dir="${build.home}/classes"/>
61 <javac srcdir="${source.home}" destdir="${build.home}/classes" debug="${compile.debug}" deprecation="${compile.deprecation}" target="${compile.target}" source="${compile.source}" excludes="${compile.excludes}" optimize="${compile.optimize}" includeantruntime="false" encoding="${compile.encoding}">
62 <classpath refid="compile.classpath"/>
63 </javac>
64 <copy todir="${build.home}/classes" filtering="on">
65 <fileset dir="${source.home}" excludes="**/*.java"/>
66 </copy>
67 </target>
68
69 <target name="compile.tests" depends="compile" description="Compile unit test cases">
70 <mkdir dir="${build.home}/tests"/>
71 <javac srcdir="${test.home}" destdir="${build.home}/tests" debug="${compile.debug}" deprecation="off" target="${compile.target}" source="${compile.source}" optimize="${compile.optimize}" includeantruntime="false" encoding="${compile.encoding}">
72 <classpath refid="test.classpath"/>
73 </javac>
74 <copy todir="${build.home}/tests" filtering="on">
75 <fileset dir="${test.home}" excludes="**/*.java"/>
76 </copy>
77 </target>
78
79 <!-- ========== Unit Tests ========================================= -->
80 <target name="test" depends="compile.tests" description="Run all unit test cases">
81 <echo message="Running unit tests ..."/>
82 <mkdir dir="${build.home}/test-reports"/>
83 <junit printsummary="true" showoutput="true" fork="yes" haltonfailure="${test.failonerror}">
84 <classpath refid="test.classpath"/>
85 <formatter type="plain" usefile="true" />
86 <!-- If test.entry is defined, run a single test, otherwise run all valid tests -->
87 <test name="${test.entry}" todir="${build.home}/test-reports" if="test.entry"/>
88 <batchtest fork="yes" todir="${build.home}/test-reports" unless="test.entry">
89 <fileset dir="${test.home}">
90 <include name="**/*Test.java"/>
91 <exclude name="**/Abstract*Test.java"/>
92 </fileset>
93 </batchtest>
94 </junit>
95 </target>
96
97 <target name="clean" description="Clean build and distribution directories">
98 <delete dir="${build.home}"/>
99 </target>
100
101 <target name="all" depends="clean,test,compile" description="Clean and compile all components"/>
102
103 <!-- ========== JavaDocs ========================================= -->
104 <target name="javadoc" depends="compile" description="Create component Javadoc documentation">
105 <mkdir dir="${build.home}"/>
106 <mkdir dir="${build.home}/apidocs"/>
107 <tstamp>
108 <format property="current.year" pattern="yyyy"/>
109 </tstamp>
110 <javadoc sourcepath="${source.home}"
111 destdir="${build.home}/apidocs"
112 overview="${source.home}/org/apache/commons/lang3/overview.html"
113 packagenames="org.apache.commons.*"
114 excludepackagenames="${javadoc.excludepackagenames}"
115 author="false"
116 version="true"
117 doctitle="&lt;h1&gt;Commons Lang ${component.version}&lt;/h1&gt;"
118 windowtitle="Lang ${component.version}"
119 bottom="Copyright &amp;copy; 2001-${current.year} - Apache Software Foundation"
120 use="true"
121 link="${jdk.javadoc}"
122 encoding="${compile.encoding}"
123 source="${compile.source}">
124 <classpath refid="compile.classpath"/>
125 </javadoc>
126 </target>
127
128 <!-- ========== Jar Targets ========================================= -->
129 <target name="jar" depends="compile" description="Create jar">
130 <mkdir dir="${build.home}/classes/META-INF"/>
131 <copy file="LICENSE.txt" tofile="${build.home}/classes/META-INF/LICENSE.txt"/>
132 <copy file="NOTICE.txt" tofile="${build.home}/classes/META-INF/NOTICE.txt"/>
133 <jar jarfile="${build.home}/${final.name}.jar">
134 <manifest>
135 <attribute name="Specification-Title" value="Commons Lang"/>
136 <attribute name="Specification-Version" value="${component.version}"/>
137 <attribute name="Specification-Vendor" value="The Apache Software Foundation"/>
138 <attribute name="Implementation-Title" value="Commons Lang"/>
139 <attribute name="Implementation-Version" value="${component.version}"/>
140 <attribute name="Implementation-Vendor" value="The Apache Software Foundation"/>
141 <attribute name="Implementation-Vendor-Id" value="org.apache"/>
142 <attribute name="X-Compile-Source-JDK" value="${compile.source}"/>
143 <attribute name="X-Compile-Target-JDK" value="${compile.target}"/>
144 </manifest>
145 <fileset dir="${build.home}/classes">
146 <include name="**/*.class"/>
147 <include name="**/LICENSE.txt"/>
148 <include name="**/NOTICE.txt"/>
149 </fileset>
150 </jar>
151 </target>
152
153 <target name="javadoc-jar" depends="javadoc" description="Create JavaDoc jar">
154 <jar jarfile="${build.home}/${final.name}-javadoc.jar">
155 <manifest>
156 <attribute name="Specification-Title" value="Commons Lang API"/>
157 <attribute name="Specification-Version" value="${component.version}"/>
158 <attribute name="Specification-Vendor" value="The Apache Software Foundation"/>
159 <attribute name="Implementation-Title" value="Commons Lang API"/>
160 <attribute name="Implementation-Version" value="${component.version}"/>
161 <attribute name="Implementation-Vendor" value="The Apache Software Foundation"/>
162 <attribute name="Implementation-Vendor-Id" value="org.apache"/>
163 </manifest>
164 <fileset dir="${build.home}/apidocs"/>
165 <fileset dir="${basedir}">
166 <include name="LICENSE.txt"/>
167 <include name="NOTICE.txt"/>
168 </fileset>
169 </jar>
170 </target>
171
172 <target name="source-jar" depends="init" description="Create JavaDoc jar">
173 <jar jarfile="${build.home}/${final.name}-sources.jar">
174 <manifest>
175 <attribute name="Specification-Title" value="Commons Lang Source"/>
176 <attribute name="Specification-Version" value="${component.version}"/>
177 <attribute name="Specification-Vendor" value="The Apache Software Foundation"/>
178 <attribute name="Implementation-Title" value="Commons Lang Source"/>
179 <attribute name="Implementation-Version" value="${component.version}"/>
180 <attribute name="Implementation-Vendor" value="The Apache Software Foundation"/>
181 <attribute name="Implementation-Vendor-Id" value="org.apache"/>
182 </manifest>
183 <fileset dir="${source.home}">
184 <include name="**/*.java"/>
185 </fileset>
186 <fileset dir="${basedir}">
187 <include name="LICENSE.txt"/>
188 <include name="NOTICE.txt"/>
189 </fileset>
190 </jar>
191 </target>
192
193 <!-- ========== Distribution ========================================= -->
194 <target name="dist" depends="clean,jar,source-jar,javadoc-jar" description="Create binary distribution">
195
196 <!-- binary distro -->
197 <zip destfile="${build.home}/${final.name}.zip">
198 <zipfileset dir="${basedir}" prefix="${final.name}"
199 includes="LICENSE.txt,
200 NOTICE.txt,
201 RELEASE-NOTES.txt"
202 />
203 <zipfileset dir="${build.home}" includes="*.jar," prefix="${final.name}"/>
204 <zipfileset dir="${build.home}/apidocs" prefix="${final.name}/apidocs"/>
205 </zip>
206 <tar destfile="${build.home}/${final.name}.tar.gz" compression="gzip">
207 <zipfileset src="${build.home}/${final.name}.zip"/>
208 </tar>
209
210 <!-- source distro -->
211 <zip destfile="${build.home}/${final.name}-src.zip">
212 <zipfileset dir="${basedir}" prefix="${final.name}-src"
213 includes="build.xml,
214 build.xml,
215 checkstyle.xml,
216 default.properties,
217 LICENSE.txt,
218 NOTICE.txt,
219 pom.xml,
220 RELEASE-NOTES.txt"
221 />
222 <zipfileset dir="${basedir}/src" prefix="${final.name}-src/src"/>
223 </zip>
224 <tar destfile="${build.home}/${final.name}-src.tar.gz" compression="gzip">
225 <zipfileset src="${build.home}/${final.name}-src.zip"/>
226 </tar>
227
228 </target>
229 </project>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17
18 <!DOCTYPE module PUBLIC
19 "-//Puppy Crawl//DTD Check Configuration 1.1//EN"
20 "http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
21
22 <!-- commons lang customization of default Checkstyle behavior -->
23 <module name="Checker">
24 <property name="localeLanguage" value="en"/>
25 <module name="JavadocPackage">
26 <!-- setting allowLegacy means it will check for package.html instead of just package-info.java -->
27 <property name="allowLegacy" value="true"/>
28 </module>
29 <module name="FileTabCharacter">
30 <property name="fileExtensions" value="java,xml"/>
31 </module>
32 <module name="TreeWalker">
33 <module name="AvoidStarImport"/>
34 <module name="RedundantImport"/>
35 <module name="UnusedImports"/>
36 <module name="NeedBraces"/>
37 <module name="RedundantThrows">
38 <property name="allowUnchecked" value="true"/>
39 </module>
40 <module name="JavadocMethod">
41 <property name="allowUndeclaredRTE" value="true"/>
42 </module>
43 </module>
44 </module>
45
46
0 #
1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements. See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16
17 # $Id: default.properties 1154105 2011-08-05 07:28:53Z bayard $
18
19 # The location of the "junit.jar" JAR file
20 junit.jar = ${junit.home}/junit-4.7.jar
21
22 # The location of the Easymock jar
23 easymock.jar = ${easymock.home}/easymock-2.5.2.jar
24
25 # The location of the Commons-IO jar
26 commons-io.jar = ${commons-io.home}/commons-io-2.0.1.jar
27
28 # Whether or not to fork tests
29 junit.fork = true
30
31 # The name of this component
32 component.name = commons-lang
33
34 # The primary package name of this component
35 component.package = org.apache.commons.lang3
36
37 # The title of this component
38 component.title = Core Language Utilities
39
40 # The current version number of this component
41 component.version = 3.0.1
42
43 # The name that is used to create the jar file
44 final.name = ${component.name}-${component.version}
45
46 # The base directory for compilation targets
47 build.home = target
48
49 # The base directory for component configuration files
50 conf.home = src/conf
51
52 # The base directory for component sources
53 source.home = src/main/java
54
55 # The base directory for unit test sources
56 test.home = src/test/java
57
58 # Should Java compilations set the 'debug' compiler option?
59 compile.debug = true
60
61 # Should Java compilations set the 'deprecation' compiler option?
62 compile.deprecation = true
63
64 # Should Java compilations set the 'optimize' compiler option?
65 compile.optimize = true
66
67 # Generate class files for specific VM version (e.g., 1.1 or 1.2).
68 # Note that the default value depends on the JVM that is running Ant.
69 # In particular, if you use JDK 1.4+ the generated classes will not be usable
70 # for a 1.1 Java VM unless you explicitly set this attribute to the value 1.1
71 # (which is the default value for JDK 1.1 to 1.3).
72 compile.target = 1.5
73
74 # Specifies the source version for the Java compiler.
75 # Corresponds to the source attribute for the ant javac task.
76 # Valid values are 1.3, 1.4, 1.5.
77 compile.source = 1.5
78
79 # Specifies the source encoding.
80 compile.encoding = ISO-8859-1
81
82 # Should all tests fail if one does?
83 test.failonerror = true
84
85 # The test runner to execute
86 test.runner = junit.textui.TestRunner
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17
18 <!--
19 This file contains some false positive bugs detected by findbugs. Their
20 false positive nature has been analyzed individually and they have been
21 put here to instruct findbugs it must ignore them.
22 -->
23 <FindBugsFilter>
24
25 <!-- Reason: Optimization to use == -->
26 <Match>
27 <Class name="org.apache.commons.lang3.BooleanUtils" />
28 <Or>
29 <Method name="toBoolean" />
30 <Method name="toBooleanObject" />
31 </Or>
32 <Bug pattern="ES_COMPARING_PARAMETER_STRING_WITH_EQ" />
33 </Match>
34 <Match>
35 <Class name="org.apache.commons.lang3.BooleanUtils" />
36 <Method name="toBoolean" />
37 <Bug pattern="RC_REF_COMPARISON_BAD_PRACTICE_BOOLEAN" />
38 </Match>
39
40 <!-- Reason: Behavior documented in javadoc -->
41 <Match>
42 <Class name="org.apache.commons.lang3.BooleanUtils" />
43 <Or>
44 <Method name="negate" />
45 <Method name="toBooleanObject" />
46 </Or>
47 <Bug pattern="NP_BOOLEAN_RETURN_NULL" />
48 </Match>
49
50 <!-- Reason: base class cannot be changed and field is properly checked against null so behavior is OK -->
51 <Match>
52 <Class name="org.apache.commons.lang3.text.ExtendedMessageFormat" />
53 <Method name="applyPattern" />
54 <Bug pattern="UR_UNINIT_READ_CALLED_FROM_SUPER_CONSTRUCTOR" />
55 </Match>
56
57 <!-- Reason: Optimization to use == -->
58 <Match>
59 <Class name="org.apache.commons.lang3.StringUtils" />
60 <Method name="indexOfDifference"/>
61 <Bug pattern="ES_COMPARING_PARAMETER_STRING_WITH_EQ" />
62 </Match>
63
64 <!-- Reason: Very much intended to do a fall through on the switch -->
65 <Match>
66 <Class name="org.apache.commons.lang3.math.NumberUtils" />
67 <Method name="createNumber"/>
68 <Bug pattern="SF_SWITCH_FALLTHROUGH" />
69 </Match>
70
71 <!-- Reason: Very much intended to do a fall through on the switch -->
72 <Match>
73 <Class name="org.apache.commons.lang3.time.DateUtils" />
74 <Method name="getFragment"/>
75 <Bug pattern="SF_SWITCH_FALLTHROUGH" />
76 </Match>
77
78 <!-- Reason: hashCode is lazily loaded in Range classes -->
79 <!-- TODO: Work out why regex didn't work here -->
80 <Match>
81 <Class name="org.apache.commons.lang3.math.DoubleRange" />
82 <Field name="hashCode" />
83 <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED" />
84 </Match>
85 <Match>
86 <Class name="org.apache.commons.lang3.math.FloatRange" />
87 <Field name="hashCode" />
88 <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED" />
89 </Match>
90 <Match>
91 <Class name="org.apache.commons.lang3.math.IntRange" />
92 <Field name="hashCode" />
93 <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED" />
94 </Match>
95 <Match>
96 <Class name="org.apache.commons.lang3.math.LongRange" />
97 <Field name="hashCode" />
98 <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED" />
99 </Match>
100 <Match>
101 <Class name="org.apache.commons.lang3.math.NumberRange" />
102 <Field name="hashCode" />
103 <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED" />
104 </Match>
105
106 <!-- Reason: toProperString is lazily loaded -->
107 <Match>
108 <Class name="org.apache.commons.lang3.math.Fraction" />
109 <Field name="toProperString" />
110 <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED" />
111 </Match>
112
113 <!-- Reason: It does call super.clone(), but via a subsequent method -->
114 <Match>
115 <Class name="org.apache.commons.lang3.text.StrTokenizer" />
116 <Method name="clone"/>
117 <Bug pattern="CN_IDIOM_NO_SUPER_CALL" />
118 </Match>
119
120 <!-- Reason: Testing shows that new Integer(...) etc is quicker than Integer.valueOf -->
121 <Match>
122 <Bug pattern="DM_NUMBER_CTOR" />
123 </Match>
124
125 </FindBugsFilter>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <project
18 xmlns="http://maven.apache.org/POM/4.0.0"
19 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
21 <parent>
22 <groupId>org.apache.commons</groupId>
23 <artifactId>commons-parent</artifactId>
24 <version>21</version>
25 </parent>
26 <modelVersion>4.0.0</modelVersion>
27 <groupId>org.apache.commons</groupId>
28 <artifactId>commons-lang3</artifactId>
29 <version>3.0.1</version>
30 <name>Commons Lang</name>
31
32 <inceptionYear>2001</inceptionYear>
33 <description>
34 Commons Lang, a package of Java utility classes for the
35 classes that are in java.lang's hierarchy, or are considered to be so
36 standard as to justify existence in java.lang.
37 </description>
38
39 <url>http://commons.apache.org/lang/</url>
40
41 <issueManagement>
42 <system>jira</system>
43 <url>http://issues.apache.org/jira/browse/LANG</url>
44 </issueManagement>
45
46 <scm>
47 <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/lang/trunk</connection>
48 <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/lang/trunk</developerConnection>
49 <url>http://svn.apache.org/viewvc/commons/proper/lang/trunk</url>
50 </scm>
51
52 <developers>
53 <developer>
54 <name>Daniel Rall</name>
55 <id>dlr</id>
56 <email>dlr@finemaltcoding.com</email>
57 <organization>CollabNet, Inc.</organization>
58 <roles>
59 <role>Java Developer</role>
60 </roles>
61 </developer>
62 <developer>
63 <name>Stephen Colebourne</name>
64 <id>scolebourne</id>
65 <email>scolebourne@joda.org</email>
66 <organization>SITA ATS Ltd</organization>
67 <timezone>0</timezone>
68 <roles>
69 <role>Java Developer</role>
70 </roles>
71 </developer>
72 <developer>
73 <name>Henri Yandell</name>
74 <id>bayard</id>
75 <email>bayard@apache.org</email>
76 <organization/>
77 <roles>
78 <role>Java Developer</role>
79 </roles>
80 </developer>
81 <developer>
82 <name>Steven Caswell</name>
83 <id>scaswell</id>
84 <email>stevencaswell@apache.org</email>
85 <organization/>
86 <roles>
87 <role>Java Developer</role>
88 </roles>
89 <timezone>-5</timezone>
90 </developer>
91 <developer>
92 <name>Robert Burrell Donkin</name>
93 <id>rdonkin</id>
94 <email>rdonkin@apache.org</email>
95 <organization/>
96 <roles>
97 <role>Java Developer</role>
98 </roles>
99 </developer>
100 <developer>
101 <name>Gary D. Gregory</name>
102 <id>ggregory</id>
103 <email>ggregory@seagullsw.com</email>
104 <organization>Seagull Software</organization>
105 <timezone>-8</timezone>
106 <roles>
107 <role>Java Developer</role>
108 </roles>
109 </developer>
110 <developer>
111 <name>Phil Steitz</name>
112 <id>psteitz</id>
113 <organization/>
114 <roles>
115 <role>Java Developer</role>
116 </roles>
117 </developer>
118 <developer>
119 <name>Fredrik Westermarck</name>
120 <id>fredrik</id>
121 <email/>
122 <organization/>
123 <roles>
124 <role>Java Developer</role>
125 </roles>
126 </developer>
127 <developer>
128 <name>James Carman</name>
129 <id>jcarman</id>
130 <email>jcarman@apache.org</email>
131 <organization>Carman Consulting, Inc.</organization>
132 <roles>
133 <role>Java Developer</role>
134 </roles>
135 </developer>
136 <developer>
137 <name>Niall Pemberton</name>
138 <id>niallp</id>
139 <roles>
140 <role>Java Developer</role>
141 </roles>
142 </developer>
143 <developer>
144 <name>Matt Benson</name>
145 <id>mbenson</id>
146 <roles>
147 <role>Java Developer</role>
148 </roles>
149 </developer>
150 <developer>
151 <name>Joerg Schaible</name>
152 <id>joehni</id>
153 <email>joerg.schaible@gmx.de</email>
154 <roles>
155 <role>Java Developer</role>
156 </roles>
157 <timezone>+1</timezone>
158 </developer>
159 <developer>
160 <name>Oliver Heger</name>
161 <id>oheger</id>
162 <email>oheger@apache.org</email>
163 <timezone>+1</timezone>
164 <roles>
165 <role>Java Developer</role>
166 </roles>
167 </developer>
168 <developer>
169 <name>Paul Benedict</name>
170 <id>pbenedict</id>
171 <email>pbenedict@apache.org</email>
172 <roles>
173 <role>Java Developer</role>
174 </roles>
175 </developer>
176 </developers>
177 <contributors>
178 <contributor>
179 <name>C. Scott Ananian</name>
180 </contributor>
181 <contributor>
182 <name>Chris Audley</name>
183 </contributor>
184 <contributor>
185 <name>Stephane Bailliez</name>
186 </contributor>
187 <contributor>
188 <name>Michael Becke</name>
189 </contributor>
190 <contributor>
191 <name>Benjamin Bentmann</name>
192 </contributor>
193 <contributor>
194 <name>Ola Berg</name>
195 </contributor>
196 <contributor>
197 <name>Nathan Beyer</name>
198 </contributor>
199 <contributor>
200 <name>Stefan Bodewig</name>
201 </contributor>
202 <contributor>
203 <name>Janek Bogucki</name>
204 </contributor>
205 <contributor>
206 <name>Mike Bowler</name>
207 </contributor>
208 <contributor>
209 <name>Sean Brown</name>
210 </contributor>
211 <contributor>
212 <name>Alexander Day Chaffee</name>
213 </contributor>
214 <contributor>
215 <name>Al Chou</name>
216 </contributor>
217 <contributor>
218 <name>Greg Coladonato</name>
219 </contributor>
220 <contributor>
221 <name>Maarten Coene</name>
222 </contributor>
223 <contributor>
224 <name>Justin Couch</name>
225 </contributor>
226 <contributor>
227 <name>Michael Davey</name>
228 </contributor>
229 <contributor>
230 <name>Norm Deane</name>
231 </contributor>
232 <contributor>
233 <name>Ringo De Smet</name>
234 </contributor>
235 <contributor>
236 <name>Russel Dittmar</name>
237 </contributor>
238 <contributor>
239 <name>Steve Downey</name>
240 </contributor>
241 <contributor>
242 <name>Matthias Eichel</name>
243 </contributor>
244 <contributor>
245 <name>Christopher Elkins</name>
246 </contributor>
247 <contributor>
248 <name>Chris Feldhacker</name>
249 </contributor>
250 <contributor>
251 <name>Roland Foerther</name>
252 </contributor>
253 <contributor>
254 <name>Pete Gieser</name>
255 </contributor>
256 <contributor>
257 <name>Jason Gritman</name>
258 </contributor>
259 <contributor>
260 <name>Matthew Hawthorne</name>
261 </contributor>
262 <contributor>
263 <name>Michael Heuer</name>
264 </contributor>
265 <contributor>
266 <name>Chris Hyzer</name>
267 </contributor>
268 <contributor>
269 <name>Marc Johnson</name>
270 </contributor>
271 <contributor>
272 <name>Shaun Kalley</name>
273 </contributor>
274 <contributor>
275 <name>Tetsuya Kaneuchi</name>
276 </contributor>
277 <contributor>
278 <name>Nissim Karpenstein</name>
279 </contributor>
280 <contributor>
281 <name>Ed Korthof</name>
282 </contributor>
283 <contributor>
284 <name>Holger Krauth</name>
285 </contributor>
286 <contributor>
287 <name>Rafal Krupinski</name>
288 </contributor>
289 <contributor>
290 <name>Rafal Krzewski</name>
291 </contributor>
292 <contributor>
293 <name>Eli Lindsey</name>
294 </contributor>
295 <contributor>
296 <name>Sven Ludwig</name>
297 </contributor>
298 <contributor>
299 <name>Craig R. McClanahan</name>
300 </contributor>
301 <contributor>
302 <name>Rand McNeely</name>
303 </contributor>
304 <contributor>
305 <name>Hendrik Maryns</name>
306 </contributor>
307 <contributor>
308 <name>Dave Meikle</name>
309 </contributor>
310 <contributor>
311 <name>Nikolay Metchev</name>
312 </contributor>
313 <contributor>
314 <name>Kasper Nielsen</name>
315 </contributor>
316 <contributor>
317 <name>Tim O'Brien</name>
318 </contributor>
319 <contributor>
320 <name>Brian S O'Neill</name>
321 </contributor>
322 <contributor>
323 <name>Andrew C. Oliver</name>
324 </contributor>
325 <contributor>
326 <name>Alban Peignier</name>
327 </contributor>
328 <contributor>
329 <name>Moritz Petersen</name>
330 </contributor>
331 <contributor>
332 <name>Dmitri Plotnikov</name>
333 </contributor>
334 <contributor>
335 <name>Neeme Praks</name>
336 </contributor>
337 <contributor>
338 <name>Eric Pugh</name>
339 </contributor>
340 <contributor>
341 <name>Stephen Putman</name>
342 </contributor>
343 <contributor>
344 <name>Travis Reeder</name>
345 </contributor>
346 <contributor>
347 <name>Antony Riley</name>
348 </contributor>
349 <contributor>
350 <name>Valentin Rocher</name>
351 </contributor>
352 <contributor>
353 <name>Scott Sanders</name>
354 </contributor>
355 <contributor>
356 <name>Ralph Schaer</name>
357 </contributor>
358 <contributor>
359 <name>Henning P. Schmiedehausen</name>
360 </contributor>
361 <contributor>
362 <name>Sean Schofield</name>
363 </contributor>
364 <contributor>
365 <name>Robert Scholte</name>
366 </contributor>
367 <contributor>
368 <name>Reuben Sivan</name>
369 </contributor>
370 <contributor>
371 <name>Ville Skytta</name>
372 </contributor>
373 <contributor>
374 <name>David M. Sledge</name>
375 </contributor>
376 <contributor>
377 <name>Jan Sorensen</name>
378 </contributor>
379 <contributor>
380 <name>Glen Stampoultzis</name>
381 </contributor>
382 <contributor>
383 <name>Scott Stanchfield</name>
384 </contributor>
385 <contributor>
386 <name>Jon S. Stevens</name>
387 </contributor>
388 <contributor>
389 <name>Sean C. Sullivan</name>
390 </contributor>
391 <contributor>
392 <name>Ashwin Suresh</name>
393 </contributor>
394 <contributor>
395 <name>Helge Tesgaard</name>
396 </contributor>
397 <contributor>
398 <name>Arun Mammen Thomas</name>
399 </contributor>
400 <contributor>
401 <name>Masato Tezuka</name>
402 </contributor>
403 <contributor>
404 <name>Jeff Varszegi</name>
405 </contributor>
406 <contributor>
407 <name>Chris Webb</name>
408 </contributor>
409 <contributor>
410 <name>Mario Winterer</name>
411 </contributor>
412 <contributor>
413 <name>Stepan Koltsov</name>
414 </contributor>
415 <contributor>
416 <name>Holger Hoffstatte</name>
417 </contributor>
418 <contributor>
419 <name>Derek C. Ashmore</name>
420 </contributor>
421 </contributors>
422
423 <!-- Lang should depend on very little -->
424 <dependencies>
425 <dependency>
426 <groupId>junit</groupId>
427 <artifactId>junit</artifactId>
428 <version>4.8.2</version>
429 <scope>test</scope>
430 </dependency>
431
432 <dependency>
433 <groupId>commons-io</groupId>
434 <artifactId>commons-io</artifactId>
435 <version>2.0.1</version>
436 <scope>test</scope>
437 </dependency>
438
439 <dependency>
440 <groupId>org.easymock</groupId>
441 <artifactId>easymock</artifactId>
442 <version>2.5.2</version>
443 <scope>test</scope>
444 </dependency>
445 </dependencies>
446
447 <properties>
448 <project.build.sourceEncoding>ISO-8859-1</project.build.sourceEncoding>
449 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
450 <maven.compile.source>1.5</maven.compile.source>
451 <maven.compile.target>1.5</maven.compile.target>
452 <commons.componentid>lang</commons.componentid>
453 <commons.release.version>3.0.1</commons.release.version>
454 <commons.release.desc>(Java 5.0+)</commons.release.desc>
455 <commons.release.2.version>2.6</commons.release.2.version>
456 <commons.release.2.desc>(Java 1.3+)</commons.release.2.desc>
457 <commons.jira.id>LANG</commons.jira.id>
458 <commons.jira.pid>12310481</commons.jira.pid>
459 </properties>
460
461
462 <build>
463 <plugins>
464 <plugin>
465 <groupId>org.apache.maven.plugins</groupId>
466 <artifactId>maven-surefire-plugin</artifactId>
467 <configuration>
468 <includes>
469 <include>**/*Test.java</include>
470 </includes>
471 </configuration>
472 </plugin>
473 <plugin>
474 <artifactId>maven-assembly-plugin</artifactId>
475 <configuration>
476 <descriptors>
477 <descriptor>src/assembly/bin.xml</descriptor>
478 <descriptor>src/assembly/src.xml</descriptor>
479 </descriptors>
480 <tarLongFileMode>gnu</tarLongFileMode>
481 </configuration>
482 </plugin>
483 <plugin>
484 <groupId>org.apache.maven.plugins</groupId>
485 <artifactId>maven-jar-plugin</artifactId>
486 <executions>
487 <execution>
488 <goals>
489 <goal>test-jar</goal>
490 </goals>
491 </execution>
492 </executions>
493 </plugin>
494 </plugins>
495 </build>
496
497 <reporting>
498 <plugins>
499 <plugin>
500 <groupId>org.apache.maven.plugins</groupId>
501 <artifactId>maven-changes-plugin</artifactId>
502 <version>2.3</version>
503 <configuration>
504 <xmlPath>${basedir}/src/site/changes/changes.xml</xmlPath>
505 <issueLinkTemplate>%URL%/%ISSUE%</issueLinkTemplate>
506 </configuration>
507 <reportSets>
508 <reportSet>
509 <reports>
510 <report>changes-report</report>
511 </reports>
512 </reportSet>
513 </reportSets>
514 </plugin>
515 <plugin>
516 <artifactId>maven-checkstyle-plugin</artifactId>
517 <version>2.6</version>
518 <configuration>
519 <configLocation>${basedir}/checkstyle.xml</configLocation>
520 <enableRulesSummary>false</enableRulesSummary>
521 </configuration>
522 </plugin>
523 <!-- Requires setting 'export MAVEN_OPTS="-Xmx512m" ' -->
524 <plugin>
525 <groupId>org.codehaus.mojo</groupId>
526 <artifactId>findbugs-maven-plugin</artifactId>
527 <version>2.3.1</version>
528 <configuration>
529 <threshold>Normal</threshold>
530 <effort>Default</effort>
531 <excludeFilterFile>${basedir}/findbugs-exclude-filter.xml</excludeFilterFile>
532 </configuration>
533 </plugin>
534 <plugin>
535 <groupId>org.codehaus.mojo</groupId>
536 <artifactId>cobertura-maven-plugin</artifactId>
537 <version>2.4</version>
538 </plugin>
539 <plugin>
540 <groupId>org.codehaus.mojo</groupId>
541 <artifactId>clirr-maven-plugin</artifactId>
542 <version>2.2.2</version>
543 <configuration>
544 <comparisonArtifacts>
545 <comparisonArtifact>
546 <groupId>org.apache.commons</groupId>
547 <artifactId>commons-lang3</artifactId>
548 <version>3.0</version>
549 </comparisonArtifact>
550 </comparisonArtifacts>
551 <minSeverity>info</minSeverity>
552 </configuration>
553 </plugin>
554 <plugin>
555 <artifactId>maven-pmd-plugin</artifactId>
556 <version>2.3</version>
557 <configuration>
558 <targetJdk>${maven.compile.target}</targetJdk>
559 </configuration>
560 <reportSets>
561 <reportSet>
562 <reports>
563 <report>pmd</report>
564 <report>cpd</report>
565 </reports>
566 </reportSet>
567 </reportSets>
568 </plugin>
569 <plugin>
570 <groupId>org.codehaus.mojo</groupId>
571 <artifactId>taglist-maven-plugin</artifactId>
572 <version>2.4</version>
573 <configuration>
574 <tags>
575 <tag>TODO</tag>
576 <tag>NOPMD</tag>
577 <tag>NOTE</tag>
578 </tags>
579 </configuration>
580 </plugin>
581 <plugin>
582 <groupId>org.codehaus.mojo</groupId>
583 <artifactId>javancss-maven-plugin</artifactId>
584 <version>2.0</version>
585 </plugin>
586 </plugins>
587 </reporting>
588
589 </project>
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <assembly>
17 <id>bin</id>
18 <formats>
19 <format>tar.gz</format>
20 <format>zip</format>
21 </formats>
22 <includeSiteDirectory>false</includeSiteDirectory>
23 <fileSets>
24 <fileSet>
25 <includes>
26 <include>LICENSE.txt</include>
27 <include>NOTICE.txt</include>
28 <include>RELEASE-NOTES.txt</include>
29 </includes>
30 </fileSet>
31 <fileSet>
32 <directory>target</directory>
33 <outputDirectory></outputDirectory>
34 <includes>
35 <include>*.jar</include>
36 </includes>
37 </fileSet>
38 <fileSet>
39 <directory>target/site/apidocs</directory>
40 <outputDirectory>apidocs</outputDirectory>
41 </fileSet>
42 </fileSets>
43 </assembly>
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <assembly>
17 <id>src</id>
18 <formats>
19 <format>tar.gz</format>
20 <format>zip</format>
21 </formats>
22 <baseDirectory>${project.artifactId}-${commons.release.version}-src</baseDirectory>
23 <fileSets>
24 <fileSet>
25 <includes>
26 <include>checkstyle.xml</include>
27 <include>findbugs-exclude-filter.xml</include>
28 <include>LICENSE.txt</include>
29 <include>NOTICE.txt</include>
30 <include>pom.xml</include>
31 <include>PROPOSAL.html</include>
32 <include>RELEASE-NOTES.txt</include>
33 <include>build.xml</include>
34 <include>default.properties</include>
35 <include>build.properties.sample</include>
36 </includes>
37 </fileSet>
38 <fileSet>
39 <directory>src</directory>
40 </fileSet>
41 </fileSets>
42 </assembly>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.lang.annotation.Annotation;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.util.Arrays;
22
23 import org.apache.commons.lang3.builder.ToStringBuilder;
24 import org.apache.commons.lang3.builder.ToStringStyle;
25
26 /**
27 * <p>Helper methods for working with {@link Annotation} instances.</p>
28 *
29 * <p>This class contains various utility methods that make working with
30 * annotations simpler.</p>
31 *
32 * <p>{@link Annotation} instances are always proxy objects; unfortunately
33 * dynamic proxies cannot be depended upon to know how to implement certain
34 * methods in the same manner as would be done by "natural" {@link Annotation}s.
35 * The methods presented in this class can be used to avoid that possibility. It
36 * is of course also possible for dynamic proxies to actually delegate their
37 * e.g. {@link Annotation#equals(Object)}/{@link Annotation#hashCode()}/
38 * {@link Annotation#toString()} implementations to {@link AnnotationUtils}.</p>
39 *
40 * <p>#ThreadSafe#</p>
41 *
42 * @since 3.0
43 * @version $Id: AnnotationUtils.java 1083850 2011-03-21 15:59:10Z mbenson $
44 */
45 public class AnnotationUtils {
46
47 /**
48 * A style that prints annotations as recommended.
49 */
50 private static final ToStringStyle TO_STRING_STYLE = new ToStringStyle() {
51 /** Serialization version */
52 private static final long serialVersionUID = 1L;
53
54 {
55 setDefaultFullDetail(true);
56 setArrayContentDetail(true);
57 setUseClassName(true);
58 setUseShortClassName(true);
59 setUseIdentityHashCode(false);
60 setContentStart("(");
61 setContentEnd(")");
62 setFieldSeparator(", ");
63 setArrayStart("[");
64 setArrayEnd("]");
65 }
66
67 /**
68 * {@inheritDoc}
69 */
70 @Override
71 protected String getShortClassName(java.lang.Class<?> cls) {
72 Class<? extends Annotation> annotationType = null;
73 for (Class<?> iface : ClassUtils.getAllInterfaces(cls)) {
74 if (Annotation.class.isAssignableFrom(iface)) {
75 @SuppressWarnings("unchecked")
76 //because we just checked the assignability
77 Class<? extends Annotation> found = (Class<? extends Annotation>) iface;
78 annotationType = found;
79 break;
80 }
81 }
82 return new StringBuilder(annotationType == null ? "" : annotationType.getName())
83 .insert(0, '@').toString();
84 }
85
86 /**
87 * {@inheritDoc}
88 */
89 @Override
90 protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
91 if (value instanceof Annotation) {
92 value = AnnotationUtils.toString((Annotation) value);
93 }
94 super.appendDetail(buffer, fieldName, value);
95 }
96
97 };
98
99 /**
100 * <p>{@code AnnotationUtils} instances should NOT be constructed in
101 * standard programming. Instead, the class should be used statically.</p>
102 *
103 * <p>This constructor is public to permit tools that require a JavaBean
104 * instance to operate.</p>
105 */
106 public AnnotationUtils() {
107 }
108
109 //-----------------------------------------------------------------------
110 /**
111 * <p>Checks if two annotations are equal using the criteria for equality
112 * presented in the {@link Annotation#equals(Object)} API docs.</p>
113 *
114 * @param a1 the first Annotation to compare, {@code null} returns
115 * {@code false} unless both are {@code null}
116 * @param a2 the second Annotation to compare, {@code null} returns
117 * {@code false} unless both are {@code null}
118 * @return {@code true} if the two annotations are {@code equal} or both
119 * {@code null}
120 */
121 public static boolean equals(Annotation a1, Annotation a2) {
122 if (a1 == a2) {
123 return true;
124 }
125 if (a1 == null || a2 == null) {
126 return false;
127 }
128 Class<? extends Annotation> type = a1.annotationType();
129 Class<? extends Annotation> type2 = a2.annotationType();
130 Validate.notNull(type, "Annotation %s with null annotationType()", a1);
131 Validate.notNull(type2, "Annotation %s with null annotationType()", a2);
132 if (!type.equals(type2)) {
133 return false;
134 }
135 try {
136 for (Method m : type.getDeclaredMethods()) {
137 if (m.getParameterTypes().length == 0
138 && isValidAnnotationMemberType(m.getReturnType())) {
139 Object v1 = m.invoke(a1);
140 Object v2 = m.invoke(a2);
141 if (!memberEquals(m.getReturnType(), v1, v2)) {
142 return false;
143 }
144 }
145 }
146 } catch (IllegalAccessException ex) {
147 return false;
148 } catch (InvocationTargetException ex) {
149 return false;
150 }
151 return true;
152 }
153
154 /**
155 * <p>Generate a hash code for the given annotation using the algorithm
156 * presented in the {@link Annotation#hashCode()} API docs.</p>
157 *
158 * @param a the Annotation for a hash code calculation is desired, not
159 * {@code null}
160 * @return the calculated hash code
161 * @throws RuntimeException if an {@code Exception} is encountered during
162 * annotation member access
163 * @throws IllegalStateException if an annotation method invocation returns
164 * {@code null}
165 */
166 public static int hashCode(Annotation a) {
167 int result = 0;
168 Class<? extends Annotation> type = a.annotationType();
169 for (Method m : type.getDeclaredMethods()) {
170 try {
171 Object value = m.invoke(a);
172 if (value == null) {
173 throw new IllegalStateException(
174 String.format("Annotation method %s returned null", m));
175 }
176 result += hashMember(m.getName(), value);
177 } catch (RuntimeException ex) {
178 throw ex;
179 } catch (Exception ex) {
180 throw new RuntimeException(ex);
181 }
182 }
183 return result;
184 }
185
186 /**
187 * <p>Generate a string representation of an Annotation, as suggested by
188 * {@link Annotation#toString()}.</p>
189 *
190 * @param a the annotation of which a string representation is desired
191 * @return the standard string representation of an annotation, not
192 * {@code null}
193 */
194 public static String toString(final Annotation a) {
195 ToStringBuilder builder = new ToStringBuilder(a, TO_STRING_STYLE);
196 for (Method m : a.annotationType().getDeclaredMethods()) {
197 if (m.getParameterTypes().length > 0) {
198 continue; //wtf?
199 }
200 try {
201 builder.append(m.getName(), m.invoke(a));
202 } catch (RuntimeException ex) {
203 throw ex;
204 } catch (Exception ex) {
205 throw new RuntimeException(ex);
206 }
207 }
208 return builder.build();
209 }
210
211 /**
212 * <p>Checks if the specified type is permitted as an annotation member.</p>
213 *
214 * <p>The Java language specification only permits certain types to be used
215 * in annotations. These include {@link String}, {@link Class}, primitive
216 * types, {@link Annotation}, {@link Enum}, and single-dimensional arrays of
217 * these types.</p>
218 *
219 * @param type the type to check, {@code null}
220 * @return {@code true} if the type is a valid type to use in an annotation
221 */
222 public static boolean isValidAnnotationMemberType(Class<?> type) {
223 if (type == null) {
224 return false;
225 }
226 if (type.isArray()) {
227 type = type.getComponentType();
228 }
229 return type.isPrimitive() || type.isEnum() || type.isAnnotation()
230 || String.class.equals(type) || Class.class.equals(type);
231 }
232
233 //besides modularity, this has the advantage of autoboxing primitives:
234 /**
235 * Helper method for generating a hash code for a member of an annotation.
236 *
237 * @param name the name of the member
238 * @param value the value of the member
239 * @return a hash code for this member
240 */
241 private static int hashMember(String name, Object value) {
242 int part1 = name.hashCode() * 127;
243 if (value.getClass().isArray()) {
244 return part1 ^ arrayMemberHash(value.getClass().getComponentType(), value);
245 }
246 if (value instanceof Annotation) {
247 return part1 ^ hashCode((Annotation) value);
248 }
249 return part1 ^ value.hashCode();
250 }
251
252 /**
253 * Helper method for checking whether two objects of the given type are
254 * equal. This method is used to compare the parameters of two annotation
255 * instances.
256 *
257 * @param type the type of the objects to be compared
258 * @param o1 the first object
259 * @param o2 the second object
260 * @return a flag whether these objects are equal
261 */
262 private static boolean memberEquals(Class<?> type, Object o1, Object o2) {
263 if (o1 == o2) {
264 return true;
265 }
266 if (o1 == null || o2 == null) {
267 return false;
268 }
269 if (type.isArray()) {
270 return arrayMemberEquals(type.getComponentType(), o1, o2);
271 }
272 if (type.isAnnotation()) {
273 return equals((Annotation) o1, (Annotation) o2);
274 }
275 return o1.equals(o2);
276 }
277
278 /**
279 * Helper method for comparing two objects of an array type.
280 *
281 * @param componentType the component type of the array
282 * @param o1 the first object
283 * @param o2 the second object
284 * @return a flag whether these objects are equal
285 */
286 private static boolean arrayMemberEquals(Class<?> componentType, Object o1, Object o2) {
287 if (componentType.isAnnotation()) {
288 return annotationArrayMemberEquals((Annotation[]) o1, (Annotation[]) o2);
289 }
290 if (componentType.equals(Byte.TYPE)) {
291 return Arrays.equals((byte[]) o1, (byte[]) o2);
292 }
293 if (componentType.equals(Short.TYPE)) {
294 return Arrays.equals((short[]) o1, (short[]) o2);
295 }
296 if (componentType.equals(Integer.TYPE)) {
297 return Arrays.equals((int[]) o1, (int[]) o2);
298 }
299 if (componentType.equals(Character.TYPE)) {
300 return Arrays.equals((char[]) o1, (char[]) o2);
301 }
302 if (componentType.equals(Long.TYPE)) {
303 return Arrays.equals((long[]) o1, (long[]) o2);
304 }
305 if (componentType.equals(Float.TYPE)) {
306 return Arrays.equals((float[]) o1, (float[]) o2);
307 }
308 if (componentType.equals(Double.TYPE)) {
309 return Arrays.equals((double[]) o1, (double[]) o2);
310 }
311 if (componentType.equals(Boolean.TYPE)) {
312 return Arrays.equals((boolean[]) o1, (boolean[]) o2);
313 }
314 return Arrays.equals((Object[]) o1, (Object[]) o2);
315 }
316
317 /**
318 * Helper method for comparing two arrays of annotations.
319 *
320 * @param a1 the first array
321 * @param a2 the second array
322 * @return a flag whether these arrays are equal
323 */
324 private static boolean annotationArrayMemberEquals(Annotation[] a1, Annotation[] a2) {
325 if (a1.length != a2.length) {
326 return false;
327 }
328 for (int i = 0; i < a1.length; i++) {
329 if (!equals(a1[i], a2[i])) {
330 return false;
331 }
332 }
333 return true;
334 }
335
336 /**
337 * Helper method for generating a hash code for an array.
338 *
339 * @param componentType the component type of the array
340 * @param o the array
341 * @return a hash code for the specified array
342 */
343 private static int arrayMemberHash(Class<?> componentType, Object o) {
344 if (componentType.equals(Byte.TYPE)) {
345 return Arrays.hashCode((byte[]) o);
346 }
347 if (componentType.equals(Short.TYPE)) {
348 return Arrays.hashCode((short[]) o);
349 }
350 if (componentType.equals(Integer.TYPE)) {
351 return Arrays.hashCode((int[]) o);
352 }
353 if (componentType.equals(Character.TYPE)) {
354 return Arrays.hashCode((char[]) o);
355 }
356 if (componentType.equals(Long.TYPE)) {
357 return Arrays.hashCode((long[]) o);
358 }
359 if (componentType.equals(Float.TYPE)) {
360 return Arrays.hashCode((float[]) o);
361 }
362 if (componentType.equals(Double.TYPE)) {
363 return Arrays.hashCode((double[]) o);
364 }
365 if (componentType.equals(Boolean.TYPE)) {
366 return Arrays.hashCode((boolean[]) o);
367 }
368 return Arrays.hashCode((Object[]) o);
369 }
370 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.lang.reflect.Array;
19 import java.util.Arrays;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.Map;
23
24 import org.apache.commons.lang3.builder.EqualsBuilder;
25 import org.apache.commons.lang3.builder.HashCodeBuilder;
26 import org.apache.commons.lang3.builder.ToStringBuilder;
27 import org.apache.commons.lang3.builder.ToStringStyle;
28 import org.apache.commons.lang3.mutable.MutableInt;
29
30 /**
31 * <p>Operations on arrays, primitive arrays (like {@code int[]}) and
32 * primitive wrapper arrays (like {@code Integer[]}).</p>
33 *
34 * <p>This class tries to handle {@code null} input gracefully.
35 * An exception will not be thrown for a {@code null}
36 * array input. However, an Object array that contains a {@code null}
37 * element may throw an exception. Each method documents its behaviour.</p>
38 *
39 * <p>#ThreadSafe#</p>
40 * @since 2.0
41 * @version $Id: ArrayUtils.java 1154216 2011-08-05 13:57:16Z mbenson $
42 */
43 public class ArrayUtils {
44
45 /**
46 * An empty immutable {@code Object} array.
47 */
48 public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
49 /**
50 * An empty immutable {@code Class} array.
51 */
52 public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class[0];
53 /**
54 * An empty immutable {@code String} array.
55 */
56 public static final String[] EMPTY_STRING_ARRAY = new String[0];
57 /**
58 * An empty immutable {@code long} array.
59 */
60 public static final long[] EMPTY_LONG_ARRAY = new long[0];
61 /**
62 * An empty immutable {@code Long} array.
63 */
64 public static final Long[] EMPTY_LONG_OBJECT_ARRAY = new Long[0];
65 /**
66 * An empty immutable {@code int} array.
67 */
68 public static final int[] EMPTY_INT_ARRAY = new int[0];
69 /**
70 * An empty immutable {@code Integer} array.
71 */
72 public static final Integer[] EMPTY_INTEGER_OBJECT_ARRAY = new Integer[0];
73 /**
74 * An empty immutable {@code short} array.
75 */
76 public static final short[] EMPTY_SHORT_ARRAY = new short[0];
77 /**
78 * An empty immutable {@code Short} array.
79 */
80 public static final Short[] EMPTY_SHORT_OBJECT_ARRAY = new Short[0];
81 /**
82 * An empty immutable {@code byte} array.
83 */
84 public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
85 /**
86 * An empty immutable {@code Byte} array.
87 */
88 public static final Byte[] EMPTY_BYTE_OBJECT_ARRAY = new Byte[0];
89 /**
90 * An empty immutable {@code double} array.
91 */
92 public static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
93 /**
94 * An empty immutable {@code Double} array.
95 */
96 public static final Double[] EMPTY_DOUBLE_OBJECT_ARRAY = new Double[0];
97 /**
98 * An empty immutable {@code float} array.
99 */
100 public static final float[] EMPTY_FLOAT_ARRAY = new float[0];
101 /**
102 * An empty immutable {@code Float} array.
103 */
104 public static final Float[] EMPTY_FLOAT_OBJECT_ARRAY = new Float[0];
105 /**
106 * An empty immutable {@code boolean} array.
107 */
108 public static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];
109 /**
110 * An empty immutable {@code Boolean} array.
111 */
112 public static final Boolean[] EMPTY_BOOLEAN_OBJECT_ARRAY = new Boolean[0];
113 /**
114 * An empty immutable {@code char} array.
115 */
116 public static final char[] EMPTY_CHAR_ARRAY = new char[0];
117 /**
118 * An empty immutable {@code Character} array.
119 */
120 public static final Character[] EMPTY_CHARACTER_OBJECT_ARRAY = new Character[0];
121
122 /**
123 * The index value when an element is not found in a list or array: {@code -1}.
124 * This value is returned by methods in this class and can also be used in comparisons with values returned by
125 * various method from {@link java.util.List}.
126 */
127 public static final int INDEX_NOT_FOUND = -1;
128
129 /**
130 * <p>ArrayUtils instances should NOT be constructed in standard programming.
131 * Instead, the class should be used as <code>ArrayUtils.clone(new int[] {2})</code>.</p>
132 *
133 * <p>This constructor is public to permit tools that require a JavaBean instance
134 * to operate.</p>
135 */
136 public ArrayUtils() {
137 super();
138 }
139
140
141 // NOTE: Cannot use {@code} to enclose text which includes {}, but <code></code> is OK
142
143
144 // Basic methods handling multi-dimensional arrays
145 //-----------------------------------------------------------------------
146 /**
147 * <p>Outputs an array as a String, treating {@code null} as an empty array.</p>
148 *
149 * <p>Multi-dimensional arrays are handled correctly, including
150 * multi-dimensional primitive arrays.</p>
151 *
152 * <p>The format is that of Java source code, for example <code>{a,b}</code>.</p>
153 *
154 * @param array the array to get a toString for, may be {@code null}
155 * @return a String representation of the array, '{}' if null array input
156 */
157 public static String toString(Object array) {
158 return toString(array, "{}");
159 }
160
161 /**
162 * <p>Outputs an array as a String handling {@code null}s.</p>
163 *
164 * <p>Multi-dimensional arrays are handled correctly, including
165 * multi-dimensional primitive arrays.</p>
166 *
167 * <p>The format is that of Java source code, for example <code>{a,b}</code>.</p>
168 *
169 * @param array the array to get a toString for, may be {@code null}
170 * @param stringIfNull the String to return if the array is {@code null}
171 * @return a String representation of the array
172 */
173 public static String toString(Object array, String stringIfNull) {
174 if (array == null) {
175 return stringIfNull;
176 }
177 return new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString();
178 }
179
180 /**
181 * <p>Get a hash code for an array handling multi-dimensional arrays correctly.</p>
182 *
183 * <p>Multi-dimensional primitive arrays are also handled correctly by this method.</p>
184 *
185 * @param array the array to get a hash code for, {@code null} returns zero
186 * @return a hash code for the array
187 */
188 public static int hashCode(Object array) {
189 return new HashCodeBuilder().append(array).toHashCode();
190 }
191
192 /**
193 * <p>Compares two arrays, using equals(), handling multi-dimensional arrays
194 * correctly.</p>
195 *
196 * <p>Multi-dimensional primitive arrays are also handled correctly by this method.</p>
197 *
198 * @param array1 the left hand array to compare, may be {@code null}
199 * @param array2 the right hand array to compare, may be {@code null}
200 * @return {@code true} if the arrays are equal
201 */
202 public static boolean isEquals(Object array1, Object array2) {
203 return new EqualsBuilder().append(array1, array2).isEquals();
204 }
205
206 // To map
207 //-----------------------------------------------------------------------
208 /**
209 * <p>Converts the given array into a {@link java.util.Map}. Each element of the array
210 * must be either a {@link java.util.Map.Entry} or an Array, containing at least two
211 * elements, where the first element is used as key and the second as
212 * value.</p>
213 *
214 * <p>This method can be used to initialize:</p>
215 * <pre>
216 * // Create a Map mapping colors.
217 * Map colorMap = MapUtils.toMap(new String[][] {{
218 * {"RED", "#FF0000"},
219 * {"GREEN", "#00FF00"},
220 * {"BLUE", "#0000FF"}});
221 * </pre>
222 *
223 * <p>This method returns {@code null} for a {@code null} input array.</p>
224 *
225 * @param array an array whose elements are either a {@link java.util.Map.Entry} or
226 * an Array containing at least two elements, may be {@code null}
227 * @return a {@code Map} that was created from the array
228 * @throws IllegalArgumentException if one element of this Array is
229 * itself an Array containing less then two elements
230 * @throws IllegalArgumentException if the array contains elements other
231 * than {@link java.util.Map.Entry} and an Array
232 */
233 public static Map<Object, Object> toMap(Object[] array) {
234 if (array == null) {
235 return null;
236 }
237 final Map<Object, Object> map = new HashMap<Object, Object>((int) (array.length * 1.5));
238 for (int i = 0; i < array.length; i++) {
239 Object object = array[i];
240 if (object instanceof Map.Entry<?, ?>) {
241 Map.Entry<?,?> entry = (Map.Entry<?,?>) object;
242 map.put(entry.getKey(), entry.getValue());
243 } else if (object instanceof Object[]) {
244 Object[] entry = (Object[]) object;
245 if (entry.length < 2) {
246 throw new IllegalArgumentException("Array element " + i + ", '"
247 + object
248 + "', has a length less than 2");
249 }
250 map.put(entry[0], entry[1]);
251 } else {
252 throw new IllegalArgumentException("Array element " + i + ", '"
253 + object
254 + "', is neither of type Map.Entry nor an Array");
255 }
256 }
257 return map;
258 }
259
260 // Generic array
261 //-----------------------------------------------------------------------
262 /**
263 * <p>Create a type-safe generic array.</p>
264 *
265 * <p>The Java language does not allow an array to be created from a generic type:</p>
266 *
267 * <pre>
268 public static &lt;T&gt; T[] createAnArray(int size) {
269 return new T[size]; // compiler error here
270 }
271 public static &lt;T&gt; T[] createAnArray(int size) {
272 return (T[])new Object[size]; // ClassCastException at runtime
273 }
274 * </pre>
275 *
276 * <p>Therefore new arrays of generic types can be created with this method.
277 * For example, an array of Strings can be created:</p>
278 *
279 * <pre>
280 String[] array = ArrayUtils.toArray("1", "2");
281 String[] emptyArray = ArrayUtils.&lt;String&gt;toArray();
282 * </pre>
283 *
284 * <p>The method is typically used in scenarios, where the caller itself uses generic types
285 * that have to be combined into an array.</p>
286 *
287 * <p>Note, this method makes only sense to provide arguments of the same type so that the
288 * compiler can deduce the type of the array itself. While it is possible to select the
289 * type explicitly like in
290 * <code>Number[] array = ArrayUtils.&lt;Number&gt;toArray(Integer.valueOf(42), Double.valueOf(Math.PI))</code>,
291 * there is no real advantage when compared to
292 * <code>new Number[] {Integer.valueOf(42), Double.valueOf(Math.PI)}</code>.</p>
293 *
294 * @param <T> the array's element type
295 * @param items the varargs array items, null allowed
296 * @return the array, not null unless a null array is passed in
297 * @since 3.0
298 */
299 public static <T> T[] toArray(final T... items) {
300 return items;
301 }
302
303 // Clone
304 //-----------------------------------------------------------------------
305 /**
306 * <p>Shallow clones an array returning a typecast result and handling
307 * {@code null}.</p>
308 *
309 * <p>The objects in the array are not cloned, thus there is no special
310 * handling for multi-dimensional arrays.</p>
311 *
312 * <p>This method returns {@code null} for a {@code null} input array.</p>
313 *
314 * @param <T> the component type of the array
315 * @param array the array to shallow clone, may be {@code null}
316 * @return the cloned array, {@code null} if {@code null} input
317 */
318 public static <T> T[] clone(T[] array) {
319 if (array == null) {
320 return null;
321 }
322 return array.clone();
323 }
324
325 /**
326 * <p>Clones an array returning a typecast result and handling
327 * {@code null}.</p>
328 *
329 * <p>This method returns {@code null} for a {@code null} input array.</p>
330 *
331 * @param array the array to clone, may be {@code null}
332 * @return the cloned array, {@code null} if {@code null} input
333 */
334 public static long[] clone(long[] array) {
335 if (array == null) {
336 return null;
337 }
338 return array.clone();
339 }
340
341 /**
342 * <p>Clones an array returning a typecast result and handling
343 * {@code null}.</p>
344 *
345 * <p>This method returns {@code null} for a {@code null} input array.</p>
346 *
347 * @param array the array to clone, may be {@code null}
348 * @return the cloned array, {@code null} if {@code null} input
349 */
350 public static int[] clone(int[] array) {
351 if (array == null) {
352 return null;
353 }
354 return array.clone();
355 }
356
357 /**
358 * <p>Clones an array returning a typecast result and handling
359 * {@code null}.</p>
360 *
361 * <p>This method returns {@code null} for a {@code null} input array.</p>
362 *
363 * @param array the array to clone, may be {@code null}
364 * @return the cloned array, {@code null} if {@code null} input
365 */
366 public static short[] clone(short[] array) {
367 if (array == null) {
368 return null;
369 }
370 return array.clone();
371 }
372
373 /**
374 * <p>Clones an array returning a typecast result and handling
375 * {@code null}.</p>
376 *
377 * <p>This method returns {@code null} for a {@code null} input array.</p>
378 *
379 * @param array the array to clone, may be {@code null}
380 * @return the cloned array, {@code null} if {@code null} input
381 */
382 public static char[] clone(char[] array) {
383 if (array == null) {
384 return null;
385 }
386 return array.clone();
387 }
388
389 /**
390 * <p>Clones an array returning a typecast result and handling
391 * {@code null}.</p>
392 *
393 * <p>This method returns {@code null} for a {@code null} input array.</p>
394 *
395 * @param array the array to clone, may be {@code null}
396 * @return the cloned array, {@code null} if {@code null} input
397 */
398 public static byte[] clone(byte[] array) {
399 if (array == null) {
400 return null;
401 }
402 return array.clone();
403 }
404
405 /**
406 * <p>Clones an array returning a typecast result and handling
407 * {@code null}.</p>
408 *
409 * <p>This method returns {@code null} for a {@code null} input array.</p>
410 *
411 * @param array the array to clone, may be {@code null}
412 * @return the cloned array, {@code null} if {@code null} input
413 */
414 public static double[] clone(double[] array) {
415 if (array == null) {
416 return null;
417 }
418 return array.clone();
419 }
420
421 /**
422 * <p>Clones an array returning a typecast result and handling
423 * {@code null}.</p>
424 *
425 * <p>This method returns {@code null} for a {@code null} input array.</p>
426 *
427 * @param array the array to clone, may be {@code null}
428 * @return the cloned array, {@code null} if {@code null} input
429 */
430 public static float[] clone(float[] array) {
431 if (array == null) {
432 return null;
433 }
434 return array.clone();
435 }
436
437 /**
438 * <p>Clones an array returning a typecast result and handling
439 * {@code null}.</p>
440 *
441 * <p>This method returns {@code null} for a {@code null} input array.</p>
442 *
443 * @param array the array to clone, may be {@code null}
444 * @return the cloned array, {@code null} if {@code null} input
445 */
446 public static boolean[] clone(boolean[] array) {
447 if (array == null) {
448 return null;
449 }
450 return array.clone();
451 }
452
453 // nullToEmpty
454 //-----------------------------------------------------------------------
455 /**
456 * <p>Defensive programming technique to change a {@code null}
457 * reference to an empty one.</p>
458 *
459 * <p>This method returns an empty array for a {@code null} input array.</p>
460 *
461 * <p>As a memory optimizing technique an empty array passed in will be overridden with
462 * the empty {@code public static} references in this class.</p>
463 *
464 * @param array the array to check for {@code null} or empty
465 * @return the same array, {@code public static} empty array if {@code null} or empty input
466 * @since 2.5
467 */
468 public static Object[] nullToEmpty(Object[] array) {
469 if (array == null || array.length == 0) {
470 return EMPTY_OBJECT_ARRAY;
471 }
472 return array;
473 }
474
475 /**
476 * <p>Defensive programming technique to change a {@code null}
477 * reference to an empty one.</p>
478 *
479 * <p>This method returns an empty array for a {@code null} input array.</p>
480 *
481 * <p>As a memory optimizing technique an empty array passed in will be overridden with
482 * the empty {@code public static} references in this class.</p>
483 *
484 * @param array the array to check for {@code null} or empty
485 * @return the same array, {@code public static} empty array if {@code null} or empty input
486 * @since 2.5
487 */
488 public static String[] nullToEmpty(String[] array) {
489 if (array == null || array.length == 0) {
490 return EMPTY_STRING_ARRAY;
491 }
492 return array;
493 }
494
495 /**
496 * <p>Defensive programming technique to change a {@code null}
497 * reference to an empty one.</p>
498 *
499 * <p>This method returns an empty array for a {@code null} input array.</p>
500 *
501 * <p>As a memory optimizing technique an empty array passed in will be overridden with
502 * the empty {@code public static} references in this class.</p>
503 *
504 * @param array the array to check for {@code null} or empty
505 * @return the same array, {@code public static} empty array if {@code null} or empty input
506 * @since 2.5
507 */
508 public static long[] nullToEmpty(long[] array) {
509 if (array == null || array.length == 0) {
510 return EMPTY_LONG_ARRAY;
511 }
512 return array;
513 }
514
515 /**
516 * <p>Defensive programming technique to change a {@code null}
517 * reference to an empty one.</p>
518 *
519 * <p>This method returns an empty array for a {@code null} input array.</p>
520 *
521 * <p>As a memory optimizing technique an empty array passed in will be overridden with
522 * the empty {@code public static} references in this class.</p>
523 *
524 * @param array the array to check for {@code null} or empty
525 * @return the same array, {@code public static} empty array if {@code null} or empty input
526 * @since 2.5
527 */
528 public static int[] nullToEmpty(int[] array) {
529 if (array == null || array.length == 0) {
530 return EMPTY_INT_ARRAY;
531 }
532 return array;
533 }
534
535 /**
536 * <p>Defensive programming technique to change a {@code null}
537 * reference to an empty one.</p>
538 *
539 * <p>This method returns an empty array for a {@code null} input array.</p>
540 *
541 * <p>As a memory optimizing technique an empty array passed in will be overridden with
542 * the empty {@code public static} references in this class.</p>
543 *
544 * @param array the array to check for {@code null} or empty
545 * @return the same array, {@code public static} empty array if {@code null} or empty input
546 * @since 2.5
547 */
548 public static short[] nullToEmpty(short[] array) {
549 if (array == null || array.length == 0) {
550 return EMPTY_SHORT_ARRAY;
551 }
552 return array;
553 }
554
555 /**
556 * <p>Defensive programming technique to change a {@code null}
557 * reference to an empty one.</p>
558 *
559 * <p>This method returns an empty array for a {@code null} input array.</p>
560 *
561 * <p>As a memory optimizing technique an empty array passed in will be overridden with
562 * the empty {@code public static} references in this class.</p>
563 *
564 * @param array the array to check for {@code null} or empty
565 * @return the same array, {@code public static} empty array if {@code null} or empty input
566 * @since 2.5
567 */
568 public static char[] nullToEmpty(char[] array) {
569 if (array == null || array.length == 0) {
570 return EMPTY_CHAR_ARRAY;
571 }
572 return array;
573 }
574
575 /**
576 * <p>Defensive programming technique to change a {@code null}
577 * reference to an empty one.</p>
578 *
579 * <p>This method returns an empty array for a {@code null} input array.</p>
580 *
581 * <p>As a memory optimizing technique an empty array passed in will be overridden with
582 * the empty {@code public static} references in this class.</p>
583 *
584 * @param array the array to check for {@code null} or empty
585 * @return the same array, {@code public static} empty array if {@code null} or empty input
586 * @since 2.5
587 */
588 public static byte[] nullToEmpty(byte[] array) {
589 if (array == null || array.length == 0) {
590 return EMPTY_BYTE_ARRAY;
591 }
592 return array;
593 }
594
595 /**
596 * <p>Defensive programming technique to change a {@code null}
597 * reference to an empty one.</p>
598 *
599 * <p>This method returns an empty array for a {@code null} input array.</p>
600 *
601 * <p>As a memory optimizing technique an empty array passed in will be overridden with
602 * the empty {@code public static} references in this class.</p>
603 *
604 * @param array the array to check for {@code null} or empty
605 * @return the same array, {@code public static} empty array if {@code null} or empty input
606 * @since 2.5
607 */
608 public static double[] nullToEmpty(double[] array) {
609 if (array == null || array.length == 0) {
610 return EMPTY_DOUBLE_ARRAY;
611 }
612 return array;
613 }
614
615 /**
616 * <p>Defensive programming technique to change a {@code null}
617 * reference to an empty one.</p>
618 *
619 * <p>This method returns an empty array for a {@code null} input array.</p>
620 *
621 * <p>As a memory optimizing technique an empty array passed in will be overridden with
622 * the empty {@code public static} references in this class.</p>
623 *
624 * @param array the array to check for {@code null} or empty
625 * @return the same array, {@code public static} empty array if {@code null} or empty input
626 * @since 2.5
627 */
628 public static float[] nullToEmpty(float[] array) {
629 if (array == null || array.length == 0) {
630 return EMPTY_FLOAT_ARRAY;
631 }
632 return array;
633 }
634
635 /**
636 * <p>Defensive programming technique to change a {@code null}
637 * reference to an empty one.</p>
638 *
639 * <p>This method returns an empty array for a {@code null} input array.</p>
640 *
641 * <p>As a memory optimizing technique an empty array passed in will be overridden with
642 * the empty {@code public static} references in this class.</p>
643 *
644 * @param array the array to check for {@code null} or empty
645 * @return the same array, {@code public static} empty array if {@code null} or empty input
646 * @since 2.5
647 */
648 public static boolean[] nullToEmpty(boolean[] array) {
649 if (array == null || array.length == 0) {
650 return EMPTY_BOOLEAN_ARRAY;
651 }
652 return array;
653 }
654
655 /**
656 * <p>Defensive programming technique to change a {@code null}
657 * reference to an empty one.</p>
658 *
659 * <p>This method returns an empty array for a {@code null} input array.</p>
660 *
661 * <p>As a memory optimizing technique an empty array passed in will be overridden with
662 * the empty {@code public static} references in this class.</p>
663 *
664 * @param array the array to check for {@code null} or empty
665 * @return the same array, {@code public static} empty array if {@code null} or empty input
666 * @since 2.5
667 */
668 public static Long[] nullToEmpty(Long[] array) {
669 if (array == null || array.length == 0) {
670 return EMPTY_LONG_OBJECT_ARRAY;
671 }
672 return array;
673 }
674
675 /**
676 * <p>Defensive programming technique to change a {@code null}
677 * reference to an empty one.</p>
678 *
679 * <p>This method returns an empty array for a {@code null} input array.</p>
680 *
681 * <p>As a memory optimizing technique an empty array passed in will be overridden with
682 * the empty {@code public static} references in this class.</p>
683 *
684 * @param array the array to check for {@code null} or empty
685 * @return the same array, {@code public static} empty array if {@code null} or empty input
686 * @since 2.5
687 */
688 public static Integer[] nullToEmpty(Integer[] array) {
689 if (array == null || array.length == 0) {
690 return EMPTY_INTEGER_OBJECT_ARRAY;
691 }
692 return array;
693 }
694
695 /**
696 * <p>Defensive programming technique to change a {@code null}
697 * reference to an empty one.</p>
698 *
699 * <p>This method returns an empty array for a {@code null} input array.</p>
700 *
701 * <p>As a memory optimizing technique an empty array passed in will be overridden with
702 * the empty {@code public static} references in this class.</p>
703 *
704 * @param array the array to check for {@code null} or empty
705 * @return the same array, {@code public static} empty array if {@code null} or empty input
706 * @since 2.5
707 */
708 public static Short[] nullToEmpty(Short[] array) {
709 if (array == null || array.length == 0) {
710 return EMPTY_SHORT_OBJECT_ARRAY;
711 }
712 return array;
713 }
714
715 /**
716 * <p>Defensive programming technique to change a {@code null}
717 * reference to an empty one.</p>
718 *
719 * <p>This method returns an empty array for a {@code null} input array.</p>
720 *
721 * <p>As a memory optimizing technique an empty array passed in will be overridden with
722 * the empty {@code public static} references in this class.</p>
723 *
724 * @param array the array to check for {@code null} or empty
725 * @return the same array, {@code public static} empty array if {@code null} or empty input
726 * @since 2.5
727 */
728 public static Character[] nullToEmpty(Character[] array) {
729 if (array == null || array.length == 0) {
730 return EMPTY_CHARACTER_OBJECT_ARRAY;
731 }
732 return array;
733 }
734
735 /**
736 * <p>Defensive programming technique to change a {@code null}
737 * reference to an empty one.</p>
738 *
739 * <p>This method returns an empty array for a {@code null} input array.</p>
740 *
741 * <p>As a memory optimizing technique an empty array passed in will be overridden with
742 * the empty {@code public static} references in this class.</p>
743 *
744 * @param array the array to check for {@code null} or empty
745 * @return the same array, {@code public static} empty array if {@code null} or empty input
746 * @since 2.5
747 */
748 public static Byte[] nullToEmpty(Byte[] array) {
749 if (array == null || array.length == 0) {
750 return EMPTY_BYTE_OBJECT_ARRAY;
751 }
752 return array;
753 }
754
755 /**
756 * <p>Defensive programming technique to change a {@code null}
757 * reference to an empty one.</p>
758 *
759 * <p>This method returns an empty array for a {@code null} input array.</p>
760 *
761 * <p>As a memory optimizing technique an empty array passed in will be overridden with
762 * the empty {@code public static} references in this class.</p>
763 *
764 * @param array the array to check for {@code null} or empty
765 * @return the same array, {@code public static} empty array if {@code null} or empty input
766 * @since 2.5
767 */
768 public static Double[] nullToEmpty(Double[] array) {
769 if (array == null || array.length == 0) {
770 return EMPTY_DOUBLE_OBJECT_ARRAY;
771 }
772 return array;
773 }
774
775 /**
776 * <p>Defensive programming technique to change a {@code null}
777 * reference to an empty one.</p>
778 *
779 * <p>This method returns an empty array for a {@code null} input array.</p>
780 *
781 * <p>As a memory optimizing technique an empty array passed in will be overridden with
782 * the empty {@code public static} references in this class.</p>
783 *
784 * @param array the array to check for {@code null} or empty
785 * @return the same array, {@code public static} empty array if {@code null} or empty input
786 * @since 2.5
787 */
788 public static Float[] nullToEmpty(Float[] array) {
789 if (array == null || array.length == 0) {
790 return EMPTY_FLOAT_OBJECT_ARRAY;
791 }
792 return array;
793 }
794
795 /**
796 * <p>Defensive programming technique to change a {@code null}
797 * reference to an empty one.</p>
798 *
799 * <p>This method returns an empty array for a {@code null} input array.</p>
800 *
801 * <p>As a memory optimizing technique an empty array passed in will be overridden with
802 * the empty {@code public static} references in this class.</p>
803 *
804 * @param array the array to check for {@code null} or empty
805 * @return the same array, {@code public static} empty array if {@code null} or empty input
806 * @since 2.5
807 */
808 public static Boolean[] nullToEmpty(Boolean[] array) {
809 if (array == null || array.length == 0) {
810 return EMPTY_BOOLEAN_OBJECT_ARRAY;
811 }
812 return array;
813 }
814
815 // Subarrays
816 //-----------------------------------------------------------------------
817 /**
818 * <p>Produces a new array containing the elements between
819 * the start and end indices.</p>
820 *
821 * <p>The start index is inclusive, the end index exclusive.
822 * Null array input produces null output.</p>
823 *
824 * <p>The component type of the subarray is always the same as
825 * that of the input array. Thus, if the input is an array of type
826 * {@code Date}, the following usage is envisaged:</p>
827 *
828 * <pre>
829 * Date[] someDates = (Date[])ArrayUtils.subarray(allDates, 2, 5);
830 * </pre>
831 *
832 * @param <T> the component type of the array
833 * @param array the array
834 * @param startIndexInclusive the starting index. Undervalue (&lt;0)
835 * is promoted to 0, overvalue (&gt;array.length) results
836 * in an empty array.
837 * @param endIndexExclusive elements up to endIndex-1 are present in the
838 * returned subarray. Undervalue (&lt; startIndex) produces
839 * empty array, overvalue (&gt;array.length) is demoted to
840 * array length.
841 * @return a new array containing the elements between
842 * the start and end indices.
843 * @since 2.1
844 */
845 public static <T> T[] subarray(T[] array, int startIndexInclusive, int endIndexExclusive) {
846 if (array == null) {
847 return null;
848 }
849 if (startIndexInclusive < 0) {
850 startIndexInclusive = 0;
851 }
852 if (endIndexExclusive > array.length) {
853 endIndexExclusive = array.length;
854 }
855 int newSize = endIndexExclusive - startIndexInclusive;
856 Class<?> type = array.getClass().getComponentType();
857 if (newSize <= 0) {
858 @SuppressWarnings("unchecked") // OK, because array is of type T
859 final T[] emptyArray = (T[]) Array.newInstance(type, 0);
860 return emptyArray;
861 }
862 @SuppressWarnings("unchecked") // OK, because array is of type T
863 T[] subarray = (T[]) Array.newInstance(type, newSize);
864 System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
865 return subarray;
866 }
867
868 /**
869 * <p>Produces a new {@code long} array containing the elements
870 * between the start and end indices.</p>
871 *
872 * <p>The start index is inclusive, the end index exclusive.
873 * Null array input produces null output.</p>
874 *
875 * @param array the array
876 * @param startIndexInclusive the starting index. Undervalue (&lt;0)
877 * is promoted to 0, overvalue (&gt;array.length) results
878 * in an empty array.
879 * @param endIndexExclusive elements up to endIndex-1 are present in the
880 * returned subarray. Undervalue (&lt; startIndex) produces
881 * empty array, overvalue (&gt;array.length) is demoted to
882 * array length.
883 * @return a new array containing the elements between
884 * the start and end indices.
885 * @since 2.1
886 */
887 public static long[] subarray(long[] array, int startIndexInclusive, int endIndexExclusive) {
888 if (array == null) {
889 return null;
890 }
891 if (startIndexInclusive < 0) {
892 startIndexInclusive = 0;
893 }
894 if (endIndexExclusive > array.length) {
895 endIndexExclusive = array.length;
896 }
897 int newSize = endIndexExclusive - startIndexInclusive;
898 if (newSize <= 0) {
899 return EMPTY_LONG_ARRAY;
900 }
901
902 long[] subarray = new long[newSize];
903 System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
904 return subarray;
905 }
906
907 /**
908 * <p>Produces a new {@code int} array containing the elements
909 * between the start and end indices.</p>
910 *
911 * <p>The start index is inclusive, the end index exclusive.
912 * Null array input produces null output.</p>
913 *
914 * @param array the array
915 * @param startIndexInclusive the starting index. Undervalue (&lt;0)
916 * is promoted to 0, overvalue (&gt;array.length) results
917 * in an empty array.
918 * @param endIndexExclusive elements up to endIndex-1 are present in the
919 * returned subarray. Undervalue (&lt; startIndex) produces
920 * empty array, overvalue (&gt;array.length) is demoted to
921 * array length.
922 * @return a new array containing the elements between
923 * the start and end indices.
924 * @since 2.1
925 */
926 public static int[] subarray(int[] array, int startIndexInclusive, int endIndexExclusive) {
927 if (array == null) {
928 return null;
929 }
930 if (startIndexInclusive < 0) {
931 startIndexInclusive = 0;
932 }
933 if (endIndexExclusive > array.length) {
934 endIndexExclusive = array.length;
935 }
936 int newSize = endIndexExclusive - startIndexInclusive;
937 if (newSize <= 0) {
938 return EMPTY_INT_ARRAY;
939 }
940
941 int[] subarray = new int[newSize];
942 System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
943 return subarray;
944 }
945
946 /**
947 * <p>Produces a new {@code short} array containing the elements
948 * between the start and end indices.</p>
949 *
950 * <p>The start index is inclusive, the end index exclusive.
951 * Null array input produces null output.</p>
952 *
953 * @param array the array
954 * @param startIndexInclusive the starting index. Undervalue (&lt;0)
955 * is promoted to 0, overvalue (&gt;array.length) results
956 * in an empty array.
957 * @param endIndexExclusive elements up to endIndex-1 are present in the
958 * returned subarray. Undervalue (&lt; startIndex) produces
959 * empty array, overvalue (&gt;array.length) is demoted to
960 * array length.
961 * @return a new array containing the elements between
962 * the start and end indices.
963 * @since 2.1
964 */
965 public static short[] subarray(short[] array, int startIndexInclusive, int endIndexExclusive) {
966 if (array == null) {
967 return null;
968 }
969 if (startIndexInclusive < 0) {
970 startIndexInclusive = 0;
971 }
972 if (endIndexExclusive > array.length) {
973 endIndexExclusive = array.length;
974 }
975 int newSize = endIndexExclusive - startIndexInclusive;
976 if (newSize <= 0) {
977 return EMPTY_SHORT_ARRAY;
978 }
979
980 short[] subarray = new short[newSize];
981 System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
982 return subarray;
983 }
984
985 /**
986 * <p>Produces a new {@code char} array containing the elements
987 * between the start and end indices.</p>
988 *
989 * <p>The start index is inclusive, the end index exclusive.
990 * Null array input produces null output.</p>
991 *
992 * @param array the array
993 * @param startIndexInclusive the starting index. Undervalue (&lt;0)
994 * is promoted to 0, overvalue (&gt;array.length) results
995 * in an empty array.
996 * @param endIndexExclusive elements up to endIndex-1 are present in the
997 * returned subarray. Undervalue (&lt; startIndex) produces
998 * empty array, overvalue (&gt;array.length) is demoted to
999 * array length.
1000 * @return a new array containing the elements between
1001 * the start and end indices.
1002 * @since 2.1
1003 */
1004 public static char[] subarray(char[] array, int startIndexInclusive, int endIndexExclusive) {
1005 if (array == null) {
1006 return null;
1007 }
1008 if (startIndexInclusive < 0) {
1009 startIndexInclusive = 0;
1010 }
1011 if (endIndexExclusive > array.length) {
1012 endIndexExclusive = array.length;
1013 }
1014 int newSize = endIndexExclusive - startIndexInclusive;
1015 if (newSize <= 0) {
1016 return EMPTY_CHAR_ARRAY;
1017 }
1018
1019 char[] subarray = new char[newSize];
1020 System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
1021 return subarray;
1022 }
1023
1024 /**
1025 * <p>Produces a new {@code byte} array containing the elements
1026 * between the start and end indices.</p>
1027 *
1028 * <p>The start index is inclusive, the end index exclusive.
1029 * Null array input produces null output.</p>
1030 *
1031 * @param array the array
1032 * @param startIndexInclusive the starting index. Undervalue (&lt;0)
1033 * is promoted to 0, overvalue (&gt;array.length) results
1034 * in an empty array.
1035 * @param endIndexExclusive elements up to endIndex-1 are present in the
1036 * returned subarray. Undervalue (&lt; startIndex) produces
1037 * empty array, overvalue (&gt;array.length) is demoted to
1038 * array length.
1039 * @return a new array containing the elements between
1040 * the start and end indices.
1041 * @since 2.1
1042 */
1043 public static byte[] subarray(byte[] array, int startIndexInclusive, int endIndexExclusive) {
1044 if (array == null) {
1045 return null;
1046 }
1047 if (startIndexInclusive < 0) {
1048 startIndexInclusive = 0;
1049 }
1050 if (endIndexExclusive > array.length) {
1051 endIndexExclusive = array.length;
1052 }
1053 int newSize = endIndexExclusive - startIndexInclusive;
1054 if (newSize <= 0) {
1055 return EMPTY_BYTE_ARRAY;
1056 }
1057
1058 byte[] subarray = new byte[newSize];
1059 System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
1060 return subarray;
1061 }
1062
1063 /**
1064 * <p>Produces a new {@code double} array containing the elements
1065 * between the start and end indices.</p>
1066 *
1067 * <p>The start index is inclusive, the end index exclusive.
1068 * Null array input produces null output.</p>
1069 *
1070 * @param array the array
1071 * @param startIndexInclusive the starting index. Undervalue (&lt;0)
1072 * is promoted to 0, overvalue (&gt;array.length) results
1073 * in an empty array.
1074 * @param endIndexExclusive elements up to endIndex-1 are present in the
1075 * returned subarray. Undervalue (&lt; startIndex) produces
1076 * empty array, overvalue (&gt;array.length) is demoted to
1077 * array length.
1078 * @return a new array containing the elements between
1079 * the start and end indices.
1080 * @since 2.1
1081 */
1082 public static double[] subarray(double[] array, int startIndexInclusive, int endIndexExclusive) {
1083 if (array == null) {
1084 return null;
1085 }
1086 if (startIndexInclusive < 0) {
1087 startIndexInclusive = 0;
1088 }
1089 if (endIndexExclusive > array.length) {
1090 endIndexExclusive = array.length;
1091 }
1092 int newSize = endIndexExclusive - startIndexInclusive;
1093 if (newSize <= 0) {
1094 return EMPTY_DOUBLE_ARRAY;
1095 }
1096
1097 double[] subarray = new double[newSize];
1098 System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
1099 return subarray;
1100 }
1101
1102 /**
1103 * <p>Produces a new {@code float} array containing the elements
1104 * between the start and end indices.</p>
1105 *
1106 * <p>The start index is inclusive, the end index exclusive.
1107 * Null array input produces null output.</p>
1108 *
1109 * @param array the array
1110 * @param startIndexInclusive the starting index. Undervalue (&lt;0)
1111 * is promoted to 0, overvalue (&gt;array.length) results
1112 * in an empty array.
1113 * @param endIndexExclusive elements up to endIndex-1 are present in the
1114 * returned subarray. Undervalue (&lt; startIndex) produces
1115 * empty array, overvalue (&gt;array.length) is demoted to
1116 * array length.
1117 * @return a new array containing the elements between
1118 * the start and end indices.
1119 * @since 2.1
1120 */
1121 public static float[] subarray(float[] array, int startIndexInclusive, int endIndexExclusive) {
1122 if (array == null) {
1123 return null;
1124 }
1125 if (startIndexInclusive < 0) {
1126 startIndexInclusive = 0;
1127 }
1128 if (endIndexExclusive > array.length) {
1129 endIndexExclusive = array.length;
1130 }
1131 int newSize = endIndexExclusive - startIndexInclusive;
1132 if (newSize <= 0) {
1133 return EMPTY_FLOAT_ARRAY;
1134 }
1135
1136 float[] subarray = new float[newSize];
1137 System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
1138 return subarray;
1139 }
1140
1141 /**
1142 * <p>Produces a new {@code boolean} array containing the elements
1143 * between the start and end indices.</p>
1144 *
1145 * <p>The start index is inclusive, the end index exclusive.
1146 * Null array input produces null output.</p>
1147 *
1148 * @param array the array
1149 * @param startIndexInclusive the starting index. Undervalue (&lt;0)
1150 * is promoted to 0, overvalue (&gt;array.length) results
1151 * in an empty array.
1152 * @param endIndexExclusive elements up to endIndex-1 are present in the
1153 * returned subarray. Undervalue (&lt; startIndex) produces
1154 * empty array, overvalue (&gt;array.length) is demoted to
1155 * array length.
1156 * @return a new array containing the elements between
1157 * the start and end indices.
1158 * @since 2.1
1159 */
1160 public static boolean[] subarray(boolean[] array, int startIndexInclusive, int endIndexExclusive) {
1161 if (array == null) {
1162 return null;
1163 }
1164 if (startIndexInclusive < 0) {
1165 startIndexInclusive = 0;
1166 }
1167 if (endIndexExclusive > array.length) {
1168 endIndexExclusive = array.length;
1169 }
1170 int newSize = endIndexExclusive - startIndexInclusive;
1171 if (newSize <= 0) {
1172 return EMPTY_BOOLEAN_ARRAY;
1173 }
1174
1175 boolean[] subarray = new boolean[newSize];
1176 System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
1177 return subarray;
1178 }
1179
1180 // Is same length
1181 //-----------------------------------------------------------------------
1182 /**
1183 * <p>Checks whether two arrays are the same length, treating
1184 * {@code null} arrays as length {@code 0}.
1185 *
1186 * <p>Any multi-dimensional aspects of the arrays are ignored.</p>
1187 *
1188 * @param array1 the first array, may be {@code null}
1189 * @param array2 the second array, may be {@code null}
1190 * @return {@code true} if length of arrays matches, treating
1191 * {@code null} as an empty array
1192 */
1193 public static boolean isSameLength(Object[] array1, Object[] array2) {
1194 if ((array1 == null && array2 != null && array2.length > 0) ||
1195 (array2 == null && array1 != null && array1.length > 0) ||
1196 (array1 != null && array2 != null && array1.length != array2.length)) {
1197 return false;
1198 }
1199 return true;
1200 }
1201
1202 /**
1203 * <p>Checks whether two arrays are the same length, treating
1204 * {@code null} arrays as length {@code 0}.</p>
1205 *
1206 * @param array1 the first array, may be {@code null}
1207 * @param array2 the second array, may be {@code null}
1208 * @return {@code true} if length of arrays matches, treating
1209 * {@code null} as an empty array
1210 */
1211 public static boolean isSameLength(long[] array1, long[] array2) {
1212 if ((array1 == null && array2 != null && array2.length > 0) ||
1213 (array2 == null && array1 != null && array1.length > 0) ||
1214 (array1 != null && array2 != null && array1.length != array2.length)) {
1215 return false;
1216 }
1217 return true;
1218 }
1219
1220 /**
1221 * <p>Checks whether two arrays are the same length, treating
1222 * {@code null} arrays as length {@code 0}.</p>
1223 *
1224 * @param array1 the first array, may be {@code null}
1225 * @param array2 the second array, may be {@code null}
1226 * @return {@code true} if length of arrays matches, treating
1227 * {@code null} as an empty array
1228 */
1229 public static boolean isSameLength(int[] array1, int[] array2) {
1230 if ((array1 == null && array2 != null && array2.length > 0) ||
1231 (array2 == null && array1 != null && array1.length > 0) ||
1232 (array1 != null && array2 != null && array1.length != array2.length)) {
1233 return false;
1234 }
1235 return true;
1236 }
1237
1238 /**
1239 * <p>Checks whether two arrays are the same length, treating
1240 * {@code null} arrays as length {@code 0}.</p>
1241 *
1242 * @param array1 the first array, may be {@code null}
1243 * @param array2 the second array, may be {@code null}
1244 * @return {@code true} if length of arrays matches, treating
1245 * {@code null} as an empty array
1246 */
1247 public static boolean isSameLength(short[] array1, short[] array2) {
1248 if ((array1 == null && array2 != null && array2.length > 0) ||
1249 (array2 == null && array1 != null && array1.length > 0) ||
1250 (array1 != null && array2 != null && array1.length != array2.length)) {
1251 return false;
1252 }
1253 return true;
1254 }
1255
1256 /**
1257 * <p>Checks whether two arrays are the same length, treating
1258 * {@code null} arrays as length {@code 0}.</p>
1259 *
1260 * @param array1 the first array, may be {@code null}
1261 * @param array2 the second array, may be {@code null}
1262 * @return {@code true} if length of arrays matches, treating
1263 * {@code null} as an empty array
1264 */
1265 public static boolean isSameLength(char[] array1, char[] array2) {
1266 if ((array1 == null && array2 != null && array2.length > 0) ||
1267 (array2 == null && array1 != null && array1.length > 0) ||
1268 (array1 != null && array2 != null && array1.length != array2.length)) {
1269 return false;
1270 }
1271 return true;
1272 }
1273
1274 /**
1275 * <p>Checks whether two arrays are the same length, treating
1276 * {@code null} arrays as length {@code 0}.</p>
1277 *
1278 * @param array1 the first array, may be {@code null}
1279 * @param array2 the second array, may be {@code null}
1280 * @return {@code true} if length of arrays matches, treating
1281 * {@code null} as an empty array
1282 */
1283 public static boolean isSameLength(byte[] array1, byte[] array2) {
1284 if ((array1 == null && array2 != null && array2.length > 0) ||
1285 (array2 == null && array1 != null && array1.length > 0) ||
1286 (array1 != null && array2 != null && array1.length != array2.length)) {
1287 return false;
1288 }
1289 return true;
1290 }
1291
1292 /**
1293 * <p>Checks whether two arrays are the same length, treating
1294 * {@code null} arrays as length {@code 0}.</p>
1295 *
1296 * @param array1 the first array, may be {@code null}
1297 * @param array2 the second array, may be {@code null}
1298 * @return {@code true} if length of arrays matches, treating
1299 * {@code null} as an empty array
1300 */
1301 public static boolean isSameLength(double[] array1, double[] array2) {
1302 if ((array1 == null && array2 != null && array2.length > 0) ||
1303 (array2 == null && array1 != null && array1.length > 0) ||
1304 (array1 != null && array2 != null && array1.length != array2.length)) {
1305 return false;
1306 }
1307 return true;
1308 }
1309
1310 /**
1311 * <p>Checks whether two arrays are the same length, treating
1312 * {@code null} arrays as length {@code 0}.</p>
1313 *
1314 * @param array1 the first array, may be {@code null}
1315 * @param array2 the second array, may be {@code null}
1316 * @return {@code true} if length of arrays matches, treating
1317 * {@code null} as an empty array
1318 */
1319 public static boolean isSameLength(float[] array1, float[] array2) {
1320 if ((array1 == null && array2 != null && array2.length > 0) ||
1321 (array2 == null && array1 != null && array1.length > 0) ||
1322 (array1 != null && array2 != null && array1.length != array2.length)) {
1323 return false;
1324 }
1325 return true;
1326 }
1327
1328 /**
1329 * <p>Checks whether two arrays are the same length, treating
1330 * {@code null} arrays as length {@code 0}.</p>
1331 *
1332 * @param array1 the first array, may be {@code null}
1333 * @param array2 the second array, may be {@code null}
1334 * @return {@code true} if length of arrays matches, treating
1335 * {@code null} as an empty array
1336 */
1337 public static boolean isSameLength(boolean[] array1, boolean[] array2) {
1338 if ((array1 == null && array2 != null && array2.length > 0) ||
1339 (array2 == null && array1 != null && array1.length > 0) ||
1340 (array1 != null && array2 != null && array1.length != array2.length)) {
1341 return false;
1342 }
1343 return true;
1344 }
1345
1346 //-----------------------------------------------------------------------
1347 /**
1348 * <p>Returns the length of the specified array.
1349 * This method can deal with {@code Object} arrays and with primitive arrays.</p>
1350 *
1351 * <p>If the input array is {@code null}, {@code 0} is returned.</p>
1352 *
1353 * <pre>
1354 * ArrayUtils.getLength(null) = 0
1355 * ArrayUtils.getLength([]) = 0
1356 * ArrayUtils.getLength([null]) = 1
1357 * ArrayUtils.getLength([true, false]) = 2
1358 * ArrayUtils.getLength([1, 2, 3]) = 3
1359 * ArrayUtils.getLength(["a", "b", "c"]) = 3
1360 * </pre>
1361 *
1362 * @param array the array to retrieve the length from, may be null
1363 * @return The length of the array, or {@code 0} if the array is {@code null}
1364 * @throws IllegalArgumentException if the object arguement is not an array.
1365 * @since 2.1
1366 */
1367 public static int getLength(Object array) {
1368 if (array == null) {
1369 return 0;
1370 }
1371 return Array.getLength(array);
1372 }
1373
1374 /**
1375 * <p>Checks whether two arrays are the same type taking into account
1376 * multi-dimensional arrays.</p>
1377 *
1378 * @param array1 the first array, must not be {@code null}
1379 * @param array2 the second array, must not be {@code null}
1380 * @return {@code true} if type of arrays matches
1381 * @throws IllegalArgumentException if either array is {@code null}
1382 */
1383 public static boolean isSameType(Object array1, Object array2) {
1384 if (array1 == null || array2 == null) {
1385 throw new IllegalArgumentException("The Array must not be null");
1386 }
1387 return array1.getClass().getName().equals(array2.getClass().getName());
1388 }
1389
1390 // Reverse
1391 //-----------------------------------------------------------------------
1392 /**
1393 * <p>Reverses the order of the given array.</p>
1394 *
1395 * <p>There is no special handling for multi-dimensional arrays.</p>
1396 *
1397 * <p>This method does nothing for a {@code null} input array.</p>
1398 *
1399 * @param array the array to reverse, may be {@code null}
1400 */
1401 public static void reverse(Object[] array) {
1402 if (array == null) {
1403 return;
1404 }
1405 int i = 0;
1406 int j = array.length - 1;
1407 Object tmp;
1408 while (j > i) {
1409 tmp = array[j];
1410 array[j] = array[i];
1411 array[i] = tmp;
1412 j--;
1413 i++;
1414 }
1415 }
1416
1417 /**
1418 * <p>Reverses the order of the given array.</p>
1419 *
1420 * <p>This method does nothing for a {@code null} input array.</p>
1421 *
1422 * @param array the array to reverse, may be {@code null}
1423 */
1424 public static void reverse(long[] array) {
1425 if (array == null) {
1426 return;
1427 }
1428 int i = 0;
1429 int j = array.length - 1;
1430 long tmp;
1431 while (j > i) {
1432 tmp = array[j];
1433 array[j] = array[i];
1434 array[i] = tmp;
1435 j--;
1436 i++;
1437 }
1438 }
1439
1440 /**
1441 * <p>Reverses the order of the given array.</p>
1442 *
1443 * <p>This method does nothing for a {@code null} input array.</p>
1444 *
1445 * @param array the array to reverse, may be {@code null}
1446 */
1447 public static void reverse(int[] array) {
1448 if (array == null) {
1449 return;
1450 }
1451 int i = 0;
1452 int j = array.length - 1;
1453 int tmp;
1454 while (j > i) {
1455 tmp = array[j];
1456 array[j] = array[i];
1457 array[i] = tmp;
1458 j--;
1459 i++;
1460 }
1461 }
1462
1463 /**
1464 * <p>Reverses the order of the given array.</p>
1465 *
1466 * <p>This method does nothing for a {@code null} input array.</p>
1467 *
1468 * @param array the array to reverse, may be {@code null}
1469 */
1470 public static void reverse(short[] array) {
1471 if (array == null) {
1472 return;
1473 }
1474 int i = 0;
1475 int j = array.length - 1;
1476 short tmp;
1477 while (j > i) {
1478 tmp = array[j];
1479 array[j] = array[i];
1480 array[i] = tmp;
1481 j--;
1482 i++;
1483 }
1484 }
1485
1486 /**
1487 * <p>Reverses the order of the given array.</p>
1488 *
1489 * <p>This method does nothing for a {@code null} input array.</p>
1490 *
1491 * @param array the array to reverse, may be {@code null}
1492 */
1493 public static void reverse(char[] array) {
1494 if (array == null) {
1495 return;
1496 }
1497 int i = 0;
1498 int j = array.length - 1;
1499 char tmp;
1500 while (j > i) {
1501 tmp = array[j];
1502 array[j] = array[i];
1503 array[i] = tmp;
1504 j--;
1505 i++;
1506 }
1507 }
1508
1509 /**
1510 * <p>Reverses the order of the given array.</p>
1511 *
1512 * <p>This method does nothing for a {@code null} input array.</p>
1513 *
1514 * @param array the array to reverse, may be {@code null}
1515 */
1516 public static void reverse(byte[] array) {
1517 if (array == null) {
1518 return;
1519 }
1520 int i = 0;
1521 int j = array.length - 1;
1522 byte tmp;
1523 while (j > i) {
1524 tmp = array[j];
1525 array[j] = array[i];
1526 array[i] = tmp;
1527 j--;
1528 i++;
1529 }
1530 }
1531
1532 /**
1533 * <p>Reverses the order of the given array.</p>
1534 *
1535 * <p>This method does nothing for a {@code null} input array.</p>
1536 *
1537 * @param array the array to reverse, may be {@code null}
1538 */
1539 public static void reverse(double[] array) {
1540 if (array == null) {
1541 return;
1542 }
1543 int i = 0;
1544 int j = array.length - 1;
1545 double tmp;
1546 while (j > i) {
1547 tmp = array[j];
1548 array[j] = array[i];
1549 array[i] = tmp;
1550 j--;
1551 i++;
1552 }
1553 }
1554
1555 /**
1556 * <p>Reverses the order of the given array.</p>
1557 *
1558 * <p>This method does nothing for a {@code null} input array.</p>
1559 *
1560 * @param array the array to reverse, may be {@code null}
1561 */
1562 public static void reverse(float[] array) {
1563 if (array == null) {
1564 return;
1565 }
1566 int i = 0;
1567 int j = array.length - 1;
1568 float tmp;
1569 while (j > i) {
1570 tmp = array[j];
1571 array[j] = array[i];
1572 array[i] = tmp;
1573 j--;
1574 i++;
1575 }
1576 }
1577
1578 /**
1579 * <p>Reverses the order of the given array.</p>
1580 *
1581 * <p>This method does nothing for a {@code null} input array.</p>
1582 *
1583 * @param array the array to reverse, may be {@code null}
1584 */
1585 public static void reverse(boolean[] array) {
1586 if (array == null) {
1587 return;
1588 }
1589 int i = 0;
1590 int j = array.length - 1;
1591 boolean tmp;
1592 while (j > i) {
1593 tmp = array[j];
1594 array[j] = array[i];
1595 array[i] = tmp;
1596 j--;
1597 i++;
1598 }
1599 }
1600
1601 // IndexOf search
1602 // ----------------------------------------------------------------------
1603
1604 // Object IndexOf
1605 //-----------------------------------------------------------------------
1606 /**
1607 * <p>Finds the index of the given object in the array.</p>
1608 *
1609 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1610 *
1611 * @param array the array to search through for the object, may be {@code null}
1612 * @param objectToFind the object to find, may be {@code null}
1613 * @return the index of the object within the array,
1614 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1615 */
1616 public static int indexOf(Object[] array, Object objectToFind) {
1617 return indexOf(array, objectToFind, 0);
1618 }
1619
1620 /**
1621 * <p>Finds the index of the given object in the array starting at the given index.</p>
1622 *
1623 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1624 *
1625 * <p>A negative startIndex is treated as zero. A startIndex larger than the array
1626 * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
1627 *
1628 * @param array the array to search through for the object, may be {@code null}
1629 * @param objectToFind the object to find, may be {@code null}
1630 * @param startIndex the index to start searching at
1631 * @return the index of the object within the array starting at the index,
1632 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1633 */
1634 public static int indexOf(Object[] array, Object objectToFind, int startIndex) {
1635 if (array == null) {
1636 return INDEX_NOT_FOUND;
1637 }
1638 if (startIndex < 0) {
1639 startIndex = 0;
1640 }
1641 if (objectToFind == null) {
1642 for (int i = startIndex; i < array.length; i++) {
1643 if (array[i] == null) {
1644 return i;
1645 }
1646 }
1647 } else if (array.getClass().getComponentType().isInstance(objectToFind)) {
1648 for (int i = startIndex; i < array.length; i++) {
1649 if (objectToFind.equals(array[i])) {
1650 return i;
1651 }
1652 }
1653 }
1654 return INDEX_NOT_FOUND;
1655 }
1656
1657 /**
1658 * <p>Finds the last index of the given object within the array.</p>
1659 *
1660 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1661 *
1662 * @param array the array to travers backwords looking for the object, may be {@code null}
1663 * @param objectToFind the object to find, may be {@code null}
1664 * @return the last index of the object within the array,
1665 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1666 */
1667 public static int lastIndexOf(Object[] array, Object objectToFind) {
1668 return lastIndexOf(array, objectToFind, Integer.MAX_VALUE);
1669 }
1670
1671 /**
1672 * <p>Finds the last index of the given object in the array starting at the given index.</p>
1673 *
1674 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1675 *
1676 * <p>A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than
1677 * the array length will search from the end of the array.</p>
1678 *
1679 * @param array the array to traverse for looking for the object, may be {@code null}
1680 * @param objectToFind the object to find, may be {@code null}
1681 * @param startIndex the start index to travers backwards from
1682 * @return the last index of the object within the array,
1683 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1684 */
1685 public static int lastIndexOf(Object[] array, Object objectToFind, int startIndex) {
1686 if (array == null) {
1687 return INDEX_NOT_FOUND;
1688 }
1689 if (startIndex < 0) {
1690 return INDEX_NOT_FOUND;
1691 } else if (startIndex >= array.length) {
1692 startIndex = array.length - 1;
1693 }
1694 if (objectToFind == null) {
1695 for (int i = startIndex; i >= 0; i--) {
1696 if (array[i] == null) {
1697 return i;
1698 }
1699 }
1700 } else if (array.getClass().getComponentType().isInstance(objectToFind)) {
1701 for (int i = startIndex; i >= 0; i--) {
1702 if (objectToFind.equals(array[i])) {
1703 return i;
1704 }
1705 }
1706 }
1707 return INDEX_NOT_FOUND;
1708 }
1709
1710 /**
1711 * <p>Checks if the object is in the given array.</p>
1712 *
1713 * <p>The method returns {@code false} if a {@code null} array is passed in.</p>
1714 *
1715 * @param array the array to search through
1716 * @param objectToFind the object to find
1717 * @return {@code true} if the array contains the object
1718 */
1719 public static boolean contains(Object[] array, Object objectToFind) {
1720 return indexOf(array, objectToFind) != INDEX_NOT_FOUND;
1721 }
1722
1723 // long IndexOf
1724 //-----------------------------------------------------------------------
1725 /**
1726 * <p>Finds the index of the given value in the array.</p>
1727 *
1728 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1729 *
1730 * @param array the array to search through for the object, may be {@code null}
1731 * @param valueToFind the value to find
1732 * @return the index of the value within the array,
1733 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1734 */
1735 public static int indexOf(long[] array, long valueToFind) {
1736 return indexOf(array, valueToFind, 0);
1737 }
1738
1739 /**
1740 * <p>Finds the index of the given value in the array starting at the given index.</p>
1741 *
1742 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1743 *
1744 * <p>A negative startIndex is treated as zero. A startIndex larger than the array
1745 * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
1746 *
1747 * @param array the array to search through for the object, may be {@code null}
1748 * @param valueToFind the value to find
1749 * @param startIndex the index to start searching at
1750 * @return the index of the value within the array,
1751 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1752 */
1753 public static int indexOf(long[] array, long valueToFind, int startIndex) {
1754 if (array == null) {
1755 return INDEX_NOT_FOUND;
1756 }
1757 if (startIndex < 0) {
1758 startIndex = 0;
1759 }
1760 for (int i = startIndex; i < array.length; i++) {
1761 if (valueToFind == array[i]) {
1762 return i;
1763 }
1764 }
1765 return INDEX_NOT_FOUND;
1766 }
1767
1768 /**
1769 * <p>Finds the last index of the given value within the array.</p>
1770 *
1771 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1772 *
1773 * @param array the array to travers backwords looking for the object, may be {@code null}
1774 * @param valueToFind the object to find
1775 * @return the last index of the value within the array,
1776 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1777 */
1778 public static int lastIndexOf(long[] array, long valueToFind) {
1779 return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
1780 }
1781
1782 /**
1783 * <p>Finds the last index of the given value in the array starting at the given index.</p>
1784 *
1785 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1786 *
1787 * <p>A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
1788 * array length will search from the end of the array.</p>
1789 *
1790 * @param array the array to traverse for looking for the object, may be {@code null}
1791 * @param valueToFind the value to find
1792 * @param startIndex the start index to travers backwards from
1793 * @return the last index of the value within the array,
1794 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1795 */
1796 public static int lastIndexOf(long[] array, long valueToFind, int startIndex) {
1797 if (array == null) {
1798 return INDEX_NOT_FOUND;
1799 }
1800 if (startIndex < 0) {
1801 return INDEX_NOT_FOUND;
1802 } else if (startIndex >= array.length) {
1803 startIndex = array.length - 1;
1804 }
1805 for (int i = startIndex; i >= 0; i--) {
1806 if (valueToFind == array[i]) {
1807 return i;
1808 }
1809 }
1810 return INDEX_NOT_FOUND;
1811 }
1812
1813 /**
1814 * <p>Checks if the value is in the given array.</p>
1815 *
1816 * <p>The method returns {@code false} if a {@code null} array is passed in.</p>
1817 *
1818 * @param array the array to search through
1819 * @param valueToFind the value to find
1820 * @return {@code true} if the array contains the object
1821 */
1822 public static boolean contains(long[] array, long valueToFind) {
1823 return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
1824 }
1825
1826 // int IndexOf
1827 //-----------------------------------------------------------------------
1828 /**
1829 * <p>Finds the index of the given value in the array.</p>
1830 *
1831 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1832 *
1833 * @param array the array to search through for the object, may be {@code null}
1834 * @param valueToFind the value to find
1835 * @return the index of the value within the array,
1836 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1837 */
1838 public static int indexOf(int[] array, int valueToFind) {
1839 return indexOf(array, valueToFind, 0);
1840 }
1841
1842 /**
1843 * <p>Finds the index of the given value in the array starting at the given index.</p>
1844 *
1845 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1846 *
1847 * <p>A negative startIndex is treated as zero. A startIndex larger than the array
1848 * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
1849 *
1850 * @param array the array to search through for the object, may be {@code null}
1851 * @param valueToFind the value to find
1852 * @param startIndex the index to start searching at
1853 * @return the index of the value within the array,
1854 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1855 */
1856 public static int indexOf(int[] array, int valueToFind, int startIndex) {
1857 if (array == null) {
1858 return INDEX_NOT_FOUND;
1859 }
1860 if (startIndex < 0) {
1861 startIndex = 0;
1862 }
1863 for (int i = startIndex; i < array.length; i++) {
1864 if (valueToFind == array[i]) {
1865 return i;
1866 }
1867 }
1868 return INDEX_NOT_FOUND;
1869 }
1870
1871 /**
1872 * <p>Finds the last index of the given value within the array.</p>
1873 *
1874 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1875 *
1876 * @param array the array to travers backwords looking for the object, may be {@code null}
1877 * @param valueToFind the object to find
1878 * @return the last index of the value within the array,
1879 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1880 */
1881 public static int lastIndexOf(int[] array, int valueToFind) {
1882 return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
1883 }
1884
1885 /**
1886 * <p>Finds the last index of the given value in the array starting at the given index.</p>
1887 *
1888 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1889 *
1890 * <p>A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
1891 * array length will search from the end of the array.</p>
1892 *
1893 * @param array the array to traverse for looking for the object, may be {@code null}
1894 * @param valueToFind the value to find
1895 * @param startIndex the start index to travers backwards from
1896 * @return the last index of the value within the array,
1897 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1898 */
1899 public static int lastIndexOf(int[] array, int valueToFind, int startIndex) {
1900 if (array == null) {
1901 return INDEX_NOT_FOUND;
1902 }
1903 if (startIndex < 0) {
1904 return INDEX_NOT_FOUND;
1905 } else if (startIndex >= array.length) {
1906 startIndex = array.length - 1;
1907 }
1908 for (int i = startIndex; i >= 0; i--) {
1909 if (valueToFind == array[i]) {
1910 return i;
1911 }
1912 }
1913 return INDEX_NOT_FOUND;
1914 }
1915
1916 /**
1917 * <p>Checks if the value is in the given array.</p>
1918 *
1919 * <p>The method returns {@code false} if a {@code null} array is passed in.</p>
1920 *
1921 * @param array the array to search through
1922 * @param valueToFind the value to find
1923 * @return {@code true} if the array contains the object
1924 */
1925 public static boolean contains(int[] array, int valueToFind) {
1926 return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
1927 }
1928
1929 // short IndexOf
1930 //-----------------------------------------------------------------------
1931 /**
1932 * <p>Finds the index of the given value in the array.</p>
1933 *
1934 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1935 *
1936 * @param array the array to search through for the object, may be {@code null}
1937 * @param valueToFind the value to find
1938 * @return the index of the value within the array,
1939 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1940 */
1941 public static int indexOf(short[] array, short valueToFind) {
1942 return indexOf(array, valueToFind, 0);
1943 }
1944
1945 /**
1946 * <p>Finds the index of the given value in the array starting at the given index.</p>
1947 *
1948 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1949 *
1950 * <p>A negative startIndex is treated as zero. A startIndex larger than the array
1951 * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
1952 *
1953 * @param array the array to search through for the object, may be {@code null}
1954 * @param valueToFind the value to find
1955 * @param startIndex the index to start searching at
1956 * @return the index of the value within the array,
1957 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1958 */
1959 public static int indexOf(short[] array, short valueToFind, int startIndex) {
1960 if (array == null) {
1961 return INDEX_NOT_FOUND;
1962 }
1963 if (startIndex < 0) {
1964 startIndex = 0;
1965 }
1966 for (int i = startIndex; i < array.length; i++) {
1967 if (valueToFind == array[i]) {
1968 return i;
1969 }
1970 }
1971 return INDEX_NOT_FOUND;
1972 }
1973
1974 /**
1975 * <p>Finds the last index of the given value within the array.</p>
1976 *
1977 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1978 *
1979 * @param array the array to travers backwords looking for the object, may be {@code null}
1980 * @param valueToFind the object to find
1981 * @return the last index of the value within the array,
1982 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
1983 */
1984 public static int lastIndexOf(short[] array, short valueToFind) {
1985 return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
1986 }
1987
1988 /**
1989 * <p>Finds the last index of the given value in the array starting at the given index.</p>
1990 *
1991 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
1992 *
1993 * <p>A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
1994 * array length will search from the end of the array.</p>
1995 *
1996 * @param array the array to traverse for looking for the object, may be {@code null}
1997 * @param valueToFind the value to find
1998 * @param startIndex the start index to travers backwards from
1999 * @return the last index of the value within the array,
2000 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2001 */
2002 public static int lastIndexOf(short[] array, short valueToFind, int startIndex) {
2003 if (array == null) {
2004 return INDEX_NOT_FOUND;
2005 }
2006 if (startIndex < 0) {
2007 return INDEX_NOT_FOUND;
2008 } else if (startIndex >= array.length) {
2009 startIndex = array.length - 1;
2010 }
2011 for (int i = startIndex; i >= 0; i--) {
2012 if (valueToFind == array[i]) {
2013 return i;
2014 }
2015 }
2016 return INDEX_NOT_FOUND;
2017 }
2018
2019 /**
2020 * <p>Checks if the value is in the given array.</p>
2021 *
2022 * <p>The method returns {@code false} if a {@code null} array is passed in.</p>
2023 *
2024 * @param array the array to search through
2025 * @param valueToFind the value to find
2026 * @return {@code true} if the array contains the object
2027 */
2028 public static boolean contains(short[] array, short valueToFind) {
2029 return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
2030 }
2031
2032 // char IndexOf
2033 //-----------------------------------------------------------------------
2034 /**
2035 * <p>Finds the index of the given value in the array.</p>
2036 *
2037 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2038 *
2039 * @param array the array to search through for the object, may be {@code null}
2040 * @param valueToFind the value to find
2041 * @return the index of the value within the array,
2042 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2043 * @since 2.1
2044 */
2045 public static int indexOf(char[] array, char valueToFind) {
2046 return indexOf(array, valueToFind, 0);
2047 }
2048
2049 /**
2050 * <p>Finds the index of the given value in the array starting at the given index.</p>
2051 *
2052 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2053 *
2054 * <p>A negative startIndex is treated as zero. A startIndex larger than the array
2055 * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
2056 *
2057 * @param array the array to search through for the object, may be {@code null}
2058 * @param valueToFind the value to find
2059 * @param startIndex the index to start searching at
2060 * @return the index of the value within the array,
2061 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2062 * @since 2.1
2063 */
2064 public static int indexOf(char[] array, char valueToFind, int startIndex) {
2065 if (array == null) {
2066 return INDEX_NOT_FOUND;
2067 }
2068 if (startIndex < 0) {
2069 startIndex = 0;
2070 }
2071 for (int i = startIndex; i < array.length; i++) {
2072 if (valueToFind == array[i]) {
2073 return i;
2074 }
2075 }
2076 return INDEX_NOT_FOUND;
2077 }
2078
2079 /**
2080 * <p>Finds the last index of the given value within the array.</p>
2081 *
2082 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2083 *
2084 * @param array the array to travers backwords looking for the object, may be {@code null}
2085 * @param valueToFind the object to find
2086 * @return the last index of the value within the array,
2087 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2088 * @since 2.1
2089 */
2090 public static int lastIndexOf(char[] array, char valueToFind) {
2091 return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
2092 }
2093
2094 /**
2095 * <p>Finds the last index of the given value in the array starting at the given index.</p>
2096 *
2097 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2098 *
2099 * <p>A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
2100 * array length will search from the end of the array.</p>
2101 *
2102 * @param array the array to traverse for looking for the object, may be {@code null}
2103 * @param valueToFind the value to find
2104 * @param startIndex the start index to travers backwards from
2105 * @return the last index of the value within the array,
2106 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2107 * @since 2.1
2108 */
2109 public static int lastIndexOf(char[] array, char valueToFind, int startIndex) {
2110 if (array == null) {
2111 return INDEX_NOT_FOUND;
2112 }
2113 if (startIndex < 0) {
2114 return INDEX_NOT_FOUND;
2115 } else if (startIndex >= array.length) {
2116 startIndex = array.length - 1;
2117 }
2118 for (int i = startIndex; i >= 0; i--) {
2119 if (valueToFind == array[i]) {
2120 return i;
2121 }
2122 }
2123 return INDEX_NOT_FOUND;
2124 }
2125
2126 /**
2127 * <p>Checks if the value is in the given array.</p>
2128 *
2129 * <p>The method returns {@code false} if a {@code null} array is passed in.</p>
2130 *
2131 * @param array the array to search through
2132 * @param valueToFind the value to find
2133 * @return {@code true} if the array contains the object
2134 * @since 2.1
2135 */
2136 public static boolean contains(char[] array, char valueToFind) {
2137 return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
2138 }
2139
2140 // byte IndexOf
2141 //-----------------------------------------------------------------------
2142 /**
2143 * <p>Finds the index of the given value in the array.</p>
2144 *
2145 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2146 *
2147 * @param array the array to search through for the object, may be {@code null}
2148 * @param valueToFind the value to find
2149 * @return the index of the value within the array,
2150 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2151 */
2152 public static int indexOf(byte[] array, byte valueToFind) {
2153 return indexOf(array, valueToFind, 0);
2154 }
2155
2156 /**
2157 * <p>Finds the index of the given value in the array starting at the given index.</p>
2158 *
2159 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2160 *
2161 * <p>A negative startIndex is treated as zero. A startIndex larger than the array
2162 * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
2163 *
2164 * @param array the array to search through for the object, may be {@code null}
2165 * @param valueToFind the value to find
2166 * @param startIndex the index to start searching at
2167 * @return the index of the value within the array,
2168 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2169 */
2170 public static int indexOf(byte[] array, byte valueToFind, int startIndex) {
2171 if (array == null) {
2172 return INDEX_NOT_FOUND;
2173 }
2174 if (startIndex < 0) {
2175 startIndex = 0;
2176 }
2177 for (int i = startIndex; i < array.length; i++) {
2178 if (valueToFind == array[i]) {
2179 return i;
2180 }
2181 }
2182 return INDEX_NOT_FOUND;
2183 }
2184
2185 /**
2186 * <p>Finds the last index of the given value within the array.</p>
2187 *
2188 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2189 *
2190 * @param array the array to travers backwords looking for the object, may be {@code null}
2191 * @param valueToFind the object to find
2192 * @return the last index of the value within the array,
2193 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2194 */
2195 public static int lastIndexOf(byte[] array, byte valueToFind) {
2196 return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
2197 }
2198
2199 /**
2200 * <p>Finds the last index of the given value in the array starting at the given index.</p>
2201 *
2202 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2203 *
2204 * <p>A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
2205 * array length will search from the end of the array.</p>
2206 *
2207 * @param array the array to traverse for looking for the object, may be {@code null}
2208 * @param valueToFind the value to find
2209 * @param startIndex the start index to travers backwards from
2210 * @return the last index of the value within the array,
2211 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2212 */
2213 public static int lastIndexOf(byte[] array, byte valueToFind, int startIndex) {
2214 if (array == null) {
2215 return INDEX_NOT_FOUND;
2216 }
2217 if (startIndex < 0) {
2218 return INDEX_NOT_FOUND;
2219 } else if (startIndex >= array.length) {
2220 startIndex = array.length - 1;
2221 }
2222 for (int i = startIndex; i >= 0; i--) {
2223 if (valueToFind == array[i]) {
2224 return i;
2225 }
2226 }
2227 return INDEX_NOT_FOUND;
2228 }
2229
2230 /**
2231 * <p>Checks if the value is in the given array.</p>
2232 *
2233 * <p>The method returns {@code false} if a {@code null} array is passed in.</p>
2234 *
2235 * @param array the array to search through
2236 * @param valueToFind the value to find
2237 * @return {@code true} if the array contains the object
2238 */
2239 public static boolean contains(byte[] array, byte valueToFind) {
2240 return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
2241 }
2242
2243 // double IndexOf
2244 //-----------------------------------------------------------------------
2245 /**
2246 * <p>Finds the index of the given value in the array.</p>
2247 *
2248 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2249 *
2250 * @param array the array to search through for the object, may be {@code null}
2251 * @param valueToFind the value to find
2252 * @return the index of the value within the array,
2253 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2254 */
2255 public static int indexOf(double[] array, double valueToFind) {
2256 return indexOf(array, valueToFind, 0);
2257 }
2258
2259 /**
2260 * <p>Finds the index of the given value within a given tolerance in the array.
2261 * This method will return the index of the first value which falls between the region
2262 * defined by valueToFind - tolerance and valueToFind + tolerance.</p>
2263 *
2264 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2265 *
2266 * @param array the array to search through for the object, may be {@code null}
2267 * @param valueToFind the value to find
2268 * @param tolerance tolerance of the search
2269 * @return the index of the value within the array,
2270 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2271 */
2272 public static int indexOf(double[] array, double valueToFind, double tolerance) {
2273 return indexOf(array, valueToFind, 0, tolerance);
2274 }
2275
2276 /**
2277 * <p>Finds the index of the given value in the array starting at the given index.</p>
2278 *
2279 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2280 *
2281 * <p>A negative startIndex is treated as zero. A startIndex larger than the array
2282 * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
2283 *
2284 * @param array the array to search through for the object, may be {@code null}
2285 * @param valueToFind the value to find
2286 * @param startIndex the index to start searching at
2287 * @return the index of the value within the array,
2288 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2289 */
2290 public static int indexOf(double[] array, double valueToFind, int startIndex) {
2291 if (ArrayUtils.isEmpty(array)) {
2292 return INDEX_NOT_FOUND;
2293 }
2294 if (startIndex < 0) {
2295 startIndex = 0;
2296 }
2297 for (int i = startIndex; i < array.length; i++) {
2298 if (valueToFind == array[i]) {
2299 return i;
2300 }
2301 }
2302 return INDEX_NOT_FOUND;
2303 }
2304
2305 /**
2306 * <p>Finds the index of the given value in the array starting at the given index.
2307 * This method will return the index of the first value which falls between the region
2308 * defined by valueToFind - tolerance and valueToFind + tolerance.</p>
2309 *
2310 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2311 *
2312 * <p>A negative startIndex is treated as zero. A startIndex larger than the array
2313 * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
2314 *
2315 * @param array the array to search through for the object, may be {@code null}
2316 * @param valueToFind the value to find
2317 * @param startIndex the index to start searching at
2318 * @param tolerance tolerance of the search
2319 * @return the index of the value within the array,
2320 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2321 */
2322 public static int indexOf(double[] array, double valueToFind, int startIndex, double tolerance) {
2323 if (ArrayUtils.isEmpty(array)) {
2324 return INDEX_NOT_FOUND;
2325 }
2326 if (startIndex < 0) {
2327 startIndex = 0;
2328 }
2329 double min = valueToFind - tolerance;
2330 double max = valueToFind + tolerance;
2331 for (int i = startIndex; i < array.length; i++) {
2332 if (array[i] >= min && array[i] <= max) {
2333 return i;
2334 }
2335 }
2336 return INDEX_NOT_FOUND;
2337 }
2338
2339 /**
2340 * <p>Finds the last index of the given value within the array.</p>
2341 *
2342 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2343 *
2344 * @param array the array to travers backwords looking for the object, may be {@code null}
2345 * @param valueToFind the object to find
2346 * @return the last index of the value within the array,
2347 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2348 */
2349 public static int lastIndexOf(double[] array, double valueToFind) {
2350 return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
2351 }
2352
2353 /**
2354 * <p>Finds the last index of the given value within a given tolerance in the array.
2355 * This method will return the index of the last value which falls between the region
2356 * defined by valueToFind - tolerance and valueToFind + tolerance.</p>
2357 *
2358 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2359 *
2360 * @param array the array to search through for the object, may be {@code null}
2361 * @param valueToFind the value to find
2362 * @param tolerance tolerance of the search
2363 * @return the index of the value within the array,
2364 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2365 */
2366 public static int lastIndexOf(double[] array, double valueToFind, double tolerance) {
2367 return lastIndexOf(array, valueToFind, Integer.MAX_VALUE, tolerance);
2368 }
2369
2370 /**
2371 * <p>Finds the last index of the given value in the array starting at the given index.</p>
2372 *
2373 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2374 *
2375 * <p>A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
2376 * array length will search from the end of the array.</p>
2377 *
2378 * @param array the array to traverse for looking for the object, may be {@code null}
2379 * @param valueToFind the value to find
2380 * @param startIndex the start index to travers backwards from
2381 * @return the last index of the value within the array,
2382 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2383 */
2384 public static int lastIndexOf(double[] array, double valueToFind, int startIndex) {
2385 if (ArrayUtils.isEmpty(array)) {
2386 return INDEX_NOT_FOUND;
2387 }
2388 if (startIndex < 0) {
2389 return INDEX_NOT_FOUND;
2390 } else if (startIndex >= array.length) {
2391 startIndex = array.length - 1;
2392 }
2393 for (int i = startIndex; i >= 0; i--) {
2394 if (valueToFind == array[i]) {
2395 return i;
2396 }
2397 }
2398 return INDEX_NOT_FOUND;
2399 }
2400
2401 /**
2402 * <p>Finds the last index of the given value in the array starting at the given index.
2403 * This method will return the index of the last value which falls between the region
2404 * defined by valueToFind - tolerance and valueToFind + tolerance.</p>
2405 *
2406 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2407 *
2408 * <p>A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
2409 * array length will search from the end of the array.</p>
2410 *
2411 * @param array the array to traverse for looking for the object, may be {@code null}
2412 * @param valueToFind the value to find
2413 * @param startIndex the start index to travers backwards from
2414 * @param tolerance search for value within plus/minus this amount
2415 * @return the last index of the value within the array,
2416 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2417 */
2418 public static int lastIndexOf(double[] array, double valueToFind, int startIndex, double tolerance) {
2419 if (ArrayUtils.isEmpty(array)) {
2420 return INDEX_NOT_FOUND;
2421 }
2422 if (startIndex < 0) {
2423 return INDEX_NOT_FOUND;
2424 } else if (startIndex >= array.length) {
2425 startIndex = array.length - 1;
2426 }
2427 double min = valueToFind - tolerance;
2428 double max = valueToFind + tolerance;
2429 for (int i = startIndex; i >= 0; i--) {
2430 if (array[i] >= min && array[i] <= max) {
2431 return i;
2432 }
2433 }
2434 return INDEX_NOT_FOUND;
2435 }
2436
2437 /**
2438 * <p>Checks if the value is in the given array.</p>
2439 *
2440 * <p>The method returns {@code false} if a {@code null} array is passed in.</p>
2441 *
2442 * @param array the array to search through
2443 * @param valueToFind the value to find
2444 * @return {@code true} if the array contains the object
2445 */
2446 public static boolean contains(double[] array, double valueToFind) {
2447 return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
2448 }
2449
2450 /**
2451 * <p>Checks if a value falling within the given tolerance is in the
2452 * given array. If the array contains a value within the inclusive range
2453 * defined by (value - tolerance) to (value + tolerance).</p>
2454 *
2455 * <p>The method returns {@code false} if a {@code null} array
2456 * is passed in.</p>
2457 *
2458 * @param array the array to search
2459 * @param valueToFind the value to find
2460 * @param tolerance the array contains the tolerance of the search
2461 * @return true if value falling within tolerance is in array
2462 */
2463 public static boolean contains(double[] array, double valueToFind, double tolerance) {
2464 return indexOf(array, valueToFind, 0, tolerance) != INDEX_NOT_FOUND;
2465 }
2466
2467 // float IndexOf
2468 //-----------------------------------------------------------------------
2469 /**
2470 * <p>Finds the index of the given value in the array.</p>
2471 *
2472 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2473 *
2474 * @param array the array to search through for the object, may be {@code null}
2475 * @param valueToFind the value to find
2476 * @return the index of the value within the array,
2477 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2478 */
2479 public static int indexOf(float[] array, float valueToFind) {
2480 return indexOf(array, valueToFind, 0);
2481 }
2482
2483 /**
2484 * <p>Finds the index of the given value in the array starting at the given index.</p>
2485 *
2486 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2487 *
2488 * <p>A negative startIndex is treated as zero. A startIndex larger than the array
2489 * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
2490 *
2491 * @param array the array to search through for the object, may be {@code null}
2492 * @param valueToFind the value to find
2493 * @param startIndex the index to start searching at
2494 * @return the index of the value within the array,
2495 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2496 */
2497 public static int indexOf(float[] array, float valueToFind, int startIndex) {
2498 if (ArrayUtils.isEmpty(array)) {
2499 return INDEX_NOT_FOUND;
2500 }
2501 if (startIndex < 0) {
2502 startIndex = 0;
2503 }
2504 for (int i = startIndex; i < array.length; i++) {
2505 if (valueToFind == array[i]) {
2506 return i;
2507 }
2508 }
2509 return INDEX_NOT_FOUND;
2510 }
2511
2512 /**
2513 * <p>Finds the last index of the given value within the array.</p>
2514 *
2515 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2516 *
2517 * @param array the array to travers backwords looking for the object, may be {@code null}
2518 * @param valueToFind the object to find
2519 * @return the last index of the value within the array,
2520 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2521 */
2522 public static int lastIndexOf(float[] array, float valueToFind) {
2523 return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
2524 }
2525
2526 /**
2527 * <p>Finds the last index of the given value in the array starting at the given index.</p>
2528 *
2529 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2530 *
2531 * <p>A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
2532 * array length will search from the end of the array.</p>
2533 *
2534 * @param array the array to traverse for looking for the object, may be {@code null}
2535 * @param valueToFind the value to find
2536 * @param startIndex the start index to travers backwards from
2537 * @return the last index of the value within the array,
2538 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2539 */
2540 public static int lastIndexOf(float[] array, float valueToFind, int startIndex) {
2541 if (ArrayUtils.isEmpty(array)) {
2542 return INDEX_NOT_FOUND;
2543 }
2544 if (startIndex < 0) {
2545 return INDEX_NOT_FOUND;
2546 } else if (startIndex >= array.length) {
2547 startIndex = array.length - 1;
2548 }
2549 for (int i = startIndex; i >= 0; i--) {
2550 if (valueToFind == array[i]) {
2551 return i;
2552 }
2553 }
2554 return INDEX_NOT_FOUND;
2555 }
2556
2557 /**
2558 * <p>Checks if the value is in the given array.</p>
2559 *
2560 * <p>The method returns {@code false} if a {@code null} array is passed in.</p>
2561 *
2562 * @param array the array to search through
2563 * @param valueToFind the value to find
2564 * @return {@code true} if the array contains the object
2565 */
2566 public static boolean contains(float[] array, float valueToFind) {
2567 return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
2568 }
2569
2570 // boolean IndexOf
2571 //-----------------------------------------------------------------------
2572 /**
2573 * <p>Finds the index of the given value in the array.</p>
2574 *
2575 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2576 *
2577 * @param array the array to search through for the object, may be {@code null}
2578 * @param valueToFind the value to find
2579 * @return the index of the value within the array,
2580 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2581 */
2582 public static int indexOf(boolean[] array, boolean valueToFind) {
2583 return indexOf(array, valueToFind, 0);
2584 }
2585
2586 /**
2587 * <p>Finds the index of the given value in the array starting at the given index.</p>
2588 *
2589 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2590 *
2591 * <p>A negative startIndex is treated as zero. A startIndex larger than the array
2592 * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
2593 *
2594 * @param array the array to search through for the object, may be {@code null}
2595 * @param valueToFind the value to find
2596 * @param startIndex the index to start searching at
2597 * @return the index of the value within the array,
2598 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null}
2599 * array input
2600 */
2601 public static int indexOf(boolean[] array, boolean valueToFind, int startIndex) {
2602 if (ArrayUtils.isEmpty(array)) {
2603 return INDEX_NOT_FOUND;
2604 }
2605 if (startIndex < 0) {
2606 startIndex = 0;
2607 }
2608 for (int i = startIndex; i < array.length; i++) {
2609 if (valueToFind == array[i]) {
2610 return i;
2611 }
2612 }
2613 return INDEX_NOT_FOUND;
2614 }
2615
2616 /**
2617 * <p>Finds the last index of the given value within the array.</p>
2618 *
2619 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) if
2620 * {@code null} array input.</p>
2621 *
2622 * @param array the array to travers backwords looking for the object, may be {@code null}
2623 * @param valueToFind the object to find
2624 * @return the last index of the value within the array,
2625 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2626 */
2627 public static int lastIndexOf(boolean[] array, boolean valueToFind) {
2628 return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
2629 }
2630
2631 /**
2632 * <p>Finds the last index of the given value in the array starting at the given index.</p>
2633 *
2634 * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
2635 *
2636 * <p>A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than
2637 * the array length will search from the end of the array.</p>
2638 *
2639 * @param array the array to traverse for looking for the object, may be {@code null}
2640 * @param valueToFind the value to find
2641 * @param startIndex the start index to travers backwards from
2642 * @return the last index of the value within the array,
2643 * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
2644 */
2645 public static int lastIndexOf(boolean[] array, boolean valueToFind, int startIndex) {
2646 if (ArrayUtils.isEmpty(array)) {
2647 return INDEX_NOT_FOUND;
2648 }
2649 if (startIndex < 0) {
2650 return INDEX_NOT_FOUND;
2651 } else if (startIndex >= array.length) {
2652 startIndex = array.length - 1;
2653 }
2654 for (int i = startIndex; i >= 0; i--) {
2655 if (valueToFind == array[i]) {
2656 return i;
2657 }
2658 }
2659 return INDEX_NOT_FOUND;
2660 }
2661
2662 /**
2663 * <p>Checks if the value is in the given array.</p>
2664 *
2665 * <p>The method returns {@code false} if a {@code null} array is passed in.</p>
2666 *
2667 * @param array the array to search through
2668 * @param valueToFind the value to find
2669 * @return {@code true} if the array contains the object
2670 */
2671 public static boolean contains(boolean[] array, boolean valueToFind) {
2672 return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
2673 }
2674
2675 // Primitive/Object array converters
2676 // ----------------------------------------------------------------------
2677
2678 // Character array converters
2679 // ----------------------------------------------------------------------
2680 /**
2681 * <p>Converts an array of object Characters to primitives.</p>
2682 *
2683 * <p>This method returns {@code null} for a {@code null} input array.</p>
2684 *
2685 * @param array a {@code Character} array, may be {@code null}
2686 * @return a {@code char} array, {@code null} if null array input
2687 * @throws NullPointerException if array content is {@code null}
2688 */
2689 public static char[] toPrimitive(Character[] array) {
2690 if (array == null) {
2691 return null;
2692 } else if (array.length == 0) {
2693 return EMPTY_CHAR_ARRAY;
2694 }
2695 final char[] result = new char[array.length];
2696 for (int i = 0; i < array.length; i++) {
2697 result[i] = array[i].charValue();
2698 }
2699 return result;
2700 }
2701
2702 /**
2703 * <p>Converts an array of object Character to primitives handling {@code null}.</p>
2704 *
2705 * <p>This method returns {@code null} for a {@code null} input array.</p>
2706 *
2707 * @param array a {@code Character} array, may be {@code null}
2708 * @param valueForNull the value to insert if {@code null} found
2709 * @return a {@code char} array, {@code null} if null array input
2710 */
2711 public static char[] toPrimitive(Character[] array, char valueForNull) {
2712 if (array == null) {
2713 return null;
2714 } else if (array.length == 0) {
2715 return EMPTY_CHAR_ARRAY;
2716 }
2717 final char[] result = new char[array.length];
2718 for (int i = 0; i < array.length; i++) {
2719 Character b = array[i];
2720 result[i] = (b == null ? valueForNull : b.charValue());
2721 }
2722 return result;
2723 }
2724
2725 /**
2726 * <p>Converts an array of primitive chars to objects.</p>
2727 *
2728 * <p>This method returns {@code null} for a {@code null} input array.</p>
2729 *
2730 * @param array a {@code char} array
2731 * @return a {@code Character} array, {@code null} if null array input
2732 */
2733 public static Character[] toObject(char[] array) {
2734 if (array == null) {
2735 return null;
2736 } else if (array.length == 0) {
2737 return EMPTY_CHARACTER_OBJECT_ARRAY;
2738 }
2739 final Character[] result = new Character[array.length];
2740 for (int i = 0; i < array.length; i++) {
2741 result[i] = Character.valueOf(array[i]);
2742 }
2743 return result;
2744 }
2745
2746 // Long array converters
2747 // ----------------------------------------------------------------------
2748 /**
2749 * <p>Converts an array of object Longs to primitives.</p>
2750 *
2751 * <p>This method returns {@code null} for a {@code null} input array.</p>
2752 *
2753 * @param array a {@code Long} array, may be {@code null}
2754 * @return a {@code long} array, {@code null} if null array input
2755 * @throws NullPointerException if array content is {@code null}
2756 */
2757 public static long[] toPrimitive(Long[] array) {
2758 if (array == null) {
2759 return null;
2760 } else if (array.length == 0) {
2761 return EMPTY_LONG_ARRAY;
2762 }
2763 final long[] result = new long[array.length];
2764 for (int i = 0; i < array.length; i++) {
2765 result[i] = array[i].longValue();
2766 }
2767 return result;
2768 }
2769
2770 /**
2771 * <p>Converts an array of object Long to primitives handling {@code null}.</p>
2772 *
2773 * <p>This method returns {@code null} for a {@code null} input array.</p>
2774 *
2775 * @param array a {@code Long} array, may be {@code null}
2776 * @param valueForNull the value to insert if {@code null} found
2777 * @return a {@code long} array, {@code null} if null array input
2778 */
2779 public static long[] toPrimitive(Long[] array, long valueForNull) {
2780 if (array == null) {
2781 return null;
2782 } else if (array.length == 0) {
2783 return EMPTY_LONG_ARRAY;
2784 }
2785 final long[] result = new long[array.length];
2786 for (int i = 0; i < array.length; i++) {
2787 Long b = array[i];
2788 result[i] = (b == null ? valueForNull : b.longValue());
2789 }
2790 return result;
2791 }
2792
2793 /**
2794 * <p>Converts an array of primitive longs to objects.</p>
2795 *
2796 * <p>This method returns {@code null} for a {@code null} input array.</p>
2797 *
2798 * @param array a {@code long} array
2799 * @return a {@code Long} array, {@code null} if null array input
2800 */
2801 public static Long[] toObject(long[] array) {
2802 if (array == null) {
2803 return null;
2804 } else if (array.length == 0) {
2805 return EMPTY_LONG_OBJECT_ARRAY;
2806 }
2807 final Long[] result = new Long[array.length];
2808 for (int i = 0; i < array.length; i++) {
2809 result[i] = Long.valueOf(array[i]);
2810 }
2811 return result;
2812 }
2813
2814 // Int array converters
2815 // ----------------------------------------------------------------------
2816 /**
2817 * <p>Converts an array of object Integers to primitives.</p>
2818 *
2819 * <p>This method returns {@code null} for a {@code null} input array.</p>
2820 *
2821 * @param array a {@code Integer} array, may be {@code null}
2822 * @return an {@code int} array, {@code null} if null array input
2823 * @throws NullPointerException if array content is {@code null}
2824 */
2825 public static int[] toPrimitive(Integer[] array) {
2826 if (array == null) {
2827 return null;
2828 } else if (array.length == 0) {
2829 return EMPTY_INT_ARRAY;
2830 }
2831 final int[] result = new int[array.length];
2832 for (int i = 0; i < array.length; i++) {
2833 result[i] = array[i].intValue();
2834 }
2835 return result;
2836 }
2837
2838 /**
2839 * <p>Converts an array of object Integer to primitives handling {@code null}.</p>
2840 *
2841 * <p>This method returns {@code null} for a {@code null} input array.</p>
2842 *
2843 * @param array a {@code Integer} array, may be {@code null}
2844 * @param valueForNull the value to insert if {@code null} found
2845 * @return an {@code int} array, {@code null} if null array input
2846 */
2847 public static int[] toPrimitive(Integer[] array, int valueForNull) {
2848 if (array == null) {
2849 return null;
2850 } else if (array.length == 0) {
2851 return EMPTY_INT_ARRAY;
2852 }
2853 final int[] result = new int[array.length];
2854 for (int i = 0; i < array.length; i++) {
2855 Integer b = array[i];
2856 result[i] = (b == null ? valueForNull : b.intValue());
2857 }
2858 return result;
2859 }
2860
2861 /**
2862 * <p>Converts an array of primitive ints to objects.</p>
2863 *
2864 * <p>This method returns {@code null} for a {@code null} input array.</p>
2865 *
2866 * @param array an {@code int} array
2867 * @return an {@code Integer} array, {@code null} if null array input
2868 */
2869 public static Integer[] toObject(int[] array) {
2870 if (array == null) {
2871 return null;
2872 } else if (array.length == 0) {
2873 return EMPTY_INTEGER_OBJECT_ARRAY;
2874 }
2875 final Integer[] result = new Integer[array.length];
2876 for (int i = 0; i < array.length; i++) {
2877 result[i] = Integer.valueOf(array[i]);
2878 }
2879 return result;
2880 }
2881
2882 // Short array converters
2883 // ----------------------------------------------------------------------
2884 /**
2885 * <p>Converts an array of object Shorts to primitives.</p>
2886 *
2887 * <p>This method returns {@code null} for a {@code null} input array.</p>
2888 *
2889 * @param array a {@code Short} array, may be {@code null}
2890 * @return a {@code byte} array, {@code null} if null array input
2891 * @throws NullPointerException if array content is {@code null}
2892 */
2893 public static short[] toPrimitive(Short[] array) {
2894 if (array == null) {
2895 return null;
2896 } else if (array.length == 0) {
2897 return EMPTY_SHORT_ARRAY;
2898 }
2899 final short[] result = new short[array.length];
2900 for (int i = 0; i < array.length; i++) {
2901 result[i] = array[i].shortValue();
2902 }
2903 return result;
2904 }
2905
2906 /**
2907 * <p>Converts an array of object Short to primitives handling {@code null}.</p>
2908 *
2909 * <p>This method returns {@code null} for a {@code null} input array.</p>
2910 *
2911 * @param array a {@code Short} array, may be {@code null}
2912 * @param valueForNull the value to insert if {@code null} found
2913 * @return a {@code byte} array, {@code null} if null array input
2914 */
2915 public static short[] toPrimitive(Short[] array, short valueForNull) {
2916 if (array == null) {
2917 return null;
2918 } else if (array.length == 0) {
2919 return EMPTY_SHORT_ARRAY;
2920 }
2921 final short[] result = new short[array.length];
2922 for (int i = 0; i < array.length; i++) {
2923 Short b = array[i];
2924 result[i] = (b == null ? valueForNull : b.shortValue());
2925 }
2926 return result;
2927 }
2928
2929 /**
2930 * <p>Converts an array of primitive shorts to objects.</p>
2931 *
2932 * <p>This method returns {@code null} for a {@code null} input array.</p>
2933 *
2934 * @param array a {@code short} array
2935 * @return a {@code Short} array, {@code null} if null array input
2936 */
2937 public static Short[] toObject(short[] array) {
2938 if (array == null) {
2939 return null;
2940 } else if (array.length == 0) {
2941 return EMPTY_SHORT_OBJECT_ARRAY;
2942 }
2943 final Short[] result = new Short[array.length];
2944 for (int i = 0; i < array.length; i++) {
2945 result[i] = Short.valueOf(array[i]);
2946 }
2947 return result;
2948 }
2949
2950 // Byte array converters
2951 // ----------------------------------------------------------------------
2952 /**
2953 * <p>Converts an array of object Bytes to primitives.</p>
2954 *
2955 * <p>This method returns {@code null} for a {@code null} input array.</p>
2956 *
2957 * @param array a {@code Byte} array, may be {@code null}
2958 * @return a {@code byte} array, {@code null} if null array input
2959 * @throws NullPointerException if array content is {@code null}
2960 */
2961 public static byte[] toPrimitive(Byte[] array) {
2962 if (array == null) {
2963 return null;
2964 } else if (array.length == 0) {
2965 return EMPTY_BYTE_ARRAY;
2966 }
2967 final byte[] result = new byte[array.length];
2968 for (int i = 0; i < array.length; i++) {
2969 result[i] = array[i].byteValue();
2970 }
2971 return result;
2972 }
2973
2974 /**
2975 * <p>Converts an array of object Bytes to primitives handling {@code null}.</p>
2976 *
2977 * <p>This method returns {@code null} for a {@code null} input array.</p>
2978 *
2979 * @param array a {@code Byte} array, may be {@code null}
2980 * @param valueForNull the value to insert if {@code null} found
2981 * @return a {@code byte} array, {@code null} if null array input
2982 */
2983 public static byte[] toPrimitive(Byte[] array, byte valueForNull) {
2984 if (array == null) {
2985 return null;
2986 } else if (array.length == 0) {
2987 return EMPTY_BYTE_ARRAY;
2988 }
2989 final byte[] result = new byte[array.length];
2990 for (int i = 0; i < array.length; i++) {
2991 Byte b = array[i];
2992 result[i] = (b == null ? valueForNull : b.byteValue());
2993 }
2994 return result;
2995 }
2996
2997 /**
2998 * <p>Converts an array of primitive bytes to objects.</p>
2999 *
3000 * <p>This method returns {@code null} for a {@code null} input array.</p>
3001 *
3002 * @param array a {@code byte} array
3003 * @return a {@code Byte} array, {@code null} if null array input
3004 */
3005 public static Byte[] toObject(byte[] array) {
3006 if (array == null) {
3007 return null;
3008 } else if (array.length == 0) {
3009 return EMPTY_BYTE_OBJECT_ARRAY;
3010 }
3011 final Byte[] result = new Byte[array.length];
3012 for (int i = 0; i < array.length; i++) {
3013 result[i] = Byte.valueOf(array[i]);
3014 }
3015 return result;
3016 }
3017
3018 // Double array converters
3019 // ----------------------------------------------------------------------
3020 /**
3021 * <p>Converts an array of object Doubles to primitives.</p>
3022 *
3023 * <p>This method returns {@code null} for a {@code null} input array.</p>
3024 *
3025 * @param array a {@code Double} array, may be {@code null}
3026 * @return a {@code double} array, {@code null} if null array input
3027 * @throws NullPointerException if array content is {@code null}
3028 */
3029 public static double[] toPrimitive(Double[] array) {
3030 if (array == null) {
3031 return null;
3032 } else if (array.length == 0) {
3033 return EMPTY_DOUBLE_ARRAY;
3034 }
3035 final double[] result = new double[array.length];
3036 for (int i = 0; i < array.length; i++) {
3037 result[i] = array[i].doubleValue();
3038 }
3039 return result;
3040 }
3041
3042 /**
3043 * <p>Converts an array of object Doubles to primitives handling {@code null}.</p>
3044 *
3045 * <p>This method returns {@code null} for a {@code null} input array.</p>
3046 *
3047 * @param array a {@code Double} array, may be {@code null}
3048 * @param valueForNull the value to insert if {@code null} found
3049 * @return a {@code double} array, {@code null} if null array input
3050 */
3051 public static double[] toPrimitive(Double[] array, double valueForNull) {
3052 if (array == null) {
3053 return null;
3054 } else if (array.length == 0) {
3055 return EMPTY_DOUBLE_ARRAY;
3056 }
3057 final double[] result = new double[array.length];
3058 for (int i = 0; i < array.length; i++) {
3059 Double b = array[i];
3060 result[i] = (b == null ? valueForNull : b.doubleValue());
3061 }
3062 return result;
3063 }
3064
3065 /**
3066 * <p>Converts an array of primitive doubles to objects.</p>
3067 *
3068 * <p>This method returns {@code null} for a {@code null} input array.</p>
3069 *
3070 * @param array a {@code double} array
3071 * @return a {@code Double} array, {@code null} if null array input
3072 */
3073 public static Double[] toObject(double[] array) {
3074 if (array == null) {
3075 return null;
3076 } else if (array.length == 0) {
3077 return EMPTY_DOUBLE_OBJECT_ARRAY;
3078 }
3079 final Double[] result = new Double[array.length];
3080 for (int i = 0; i < array.length; i++) {
3081 result[i] = Double.valueOf(array[i]);
3082 }
3083 return result;
3084 }
3085
3086 // Float array converters
3087 // ----------------------------------------------------------------------
3088 /**
3089 * <p>Converts an array of object Floats to primitives.</p>
3090 *
3091 * <p>This method returns {@code null} for a {@code null} input array.</p>
3092 *
3093 * @param array a {@code Float} array, may be {@code null}
3094 * @return a {@code float} array, {@code null} if null array input
3095 * @throws NullPointerException if array content is {@code null}
3096 */
3097 public static float[] toPrimitive(Float[] array) {
3098 if (array == null) {
3099 return null;
3100 } else if (array.length == 0) {
3101 return EMPTY_FLOAT_ARRAY;
3102 }
3103 final float[] result = new float[array.length];
3104 for (int i = 0; i < array.length; i++) {
3105 result[i] = array[i].floatValue();
3106 }
3107 return result;
3108 }
3109
3110 /**
3111 * <p>Converts an array of object Floats to primitives handling {@code null}.</p>
3112 *
3113 * <p>This method returns {@code null} for a {@code null} input array.</p>
3114 *
3115 * @param array a {@code Float} array, may be {@code null}
3116 * @param valueForNull the value to insert if {@code null} found
3117 * @return a {@code float} array, {@code null} if null array input
3118 */
3119 public static float[] toPrimitive(Float[] array, float valueForNull) {
3120 if (array == null) {
3121 return null;
3122 } else if (array.length == 0) {
3123 return EMPTY_FLOAT_ARRAY;
3124 }
3125 final float[] result = new float[array.length];
3126 for (int i = 0; i < array.length; i++) {
3127 Float b = array[i];
3128 result[i] = (b == null ? valueForNull : b.floatValue());
3129 }
3130 return result;
3131 }
3132
3133 /**
3134 * <p>Converts an array of primitive floats to objects.</p>
3135 *
3136 * <p>This method returns {@code null} for a {@code null} input array.</p>
3137 *
3138 * @param array a {@code float} array
3139 * @return a {@code Float} array, {@code null} if null array input
3140 */
3141 public static Float[] toObject(float[] array) {
3142 if (array == null) {
3143 return null;
3144 } else if (array.length == 0) {
3145 return EMPTY_FLOAT_OBJECT_ARRAY;
3146 }
3147 final Float[] result = new Float[array.length];
3148 for (int i = 0; i < array.length; i++) {
3149 result[i] = Float.valueOf(array[i]);
3150 }
3151 return result;
3152 }
3153
3154 // Boolean array converters
3155 // ----------------------------------------------------------------------
3156 /**
3157 * <p>Converts an array of object Booleans to primitives.</p>
3158 *
3159 * <p>This method returns {@code null} for a {@code null} input array.</p>
3160 *
3161 * @param array a {@code Boolean} array, may be {@code null}
3162 * @return a {@code boolean} array, {@code null} if null array input
3163 * @throws NullPointerException if array content is {@code null}
3164 */
3165 public static boolean[] toPrimitive(Boolean[] array) {
3166 if (array == null) {
3167 return null;
3168 } else if (array.length == 0) {
3169 return EMPTY_BOOLEAN_ARRAY;
3170 }
3171 final boolean[] result = new boolean[array.length];
3172 for (int i = 0; i < array.length; i++) {
3173 result[i] = array[i].booleanValue();
3174 }
3175 return result;
3176 }
3177
3178 /**
3179 * <p>Converts an array of object Booleans to primitives handling {@code null}.</p>
3180 *
3181 * <p>This method returns {@code null} for a {@code null} input array.</p>
3182 *
3183 * @param array a {@code Boolean} array, may be {@code null}
3184 * @param valueForNull the value to insert if {@code null} found
3185 * @return a {@code boolean} array, {@code null} if null array input
3186 */
3187 public static boolean[] toPrimitive(Boolean[] array, boolean valueForNull) {
3188 if (array == null) {
3189 return null;
3190 } else if (array.length == 0) {
3191 return EMPTY_BOOLEAN_ARRAY;
3192 }
3193 final boolean[] result = new boolean[array.length];
3194 for (int i = 0; i < array.length; i++) {
3195 Boolean b = array[i];
3196 result[i] = (b == null ? valueForNull : b.booleanValue());
3197 }
3198 return result;
3199 }
3200
3201 /**
3202 * <p>Converts an array of primitive booleans to objects.</p>
3203 *
3204 * <p>This method returns {@code null} for a {@code null} input array.</p>
3205 *
3206 * @param array a {@code boolean} array
3207 * @return a {@code Boolean} array, {@code null} if null array input
3208 */
3209 public static Boolean[] toObject(boolean[] array) {
3210 if (array == null) {
3211 return null;
3212 } else if (array.length == 0) {
3213 return EMPTY_BOOLEAN_OBJECT_ARRAY;
3214 }
3215 final Boolean[] result = new Boolean[array.length];
3216 for (int i = 0; i < array.length; i++) {
3217 result[i] = (array[i] ? Boolean.TRUE : Boolean.FALSE);
3218 }
3219 return result;
3220 }
3221
3222 // ----------------------------------------------------------------------
3223 /**
3224 * <p>Checks if an array of Objects is empty or {@code null}.</p>
3225 *
3226 * @param array the array to test
3227 * @return {@code true} if the array is empty or {@code null}
3228 * @since 2.1
3229 */
3230 public static boolean isEmpty(Object[] array) {
3231 return array == null || array.length == 0;
3232 }
3233
3234 /**
3235 * <p>Checks if an array of primitive longs is empty or {@code null}.</p>
3236 *
3237 * @param array the array to test
3238 * @return {@code true} if the array is empty or {@code null}
3239 * @since 2.1
3240 */
3241 public static boolean isEmpty(long[] array) {
3242 return array == null || array.length == 0;
3243 }
3244
3245 /**
3246 * <p>Checks if an array of primitive ints is empty or {@code null}.</p>
3247 *
3248 * @param array the array to test
3249 * @return {@code true} if the array is empty or {@code null}
3250 * @since 2.1
3251 */
3252 public static boolean isEmpty(int[] array) {
3253 return array == null || array.length == 0;
3254 }
3255
3256 /**
3257 * <p>Checks if an array of primitive shorts is empty or {@code null}.</p>
3258 *
3259 * @param array the array to test
3260 * @return {@code true} if the array is empty or {@code null}
3261 * @since 2.1
3262 */
3263 public static boolean isEmpty(short[] array) {
3264 return array == null || array.length == 0;
3265 }
3266
3267 /**
3268 * <p>Checks if an array of primitive chars is empty or {@code null}.</p>
3269 *
3270 * @param array the array to test
3271 * @return {@code true} if the array is empty or {@code null}
3272 * @since 2.1
3273 */
3274 public static boolean isEmpty(char[] array) {
3275 return array == null || array.length == 0;
3276 }
3277
3278 /**
3279 * <p>Checks if an array of primitive bytes is empty or {@code null}.</p>
3280 *
3281 * @param array the array to test
3282 * @return {@code true} if the array is empty or {@code null}
3283 * @since 2.1
3284 */
3285 public static boolean isEmpty(byte[] array) {
3286 return array == null || array.length == 0;
3287 }
3288
3289 /**
3290 * <p>Checks if an array of primitive doubles is empty or {@code null}.</p>
3291 *
3292 * @param array the array to test
3293 * @return {@code true} if the array is empty or {@code null}
3294 * @since 2.1
3295 */
3296 public static boolean isEmpty(double[] array) {
3297 return array == null || array.length == 0;
3298 }
3299
3300 /**
3301 * <p>Checks if an array of primitive floats is empty or {@code null}.</p>
3302 *
3303 * @param array the array to test
3304 * @return {@code true} if the array is empty or {@code null}
3305 * @since 2.1
3306 */
3307 public static boolean isEmpty(float[] array) {
3308 return array == null || array.length == 0;
3309 }
3310
3311 /**
3312 * <p>Checks if an array of primitive booleans is empty or {@code null}.</p>
3313 *
3314 * @param array the array to test
3315 * @return {@code true} if the array is empty or {@code null}
3316 * @since 2.1
3317 */
3318 public static boolean isEmpty(boolean[] array) {
3319 return array == null || array.length == 0;
3320 }
3321
3322 // ----------------------------------------------------------------------
3323 /**
3324 * <p>Checks if an array of Objects is not empty or not {@code null}.</p>
3325 *
3326 * @param <T> the component type of the array
3327 * @param array the array to test
3328 * @return {@code true} if the array is not empty or not {@code null}
3329 * @since 2.5
3330 */
3331 public static <T> boolean isNotEmpty(T[] array) {
3332 return (array != null && array.length != 0);
3333 }
3334
3335 /**
3336 * <p>Checks if an array of primitive longs is not empty or not {@code null}.</p>
3337 *
3338 * @param array the array to test
3339 * @return {@code true} if the array is not empty or not {@code null}
3340 * @since 2.5
3341 */
3342 public static boolean isNotEmpty(long[] array) {
3343 return (array != null && array.length != 0);
3344 }
3345
3346 /**
3347 * <p>Checks if an array of primitive ints is not empty or not {@code null}.</p>
3348 *
3349 * @param array the array to test
3350 * @return {@code true} if the array is not empty or not {@code null}
3351 * @since 2.5
3352 */
3353 public static boolean isNotEmpty(int[] array) {
3354 return (array != null && array.length != 0);
3355 }
3356
3357 /**
3358 * <p>Checks if an array of primitive shorts is not empty or not {@code null}.</p>
3359 *
3360 * @param array the array to test
3361 * @return {@code true} if the array is not empty or not {@code null}
3362 * @since 2.5
3363 */
3364 public static boolean isNotEmpty(short[] array) {
3365 return (array != null && array.length != 0);
3366 }
3367
3368 /**
3369 * <p>Checks if an array of primitive chars is not empty or not {@code null}.</p>
3370 *
3371 * @param array the array to test
3372 * @return {@code true} if the array is not empty or not {@code null}
3373 * @since 2.5
3374 */
3375 public static boolean isNotEmpty(char[] array) {
3376 return (array != null && array.length != 0);
3377 }
3378
3379 /**
3380 * <p>Checks if an array of primitive bytes is not empty or not {@code null}.</p>
3381 *
3382 * @param array the array to test
3383 * @return {@code true} if the array is not empty or not {@code null}
3384 * @since 2.5
3385 */
3386 public static boolean isNotEmpty(byte[] array) {
3387 return (array != null && array.length != 0);
3388 }
3389
3390 /**
3391 * <p>Checks if an array of primitive doubles is not empty or not {@code null}.</p>
3392 *
3393 * @param array the array to test
3394 * @return {@code true} if the array is not empty or not {@code null}
3395 * @since 2.5
3396 */
3397 public static boolean isNotEmpty(double[] array) {
3398 return (array != null && array.length != 0);
3399 }
3400
3401 /**
3402 * <p>Checks if an array of primitive floats is not empty or not {@code null}.</p>
3403 *
3404 * @param array the array to test
3405 * @return {@code true} if the array is not empty or not {@code null}
3406 * @since 2.5
3407 */
3408 public static boolean isNotEmpty(float[] array) {
3409 return (array != null && array.length != 0);
3410 }
3411
3412 /**
3413 * <p>Checks if an array of primitive booleans is not empty or not {@code null}.</p>
3414 *
3415 * @param array the array to test
3416 * @return {@code true} if the array is not empty or not {@code null}
3417 * @since 2.5
3418 */
3419 public static boolean isNotEmpty(boolean[] array) {
3420 return (array != null && array.length != 0);
3421 }
3422
3423 /**
3424 * <p>Adds all the elements of the given arrays into a new array.</p>
3425 * <p>The new array contains all of the element of {@code array1} followed
3426 * by all of the elements {@code array2}. When an array is returned, it is always
3427 * a new array.</p>
3428 *
3429 * <pre>
3430 * ArrayUtils.addAll(null, null) = null
3431 * ArrayUtils.addAll(array1, null) = cloned copy of array1
3432 * ArrayUtils.addAll(null, array2) = cloned copy of array2
3433 * ArrayUtils.addAll([], []) = []
3434 * ArrayUtils.addAll([null], [null]) = [null, null]
3435 * ArrayUtils.addAll(["a", "b", "c"], ["1", "2", "3"]) = ["a", "b", "c", "1", "2", "3"]
3436 * </pre>
3437 *
3438 * @param <T> the component type of the array
3439 * @param array1 the first array whose elements are added to the new array, may be {@code null}
3440 * @param array2 the second array whose elements are added to the new array, may be {@code null}
3441 * @return The new array, {@code null} if both arrays are {@code null}.
3442 * The type of the new array is the type of the first array,
3443 * unless the first array is null, in which case the type is the same as the second array.
3444 * @since 2.1
3445 * @throws IllegalArgumentException if the array types are incompatible
3446 */
3447 public static <T> T[] addAll(T[] array1, T... array2) {
3448 if (array1 == null) {
3449 return clone(array2);
3450 } else if (array2 == null) {
3451 return clone(array1);
3452 }
3453 final Class<?> type1 = array1.getClass().getComponentType();
3454 @SuppressWarnings("unchecked") // OK, because array is of type T
3455 T[] joinedArray = (T[]) Array.newInstance(type1, array1.length + array2.length);
3456 System.arraycopy(array1, 0, joinedArray, 0, array1.length);
3457 try {
3458 System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
3459 } catch (ArrayStoreException ase) {
3460 // Check if problem was due to incompatible types
3461 /*
3462 * We do this here, rather than before the copy because:
3463 * - it would be a wasted check most of the time
3464 * - safer, in case check turns out to be too strict
3465 */
3466 final Class<?> type2 = array2.getClass().getComponentType();
3467 if (!type1.isAssignableFrom(type2)){
3468 throw new IllegalArgumentException("Cannot store "+type2.getName()+" in an array of "
3469 +type1.getName(), ase);
3470 }
3471 throw ase; // No, so rethrow original
3472 }
3473 return joinedArray;
3474 }
3475
3476 /**
3477 * <p>Adds all the elements of the given arrays into a new array.</p>
3478 * <p>The new array contains all of the element of {@code array1} followed
3479 * by all of the elements {@code array2}. When an array is returned, it is always
3480 * a new array.</p>
3481 *
3482 * <pre>
3483 * ArrayUtils.addAll(array1, null) = cloned copy of array1
3484 * ArrayUtils.addAll(null, array2) = cloned copy of array2
3485 * ArrayUtils.addAll([], []) = []
3486 * </pre>
3487 *
3488 * @param array1 the first array whose elements are added to the new array.
3489 * @param array2 the second array whose elements are added to the new array.
3490 * @return The new boolean[] array.
3491 * @since 2.1
3492 */
3493 public static boolean[] addAll(boolean[] array1, boolean... array2) {
3494 if (array1 == null) {
3495 return clone(array2);
3496 } else if (array2 == null) {
3497 return clone(array1);
3498 }
3499 boolean[] joinedArray = new boolean[array1.length + array2.length];
3500 System.arraycopy(array1, 0, joinedArray, 0, array1.length);
3501 System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
3502 return joinedArray;
3503 }
3504
3505 /**
3506 * <p>Adds all the elements of the given arrays into a new array.</p>
3507 * <p>The new array contains all of the element of {@code array1} followed
3508 * by all of the elements {@code array2}. When an array is returned, it is always
3509 * a new array.</p>
3510 *
3511 * <pre>
3512 * ArrayUtils.addAll(array1, null) = cloned copy of array1
3513 * ArrayUtils.addAll(null, array2) = cloned copy of array2
3514 * ArrayUtils.addAll([], []) = []
3515 * </pre>
3516 *
3517 * @param array1 the first array whose elements are added to the new array.
3518 * @param array2 the second array whose elements are added to the new array.
3519 * @return The new char[] array.
3520 * @since 2.1
3521 */
3522 public static char[] addAll(char[] array1, char... array2) {
3523 if (array1 == null) {
3524 return clone(array2);
3525 } else if (array2 == null) {
3526 return clone(array1);
3527 }
3528 char[] joinedArray = new char[array1.length + array2.length];
3529 System.arraycopy(array1, 0, joinedArray, 0, array1.length);
3530 System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
3531 return joinedArray;
3532 }
3533
3534 /**
3535 * <p>Adds all the elements of the given arrays into a new array.</p>
3536 * <p>The new array contains all of the element of {@code array1} followed
3537 * by all of the elements {@code array2}. When an array is returned, it is always
3538 * a new array.</p>
3539 *
3540 * <pre>
3541 * ArrayUtils.addAll(array1, null) = cloned copy of array1
3542 * ArrayUtils.addAll(null, array2) = cloned copy of array2
3543 * ArrayUtils.addAll([], []) = []
3544 * </pre>
3545 *
3546 * @param array1 the first array whose elements are added to the new array.
3547 * @param array2 the second array whose elements are added to the new array.
3548 * @return The new byte[] array.
3549 * @since 2.1
3550 */
3551 public static byte[] addAll(byte[] array1, byte... array2) {
3552 if (array1 == null) {
3553 return clone(array2);
3554 } else if (array2 == null) {
3555 return clone(array1);
3556 }
3557 byte[] joinedArray = new byte[array1.length + array2.length];
3558 System.arraycopy(array1, 0, joinedArray, 0, array1.length);
3559 System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
3560 return joinedArray;
3561 }
3562
3563 /**
3564 * <p>Adds all the elements of the given arrays into a new array.</p>
3565 * <p>The new array contains all of the element of {@code array1} followed
3566 * by all of the elements {@code array2}. When an array is returned, it is always
3567 * a new array.</p>
3568 *
3569 * <pre>
3570 * ArrayUtils.addAll(array1, null) = cloned copy of array1
3571 * ArrayUtils.addAll(null, array2) = cloned copy of array2
3572 * ArrayUtils.addAll([], []) = []
3573 * </pre>
3574 *
3575 * @param array1 the first array whose elements are added to the new array.
3576 * @param array2 the second array whose elements are added to the new array.
3577 * @return The new short[] array.
3578 * @since 2.1
3579 */
3580 public static short[] addAll(short[] array1, short... array2) {
3581 if (array1 == null) {
3582 return clone(array2);
3583 } else if (array2 == null) {
3584 return clone(array1);
3585 }
3586 short[] joinedArray = new short[array1.length + array2.length];
3587 System.arraycopy(array1, 0, joinedArray, 0, array1.length);
3588 System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
3589 return joinedArray;
3590 }
3591
3592 /**
3593 * <p>Adds all the elements of the given arrays into a new array.</p>
3594 * <p>The new array contains all of the element of {@code array1} followed
3595 * by all of the elements {@code array2}. When an array is returned, it is always
3596 * a new array.</p>
3597 *
3598 * <pre>
3599 * ArrayUtils.addAll(array1, null) = cloned copy of array1
3600 * ArrayUtils.addAll(null, array2) = cloned copy of array2
3601 * ArrayUtils.addAll([], []) = []
3602 * </pre>
3603 *
3604 * @param array1 the first array whose elements are added to the new array.
3605 * @param array2 the second array whose elements are added to the new array.
3606 * @return The new int[] array.
3607 * @since 2.1
3608 */
3609 public static int[] addAll(int[] array1, int... array2) {
3610 if (array1 == null) {
3611 return clone(array2);
3612 } else if (array2 == null) {
3613 return clone(array1);
3614 }
3615 int[] joinedArray = new int[array1.length + array2.length];
3616 System.arraycopy(array1, 0, joinedArray, 0, array1.length);
3617 System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
3618 return joinedArray;
3619 }
3620
3621 /**
3622 * <p>Adds all the elements of the given arrays into a new array.</p>
3623 * <p>The new array contains all of the element of {@code array1} followed
3624 * by all of the elements {@code array2}. When an array is returned, it is always
3625 * a new array.</p>
3626 *
3627 * <pre>
3628 * ArrayUtils.addAll(array1, null) = cloned copy of array1
3629 * ArrayUtils.addAll(null, array2) = cloned copy of array2
3630 * ArrayUtils.addAll([], []) = []
3631 * </pre>
3632 *
3633 * @param array1 the first array whose elements are added to the new array.
3634 * @param array2 the second array whose elements are added to the new array.
3635 * @return The new long[] array.
3636 * @since 2.1
3637 */
3638 public static long[] addAll(long[] array1, long... array2) {
3639 if (array1 == null) {
3640 return clone(array2);
3641 } else if (array2 == null) {
3642 return clone(array1);
3643 }
3644 long[] joinedArray = new long[array1.length + array2.length];
3645 System.arraycopy(array1, 0, joinedArray, 0, array1.length);
3646 System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
3647 return joinedArray;
3648 }
3649
3650 /**
3651 * <p>Adds all the elements of the given arrays into a new array.</p>
3652 * <p>The new array contains all of the element of {@code array1} followed
3653 * by all of the elements {@code array2}. When an array is returned, it is always
3654 * a new array.</p>
3655 *
3656 * <pre>
3657 * ArrayUtils.addAll(array1, null) = cloned copy of array1
3658 * ArrayUtils.addAll(null, array2) = cloned copy of array2
3659 * ArrayUtils.addAll([], []) = []
3660 * </pre>
3661 *
3662 * @param array1 the first array whose elements are added to the new array.
3663 * @param array2 the second array whose elements are added to the new array.
3664 * @return The new float[] array.
3665 * @since 2.1
3666 */
3667 public static float[] addAll(float[] array1, float... array2) {
3668 if (array1 == null) {
3669 return clone(array2);
3670 } else if (array2 == null) {
3671 return clone(array1);
3672 }
3673 float[] joinedArray = new float[array1.length + array2.length];
3674 System.arraycopy(array1, 0, joinedArray, 0, array1.length);
3675 System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
3676 return joinedArray;
3677 }
3678
3679 /**
3680 * <p>Adds all the elements of the given arrays into a new array.</p>
3681 * <p>The new array contains all of the element of {@code array1} followed
3682 * by all of the elements {@code array2}. When an array is returned, it is always
3683 * a new array.</p>
3684 *
3685 * <pre>
3686 * ArrayUtils.addAll(array1, null) = cloned copy of array1
3687 * ArrayUtils.addAll(null, array2) = cloned copy of array2
3688 * ArrayUtils.addAll([], []) = []
3689 * </pre>
3690 *
3691 * @param array1 the first array whose elements are added to the new array.
3692 * @param array2 the second array whose elements are added to the new array.
3693 * @return The new double[] array.
3694 * @since 2.1
3695 */
3696 public static double[] addAll(double[] array1, double... array2) {
3697 if (array1 == null) {
3698 return clone(array2);
3699 } else if (array2 == null) {
3700 return clone(array1);
3701 }
3702 double[] joinedArray = new double[array1.length + array2.length];
3703 System.arraycopy(array1, 0, joinedArray, 0, array1.length);
3704 System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
3705 return joinedArray;
3706 }
3707
3708 /**
3709 * <p>Copies the given array and adds the given element at the end of the new array.</p>
3710 *
3711 * <p>The new array contains the same elements of the input
3712 * array plus the given element in the last position. The component type of
3713 * the new array is the same as that of the input array.</p>
3714 *
3715 * <p>If the input array is {@code null}, a new one element array is returned
3716 * whose component type is the same as the element, unless the element itself is null,
3717 * in which case the return type is Object[]</p>
3718 *
3719 * <pre>
3720 * ArrayUtils.add(null, null) = [null]
3721 * ArrayUtils.add(null, "a") = ["a"]
3722 * ArrayUtils.add(["a"], null) = ["a", null]
3723 * ArrayUtils.add(["a"], "b") = ["a", "b"]
3724 * ArrayUtils.add(["a", "b"], "c") = ["a", "b", "c"]
3725 * </pre>
3726 *
3727 * @param <T> the component type of the array
3728 * @param array the array to "add" the element to, may be {@code null}
3729 * @param element the object to add, may be {@code null}
3730 * @return A new array containing the existing elements plus the new element
3731 * The returned array type will be that of the input array (unless null),
3732 * in which case it will have the same type as the element.
3733 * If both are null, an IllegalArgumentException is thrown
3734 * @since 2.1
3735 * @throws IllegalArgumentException if both arguments are null
3736 */
3737 public static <T> T[] add(T[] array, T element) {
3738 Class<?> type;
3739 if (array != null){
3740 type = array.getClass();
3741 } else if (element != null) {
3742 type = element.getClass();
3743 } else {
3744 throw new IllegalArgumentException("Arguments cannot both be null");
3745 }
3746 @SuppressWarnings("unchecked") // type must be T
3747 T[] newArray = (T[]) copyArrayGrow1(array, type);
3748 newArray[newArray.length - 1] = element;
3749 return newArray;
3750 }
3751
3752 /**
3753 * <p>Copies the given array and adds the given element at the end of the new array.</p>
3754 *
3755 * <p>The new array contains the same elements of the input
3756 * array plus the given element in the last position. The component type of
3757 * the new array is the same as that of the input array.</p>
3758 *
3759 * <p>If the input array is {@code null}, a new one element array is returned
3760 * whose component type is the same as the element.</p>
3761 *
3762 * <pre>
3763 * ArrayUtils.add(null, true) = [true]
3764 * ArrayUtils.add([true], false) = [true, false]
3765 * ArrayUtils.add([true, false], true) = [true, false, true]
3766 * </pre>
3767 *
3768 * @param array the array to copy and add the element to, may be {@code null}
3769 * @param element the object to add at the last index of the new array
3770 * @return A new array containing the existing elements plus the new element
3771 * @since 2.1
3772 */
3773 public static boolean[] add(boolean[] array, boolean element) {
3774 boolean[] newArray = (boolean[])copyArrayGrow1(array, Boolean.TYPE);
3775 newArray[newArray.length - 1] = element;
3776 return newArray;
3777 }
3778
3779 /**
3780 * <p>Copies the given array and adds the given element at the end of the new array.</p>
3781 *
3782 * <p>The new array contains the same elements of the input
3783 * array plus the given element in the last position. The component type of
3784 * the new array is the same as that of the input array.</p>
3785 *
3786 * <p>If the input array is {@code null}, a new one element array is returned
3787 * whose component type is the same as the element.</p>
3788 *
3789 * <pre>
3790 * ArrayUtils.add(null, 0) = [0]
3791 * ArrayUtils.add([1], 0) = [1, 0]
3792 * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
3793 * </pre>
3794 *
3795 * @param array the array to copy and add the element to, may be {@code null}
3796 * @param element the object to add at the last index of the new array
3797 * @return A new array containing the existing elements plus the new element
3798 * @since 2.1
3799 */
3800 public static byte[] add(byte[] array, byte element) {
3801 byte[] newArray = (byte[])copyArrayGrow1(array, Byte.TYPE);
3802 newArray[newArray.length - 1] = element;
3803 return newArray;
3804 }
3805
3806 /**
3807 * <p>Copies the given array and adds the given element at the end of the new array.</p>
3808 *
3809 * <p>The new array contains the same elements of the input
3810 * array plus the given element in the last position. The component type of
3811 * the new array is the same as that of the input array.</p>
3812 *
3813 * <p>If the input array is {@code null}, a new one element array is returned
3814 * whose component type is the same as the element.</p>
3815 *
3816 * <pre>
3817 * ArrayUtils.add(null, '0') = ['0']
3818 * ArrayUtils.add(['1'], '0') = ['1', '0']
3819 * ArrayUtils.add(['1', '0'], '1') = ['1', '0', '1']
3820 * </pre>
3821 *
3822 * @param array the array to copy and add the element to, may be {@code null}
3823 * @param element the object to add at the last index of the new array
3824 * @return A new array containing the existing elements plus the new element
3825 * @since 2.1
3826 */
3827 public static char[] add(char[] array, char element) {
3828 char[] newArray = (char[])copyArrayGrow1(array, Character.TYPE);
3829 newArray[newArray.length - 1] = element;
3830 return newArray;
3831 }
3832
3833 /**
3834 * <p>Copies the given array and adds the given element at the end of the new array.</p>
3835 *
3836 * <p>The new array contains the same elements of the input
3837 * array plus the given element in the last position. The component type of
3838 * the new array is the same as that of the input array.</p>
3839 *
3840 * <p>If the input array is {@code null}, a new one element array is returned
3841 * whose component type is the same as the element.</p>
3842 *
3843 * <pre>
3844 * ArrayUtils.add(null, 0) = [0]
3845 * ArrayUtils.add([1], 0) = [1, 0]
3846 * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
3847 * </pre>
3848 *
3849 * @param array the array to copy and add the element to, may be {@code null}
3850 * @param element the object to add at the last index of the new array
3851 * @return A new array containing the existing elements plus the new element
3852 * @since 2.1
3853 */
3854 public static double[] add(double[] array, double element) {
3855 double[] newArray = (double[])copyArrayGrow1(array, Double.TYPE);
3856 newArray[newArray.length - 1] = element;
3857 return newArray;
3858 }
3859
3860 /**
3861 * <p>Copies the given array and adds the given element at the end of the new array.</p>
3862 *
3863 * <p>The new array contains the same elements of the input
3864 * array plus the given element in the last position. The component type of
3865 * the new array is the same as that of the input array.</p>
3866 *
3867 * <p>If the input array is {@code null}, a new one element array is returned
3868 * whose component type is the same as the element.</p>
3869 *
3870 * <pre>
3871 * ArrayUtils.add(null, 0) = [0]
3872 * ArrayUtils.add([1], 0) = [1, 0]
3873 * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
3874 * </pre>
3875 *
3876 * @param array the array to copy and add the element to, may be {@code null}
3877 * @param element the object to add at the last index of the new array
3878 * @return A new array containing the existing elements plus the new element
3879 * @since 2.1
3880 */
3881 public static float[] add(float[] array, float element) {
3882 float[] newArray = (float[])copyArrayGrow1(array, Float.TYPE);
3883 newArray[newArray.length - 1] = element;
3884 return newArray;
3885 }
3886
3887 /**
3888 * <p>Copies the given array and adds the given element at the end of the new array.</p>
3889 *
3890 * <p>The new array contains the same elements of the input
3891 * array plus the given element in the last position. The component type of
3892 * the new array is the same as that of the input array.</p>
3893 *
3894 * <p>If the input array is {@code null}, a new one element array is returned
3895 * whose component type is the same as the element.</p>
3896 *
3897 * <pre>
3898 * ArrayUtils.add(null, 0) = [0]
3899 * ArrayUtils.add([1], 0) = [1, 0]
3900 * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
3901 * </pre>
3902 *
3903 * @param array the array to copy and add the element to, may be {@code null}
3904 * @param element the object to add at the last index of the new array
3905 * @return A new array containing the existing elements plus the new element
3906 * @since 2.1
3907 */
3908 public static int[] add(int[] array, int element) {
3909 int[] newArray = (int[])copyArrayGrow1(array, Integer.TYPE);
3910 newArray[newArray.length - 1] = element;
3911 return newArray;
3912 }
3913
3914 /**
3915 * <p>Copies the given array and adds the given element at the end of the new array.</p>
3916 *
3917 * <p>The new array contains the same elements of the input
3918 * array plus the given element in the last position. The component type of
3919 * the new array is the same as that of the input array.</p>
3920 *
3921 * <p>If the input array is {@code null}, a new one element array is returned
3922 * whose component type is the same as the element.</p>
3923 *
3924 * <pre>
3925 * ArrayUtils.add(null, 0) = [0]
3926 * ArrayUtils.add([1], 0) = [1, 0]
3927 * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
3928 * </pre>
3929 *
3930 * @param array the array to copy and add the element to, may be {@code null}
3931 * @param element the object to add at the last index of the new array
3932 * @return A new array containing the existing elements plus the new element
3933 * @since 2.1
3934 */
3935 public static long[] add(long[] array, long element) {
3936 long[] newArray = (long[])copyArrayGrow1(array, Long.TYPE);
3937 newArray[newArray.length - 1] = element;
3938 return newArray;
3939 }
3940
3941 /**
3942 * <p>Copies the given array and adds the given element at the end of the new array.</p>
3943 *
3944 * <p>The new array contains the same elements of the input
3945 * array plus the given element in the last position. The component type of
3946 * the new array is the same as that of the input array.</p>
3947 *
3948 * <p>If the input array is {@code null}, a new one element array is returned
3949 * whose component type is the same as the element.</p>
3950 *
3951 * <pre>
3952 * ArrayUtils.add(null, 0) = [0]
3953 * ArrayUtils.add([1], 0) = [1, 0]
3954 * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
3955 * </pre>
3956 *
3957 * @param array the array to copy and add the element to, may be {@code null}
3958 * @param element the object to add at the last index of the new array
3959 * @return A new array containing the existing elements plus the new element
3960 * @since 2.1
3961 */
3962 public static short[] add(short[] array, short element) {
3963 short[] newArray = (short[])copyArrayGrow1(array, Short.TYPE);
3964 newArray[newArray.length - 1] = element;
3965 return newArray;
3966 }
3967
3968 /**
3969 * Returns a copy of the given array of size 1 greater than the argument.
3970 * The last value of the array is left to the default value.
3971 *
3972 * @param array The array to copy, must not be {@code null}.
3973 * @param newArrayComponentType If {@code array} is {@code null}, create a
3974 * size 1 array of this type.
3975 * @return A new copy of the array of size 1 greater than the input.
3976 */
3977 private static Object copyArrayGrow1(Object array, Class<?> newArrayComponentType) {
3978 if (array != null) {
3979 int arrayLength = Array.getLength(array);
3980 Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);
3981 System.arraycopy(array, 0, newArray, 0, arrayLength);
3982 return newArray;
3983 }
3984 return Array.newInstance(newArrayComponentType, 1);
3985 }
3986
3987 /**
3988 * <p>Inserts the specified element at the specified position in the array.
3989 * Shifts the element currently at that position (if any) and any subsequent
3990 * elements to the right (adds one to their indices).</p>
3991 *
3992 * <p>This method returns a new array with the same elements of the input
3993 * array plus the given element on the specified position. The component
3994 * type of the returned array is always the same as that of the input
3995 * array.</p>
3996 *
3997 * <p>If the input array is {@code null}, a new one element array is returned
3998 * whose component type is the same as the element.</p>
3999 *
4000 * <pre>
4001 * ArrayUtils.add(null, 0, null) = [null]
4002 * ArrayUtils.add(null, 0, "a") = ["a"]
4003 * ArrayUtils.add(["a"], 1, null) = ["a", null]
4004 * ArrayUtils.add(["a"], 1, "b") = ["a", "b"]
4005 * ArrayUtils.add(["a", "b"], 3, "c") = ["a", "b", "c"]
4006 * </pre>
4007 *
4008 * @param <T> the component type of the array
4009 * @param array the array to add the element to, may be {@code null}
4010 * @param index the position of the new object
4011 * @param element the object to add
4012 * @return A new array containing the existing elements and the new element
4013 * @throws IndexOutOfBoundsException if the index is out of range
4014 * (index < 0 || index > array.length).
4015 * @throws IllegalArgumentException if both array and element are null
4016 */
4017 public static <T> T[] add(T[] array, int index, T element) {
4018 Class<?> clss = null;
4019 if (array != null) {
4020 clss = array.getClass().getComponentType();
4021 } else if (element != null) {
4022 clss = element.getClass();
4023 } else {
4024 throw new IllegalArgumentException("Array and element cannot both be null");
4025 }
4026 @SuppressWarnings("unchecked") // the add method creates an array of type clss, which is type T
4027 final T[] newArray = (T[]) add(array, index, element, clss);
4028 return newArray;
4029 }
4030
4031 /**
4032 * <p>Inserts the specified element at the specified position in the array.
4033 * Shifts the element currently at that position (if any) and any subsequent
4034 * elements to the right (adds one to their indices).</p>
4035 *
4036 * <p>This method returns a new array with the same elements of the input
4037 * array plus the given element on the specified position. The component
4038 * type of the returned array is always the same as that of the input
4039 * array.</p>
4040 *
4041 * <p>If the input array is {@code null}, a new one element array is returned
4042 * whose component type is the same as the element.</p>
4043 *
4044 * <pre>
4045 * ArrayUtils.add(null, 0, true) = [true]
4046 * ArrayUtils.add([true], 0, false) = [false, true]
4047 * ArrayUtils.add([false], 1, true) = [false, true]
4048 * ArrayUtils.add([true, false], 1, true) = [true, true, false]
4049 * </pre>
4050 *
4051 * @param array the array to add the element to, may be {@code null}
4052 * @param index the position of the new object
4053 * @param element the object to add
4054 * @return A new array containing the existing elements and the new element
4055 * @throws IndexOutOfBoundsException if the index is out of range
4056 * (index < 0 || index > array.length).
4057 */
4058 public static boolean[] add(boolean[] array, int index, boolean element) {
4059 return (boolean[]) add(array, index, Boolean.valueOf(element), Boolean.TYPE);
4060 }
4061
4062 /**
4063 * <p>Inserts the specified element at the specified position in the array.
4064 * Shifts the element currently at that position (if any) and any subsequent
4065 * elements to the right (adds one to their indices).</p>
4066 *
4067 * <p>This method returns a new array with the same elements of the input
4068 * array plus the given element on the specified position. The component
4069 * type of the returned array is always the same as that of the input
4070 * array.</p>
4071 *
4072 * <p>If the input array is {@code null}, a new one element array is returned
4073 * whose component type is the same as the element.</p>
4074 *
4075 * <pre>
4076 * ArrayUtils.add(null, 0, 'a') = ['a']
4077 * ArrayUtils.add(['a'], 0, 'b') = ['b', 'a']
4078 * ArrayUtils.add(['a', 'b'], 0, 'c') = ['c', 'a', 'b']
4079 * ArrayUtils.add(['a', 'b'], 1, 'k') = ['a', 'k', 'b']
4080 * ArrayUtils.add(['a', 'b', 'c'], 1, 't') = ['a', 't', 'b', 'c']
4081 * </pre>
4082 *
4083 * @param array the array to add the element to, may be {@code null}
4084 * @param index the position of the new object
4085 * @param element the object to add
4086 * @return A new array containing the existing elements and the new element
4087 * @throws IndexOutOfBoundsException if the index is out of range
4088 * (index < 0 || index > array.length).
4089 */
4090 public static char[] add(char[] array, int index, char element) {
4091 return (char[]) add(array, index, Character.valueOf(element), Character.TYPE);
4092 }
4093
4094 /**
4095 * <p>Inserts the specified element at the specified position in the array.
4096 * Shifts the element currently at that position (if any) and any subsequent
4097 * elements to the right (adds one to their indices).</p>
4098 *
4099 * <p>This method returns a new array with the same elements of the input
4100 * array plus the given element on the specified position. The component
4101 * type of the returned array is always the same as that of the input
4102 * array.</p>
4103 *
4104 * <p>If the input array is {@code null}, a new one element array is returned
4105 * whose component type is the same as the element.</p>
4106 *
4107 * <pre>
4108 * ArrayUtils.add([1], 0, 2) = [2, 1]
4109 * ArrayUtils.add([2, 6], 2, 3) = [2, 6, 3]
4110 * ArrayUtils.add([2, 6], 0, 1) = [1, 2, 6]
4111 * ArrayUtils.add([2, 6, 3], 2, 1) = [2, 6, 1, 3]
4112 * </pre>
4113 *
4114 * @param array the array to add the element to, may be {@code null}
4115 * @param index the position of the new object
4116 * @param element the object to add
4117 * @return A new array containing the existing elements and the new element
4118 * @throws IndexOutOfBoundsException if the index is out of range
4119 * (index < 0 || index > array.length).
4120 */
4121 public static byte[] add(byte[] array, int index, byte element) {
4122 return (byte[]) add(array, index, Byte.valueOf(element), Byte.TYPE);
4123 }
4124
4125 /**
4126 * <p>Inserts the specified element at the specified position in the array.
4127 * Shifts the element currently at that position (if any) and any subsequent
4128 * elements to the right (adds one to their indices).</p>
4129 *
4130 * <p>This method returns a new array with the same elements of the input
4131 * array plus the given element on the specified position. The component
4132 * type of the returned array is always the same as that of the input
4133 * array.</p>
4134 *
4135 * <p>If the input array is {@code null}, a new one element array is returned
4136 * whose component type is the same as the element.</p>
4137 *
4138 * <pre>
4139 * ArrayUtils.add([1], 0, 2) = [2, 1]
4140 * ArrayUtils.add([2, 6], 2, 10) = [2, 6, 10]
4141 * ArrayUtils.add([2, 6], 0, -4) = [-4, 2, 6]
4142 * ArrayUtils.add([2, 6, 3], 2, 1) = [2, 6, 1, 3]
4143 * </pre>
4144 *
4145 * @param array the array to add the element to, may be {@code null}
4146 * @param index the position of the new object
4147 * @param element the object to add
4148 * @return A new array containing the existing elements and the new element
4149 * @throws IndexOutOfBoundsException if the index is out of range
4150 * (index < 0 || index > array.length).
4151 */
4152 public static short[] add(short[] array, int index, short element) {
4153 return (short[]) add(array, index, Short.valueOf(element), Short.TYPE);
4154 }
4155
4156 /**
4157 * <p>Inserts the specified element at the specified position in the array.
4158 * Shifts the element currently at that position (if any) and any subsequent
4159 * elements to the right (adds one to their indices).</p>
4160 *
4161 * <p>This method returns a new array with the same elements of the input
4162 * array plus the given element on the specified position. The component
4163 * type of the returned array is always the same as that of the input
4164 * array.</p>
4165 *
4166 * <p>If the input array is {@code null}, a new one element array is returned
4167 * whose component type is the same as the element.</p>
4168 *
4169 * <pre>
4170 * ArrayUtils.add([1], 0, 2) = [2, 1]
4171 * ArrayUtils.add([2, 6], 2, 10) = [2, 6, 10]
4172 * ArrayUtils.add([2, 6], 0, -4) = [-4, 2, 6]
4173 * ArrayUtils.add([2, 6, 3], 2, 1) = [2, 6, 1, 3]
4174 * </pre>
4175 *
4176 * @param array the array to add the element to, may be {@code null}
4177 * @param index the position of the new object
4178 * @param element the object to add
4179 * @return A new array containing the existing elements and the new element
4180 * @throws IndexOutOfBoundsException if the index is out of range
4181 * (index < 0 || index > array.length).
4182 */
4183 public static int[] add(int[] array, int index, int element) {
4184 return (int[]) add(array, index, Integer.valueOf(element), Integer.TYPE);
4185 }
4186
4187 /**
4188 * <p>Inserts the specified element at the specified position in the array.
4189 * Shifts the element currently at that position (if any) and any subsequent
4190 * elements to the right (adds one to their indices).</p>
4191 *
4192 * <p>This method returns a new array with the same elements of the input
4193 * array plus the given element on the specified position. The component
4194 * type of the returned array is always the same as that of the input
4195 * array.</p>
4196 *
4197 * <p>If the input array is {@code null}, a new one element array is returned
4198 * whose component type is the same as the element.</p>
4199 *
4200 * <pre>
4201 * ArrayUtils.add([1L], 0, 2L) = [2L, 1L]
4202 * ArrayUtils.add([2L, 6L], 2, 10L) = [2L, 6L, 10L]
4203 * ArrayUtils.add([2L, 6L], 0, -4L) = [-4L, 2L, 6L]
4204 * ArrayUtils.add([2L, 6L, 3L], 2, 1L) = [2L, 6L, 1L, 3L]
4205 * </pre>
4206 *
4207 * @param array the array to add the element to, may be {@code null}
4208 * @param index the position of the new object
4209 * @param element the object to add
4210 * @return A new array containing the existing elements and the new element
4211 * @throws IndexOutOfBoundsException if the index is out of range
4212 * (index < 0 || index > array.length).
4213 */
4214 public static long[] add(long[] array, int index, long element) {
4215 return (long[]) add(array, index, Long.valueOf(element), Long.TYPE);
4216 }
4217
4218 /**
4219 * <p>Inserts the specified element at the specified position in the array.
4220 * Shifts the element currently at that position (if any) and any subsequent
4221 * elements to the right (adds one to their indices).</p>
4222 *
4223 * <p>This method returns a new array with the same elements of the input
4224 * array plus the given element on the specified position. The component
4225 * type of the returned array is always the same as that of the input
4226 * array.</p>
4227 *
4228 * <p>If the input array is {@code null}, a new one element array is returned
4229 * whose component type is the same as the element.</p>
4230 *
4231 * <pre>
4232 * ArrayUtils.add([1.1f], 0, 2.2f) = [2.2f, 1.1f]
4233 * ArrayUtils.add([2.3f, 6.4f], 2, 10.5f) = [2.3f, 6.4f, 10.5f]
4234 * ArrayUtils.add([2.6f, 6.7f], 0, -4.8f) = [-4.8f, 2.6f, 6.7f]
4235 * ArrayUtils.add([2.9f, 6.0f, 0.3f], 2, 1.0f) = [2.9f, 6.0f, 1.0f, 0.3f]
4236 * </pre>
4237 *
4238 * @param array the array to add the element to, may be {@code null}
4239 * @param index the position of the new object
4240 * @param element the object to add
4241 * @return A new array containing the existing elements and the new element
4242 * @throws IndexOutOfBoundsException if the index is out of range
4243 * (index < 0 || index > array.length).
4244 */
4245 public static float[] add(float[] array, int index, float element) {
4246 return (float[]) add(array, index, Float.valueOf(element), Float.TYPE);
4247 }
4248
4249 /**
4250 * <p>Inserts the specified element at the specified position in the array.
4251 * Shifts the element currently at that position (if any) and any subsequent
4252 * elements to the right (adds one to their indices).</p>
4253 *
4254 * <p>This method returns a new array with the same elements of the input
4255 * array plus the given element on the specified position. The component
4256 * type of the returned array is always the same as that of the input
4257 * array.</p>
4258 *
4259 * <p>If the input array is {@code null}, a new one element array is returned
4260 * whose component type is the same as the element.</p>
4261 *
4262 * <pre>
4263 * ArrayUtils.add([1.1], 0, 2.2) = [2.2, 1.1]
4264 * ArrayUtils.add([2.3, 6.4], 2, 10.5) = [2.3, 6.4, 10.5]
4265 * ArrayUtils.add([2.6, 6.7], 0, -4.8) = [-4.8, 2.6, 6.7]
4266 * ArrayUtils.add([2.9, 6.0, 0.3], 2, 1.0) = [2.9, 6.0, 1.0, 0.3]
4267 * </pre>
4268 *
4269 * @param array the array to add the element to, may be {@code null}
4270 * @param index the position of the new object
4271 * @param element the object to add
4272 * @return A new array containing the existing elements and the new element
4273 * @throws IndexOutOfBoundsException if the index is out of range
4274 * (index < 0 || index > array.length).
4275 */
4276 public static double[] add(double[] array, int index, double element) {
4277 return (double[]) add(array, index, Double.valueOf(element), Double.TYPE);
4278 }
4279
4280 /**
4281 * Underlying implementation of add(array, index, element) methods.
4282 * The last parameter is the class, which may not equal element.getClass
4283 * for primitives.
4284 *
4285 * @param array the array to add the element to, may be {@code null}
4286 * @param index the position of the new object
4287 * @param element the object to add
4288 * @param clss the type of the element being added
4289 * @return A new array containing the existing elements and the new element
4290 */
4291 private static Object add(Object array, int index, Object element, Class<?> clss) {
4292 if (array == null) {
4293 if (index != 0) {
4294 throw new IndexOutOfBoundsException("Index: " + index + ", Length: 0");
4295 }
4296 Object joinedArray = Array.newInstance(clss, 1);
4297 Array.set(joinedArray, 0, element);
4298 return joinedArray;
4299 }
4300 int length = Array.getLength(array);
4301 if (index > length || index < 0) {
4302 throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
4303 }
4304 Object result = Array.newInstance(clss, length + 1);
4305 System.arraycopy(array, 0, result, 0, index);
4306 Array.set(result, index, element);
4307 if (index < length) {
4308 System.arraycopy(array, index, result, index + 1, length - index);
4309 }
4310 return result;
4311 }
4312
4313 /**
4314 * <p>Removes the element at the specified position from the specified array.
4315 * All subsequent elements are shifted to the left (subtracts one from
4316 * their indices).</p>
4317 *
4318 * <p>This method returns a new array with the same elements of the input
4319 * array except the element on the specified position. The component
4320 * type of the returned array is always the same as that of the input
4321 * array.</p>
4322 *
4323 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4324 * will be thrown, because in that case no valid index can be specified.</p>
4325 *
4326 * <pre>
4327 * ArrayUtils.remove(["a"], 0) = []
4328 * ArrayUtils.remove(["a", "b"], 0) = ["b"]
4329 * ArrayUtils.remove(["a", "b"], 1) = ["a"]
4330 * ArrayUtils.remove(["a", "b", "c"], 1) = ["a", "c"]
4331 * </pre>
4332 *
4333 * @param <T> the component type of the array
4334 * @param array the array to remove the element from, may not be {@code null}
4335 * @param index the position of the element to be removed
4336 * @return A new array containing the existing elements except the element
4337 * at the specified position.
4338 * @throws IndexOutOfBoundsException if the index is out of range
4339 * (index < 0 || index >= array.length), or if the array is {@code null}.
4340 * @since 2.1
4341 */
4342 @SuppressWarnings("unchecked") // remove() always creates an array of the same type as its input
4343 public static <T> T[] remove(T[] array, int index) {
4344 return (T[]) remove((Object) array, index);
4345 }
4346
4347 /**
4348 * <p>Removes the first occurrence of the specified element from the
4349 * specified array. All subsequent elements are shifted to the left
4350 * (subtracts one from their indices). If the array doesn't contains
4351 * such an element, no elements are removed from the array.</p>
4352 *
4353 * <p>This method returns a new array with the same elements of the input
4354 * array except the first occurrence of the specified element. The component
4355 * type of the returned array is always the same as that of the input
4356 * array.</p>
4357 *
4358 * <pre>
4359 * ArrayUtils.removeElement(null, "a") = null
4360 * ArrayUtils.removeElement([], "a") = []
4361 * ArrayUtils.removeElement(["a"], "b") = ["a"]
4362 * ArrayUtils.removeElement(["a", "b"], "a") = ["b"]
4363 * ArrayUtils.removeElement(["a", "b", "a"], "a") = ["b", "a"]
4364 * </pre>
4365 *
4366 * @param <T> the component type of the array
4367 * @param array the array to remove the element from, may be {@code null}
4368 * @param element the element to be removed
4369 * @return A new array containing the existing elements except the first
4370 * occurrence of the specified element.
4371 * @since 2.1
4372 */
4373 public static <T> T[] removeElement(T[] array, Object element) {
4374 int index = indexOf(array, element);
4375 if (index == INDEX_NOT_FOUND) {
4376 return clone(array);
4377 }
4378 return remove(array, index);
4379 }
4380
4381 /**
4382 * <p>Removes the element at the specified position from the specified array.
4383 * All subsequent elements are shifted to the left (subtracts one from
4384 * their indices).</p>
4385 *
4386 * <p>This method returns a new array with the same elements of the input
4387 * array except the element on the specified position. The component
4388 * type of the returned array is always the same as that of the input
4389 * array.</p>
4390 *
4391 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4392 * will be thrown, because in that case no valid index can be specified.</p>
4393 *
4394 * <pre>
4395 * ArrayUtils.remove([true], 0) = []
4396 * ArrayUtils.remove([true, false], 0) = [false]
4397 * ArrayUtils.remove([true, false], 1) = [true]
4398 * ArrayUtils.remove([true, true, false], 1) = [true, false]
4399 * </pre>
4400 *
4401 * @param array the array to remove the element from, may not be {@code null}
4402 * @param index the position of the element to be removed
4403 * @return A new array containing the existing elements except the element
4404 * at the specified position.
4405 * @throws IndexOutOfBoundsException if the index is out of range
4406 * (index < 0 || index >= array.length), or if the array is {@code null}.
4407 * @since 2.1
4408 */
4409 public static boolean[] remove(boolean[] array, int index) {
4410 return (boolean[]) remove((Object) array, index);
4411 }
4412
4413 /**
4414 * <p>Removes the first occurrence of the specified element from the
4415 * specified array. All subsequent elements are shifted to the left
4416 * (subtracts one from their indices). If the array doesn't contains
4417 * such an element, no elements are removed from the array.</p>
4418 *
4419 * <p>This method returns a new array with the same elements of the input
4420 * array except the first occurrence of the specified element. The component
4421 * type of the returned array is always the same as that of the input
4422 * array.</p>
4423 *
4424 * <pre>
4425 * ArrayUtils.removeElement(null, true) = null
4426 * ArrayUtils.removeElement([], true) = []
4427 * ArrayUtils.removeElement([true], false) = [true]
4428 * ArrayUtils.removeElement([true, false], false) = [true]
4429 * ArrayUtils.removeElement([true, false, true], true) = [false, true]
4430 * </pre>
4431 *
4432 * @param array the array to remove the element from, may be {@code null}
4433 * @param element the element to be removed
4434 * @return A new array containing the existing elements except the first
4435 * occurrence of the specified element.
4436 * @since 2.1
4437 */
4438 public static boolean[] removeElement(boolean[] array, boolean element) {
4439 int index = indexOf(array, element);
4440 if (index == INDEX_NOT_FOUND) {
4441 return clone(array);
4442 }
4443 return remove(array, index);
4444 }
4445
4446 /**
4447 * <p>Removes the element at the specified position from the specified array.
4448 * All subsequent elements are shifted to the left (subtracts one from
4449 * their indices).</p>
4450 *
4451 * <p>This method returns a new array with the same elements of the input
4452 * array except the element on the specified position. The component
4453 * type of the returned array is always the same as that of the input
4454 * array.</p>
4455 *
4456 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4457 * will be thrown, because in that case no valid index can be specified.</p>
4458 *
4459 * <pre>
4460 * ArrayUtils.remove([1], 0) = []
4461 * ArrayUtils.remove([1, 0], 0) = [0]
4462 * ArrayUtils.remove([1, 0], 1) = [1]
4463 * ArrayUtils.remove([1, 0, 1], 1) = [1, 1]
4464 * </pre>
4465 *
4466 * @param array the array to remove the element from, may not be {@code null}
4467 * @param index the position of the element to be removed
4468 * @return A new array containing the existing elements except the element
4469 * at the specified position.
4470 * @throws IndexOutOfBoundsException if the index is out of range
4471 * (index < 0 || index >= array.length), or if the array is {@code null}.
4472 * @since 2.1
4473 */
4474 public static byte[] remove(byte[] array, int index) {
4475 return (byte[]) remove((Object) array, index);
4476 }
4477
4478 /**
4479 * <p>Removes the first occurrence of the specified element from the
4480 * specified array. All subsequent elements are shifted to the left
4481 * (subtracts one from their indices). If the array doesn't contains
4482 * such an element, no elements are removed from the array.</p>
4483 *
4484 * <p>This method returns a new array with the same elements of the input
4485 * array except the first occurrence of the specified element. The component
4486 * type of the returned array is always the same as that of the input
4487 * array.</p>
4488 *
4489 * <pre>
4490 * ArrayUtils.removeElement(null, 1) = null
4491 * ArrayUtils.removeElement([], 1) = []
4492 * ArrayUtils.removeElement([1], 0) = [1]
4493 * ArrayUtils.removeElement([1, 0], 0) = [1]
4494 * ArrayUtils.removeElement([1, 0, 1], 1) = [0, 1]
4495 * </pre>
4496 *
4497 * @param array the array to remove the element from, may be {@code null}
4498 * @param element the element to be removed
4499 * @return A new array containing the existing elements except the first
4500 * occurrence of the specified element.
4501 * @since 2.1
4502 */
4503 public static byte[] removeElement(byte[] array, byte element) {
4504 int index = indexOf(array, element);
4505 if (index == INDEX_NOT_FOUND) {
4506 return clone(array);
4507 }
4508 return remove(array, index);
4509 }
4510
4511 /**
4512 * <p>Removes the element at the specified position from the specified array.
4513 * All subsequent elements are shifted to the left (subtracts one from
4514 * their indices).</p>
4515 *
4516 * <p>This method returns a new array with the same elements of the input
4517 * array except the element on the specified position. The component
4518 * type of the returned array is always the same as that of the input
4519 * array.</p>
4520 *
4521 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4522 * will be thrown, because in that case no valid index can be specified.</p>
4523 *
4524 * <pre>
4525 * ArrayUtils.remove(['a'], 0) = []
4526 * ArrayUtils.remove(['a', 'b'], 0) = ['b']
4527 * ArrayUtils.remove(['a', 'b'], 1) = ['a']
4528 * ArrayUtils.remove(['a', 'b', 'c'], 1) = ['a', 'c']
4529 * </pre>
4530 *
4531 * @param array the array to remove the element from, may not be {@code null}
4532 * @param index the position of the element to be removed
4533 * @return A new array containing the existing elements except the element
4534 * at the specified position.
4535 * @throws IndexOutOfBoundsException if the index is out of range
4536 * (index < 0 || index >= array.length), or if the array is {@code null}.
4537 * @since 2.1
4538 */
4539 public static char[] remove(char[] array, int index) {
4540 return (char[]) remove((Object) array, index);
4541 }
4542
4543 /**
4544 * <p>Removes the first occurrence of the specified element from the
4545 * specified array. All subsequent elements are shifted to the left
4546 * (subtracts one from their indices). If the array doesn't contains
4547 * such an element, no elements are removed from the array.</p>
4548 *
4549 * <p>This method returns a new array with the same elements of the input
4550 * array except the first occurrence of the specified element. The component
4551 * type of the returned array is always the same as that of the input
4552 * array.</p>
4553 *
4554 * <pre>
4555 * ArrayUtils.removeElement(null, 'a') = null
4556 * ArrayUtils.removeElement([], 'a') = []
4557 * ArrayUtils.removeElement(['a'], 'b') = ['a']
4558 * ArrayUtils.removeElement(['a', 'b'], 'a') = ['b']
4559 * ArrayUtils.removeElement(['a', 'b', 'a'], 'a') = ['b', 'a']
4560 * </pre>
4561 *
4562 * @param array the array to remove the element from, may be {@code null}
4563 * @param element the element to be removed
4564 * @return A new array containing the existing elements except the first
4565 * occurrence of the specified element.
4566 * @since 2.1
4567 */
4568 public static char[] removeElement(char[] array, char element) {
4569 int index = indexOf(array, element);
4570 if (index == INDEX_NOT_FOUND) {
4571 return clone(array);
4572 }
4573 return remove(array, index);
4574 }
4575
4576 /**
4577 * <p>Removes the element at the specified position from the specified array.
4578 * All subsequent elements are shifted to the left (subtracts one from
4579 * their indices).</p>
4580 *
4581 * <p>This method returns a new array with the same elements of the input
4582 * array except the element on the specified position. The component
4583 * type of the returned array is always the same as that of the input
4584 * array.</p>
4585 *
4586 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4587 * will be thrown, because in that case no valid index can be specified.</p>
4588 *
4589 * <pre>
4590 * ArrayUtils.remove([1.1], 0) = []
4591 * ArrayUtils.remove([2.5, 6.0], 0) = [6.0]
4592 * ArrayUtils.remove([2.5, 6.0], 1) = [2.5]
4593 * ArrayUtils.remove([2.5, 6.0, 3.8], 1) = [2.5, 3.8]
4594 * </pre>
4595 *
4596 * @param array the array to remove the element from, may not be {@code null}
4597 * @param index the position of the element to be removed
4598 * @return A new array containing the existing elements except the element
4599 * at the specified position.
4600 * @throws IndexOutOfBoundsException if the index is out of range
4601 * (index < 0 || index >= array.length), or if the array is {@code null}.
4602 * @since 2.1
4603 */
4604 public static double[] remove(double[] array, int index) {
4605 return (double[]) remove((Object) array, index);
4606 }
4607
4608 /**
4609 * <p>Removes the first occurrence of the specified element from the
4610 * specified array. All subsequent elements are shifted to the left
4611 * (subtracts one from their indices). If the array doesn't contains
4612 * such an element, no elements are removed from the array.</p>
4613 *
4614 * <p>This method returns a new array with the same elements of the input
4615 * array except the first occurrence of the specified element. The component
4616 * type of the returned array is always the same as that of the input
4617 * array.</p>
4618 *
4619 * <pre>
4620 * ArrayUtils.removeElement(null, 1.1) = null
4621 * ArrayUtils.removeElement([], 1.1) = []
4622 * ArrayUtils.removeElement([1.1], 1.2) = [1.1]
4623 * ArrayUtils.removeElement([1.1, 2.3], 1.1) = [2.3]
4624 * ArrayUtils.removeElement([1.1, 2.3, 1.1], 1.1) = [2.3, 1.1]
4625 * </pre>
4626 *
4627 * @param array the array to remove the element from, may be {@code null}
4628 * @param element the element to be removed
4629 * @return A new array containing the existing elements except the first
4630 * occurrence of the specified element.
4631 * @since 2.1
4632 */
4633 public static double[] removeElement(double[] array, double element) {
4634 int index = indexOf(array, element);
4635 if (index == INDEX_NOT_FOUND) {
4636 return clone(array);
4637 }
4638 return remove(array, index);
4639 }
4640
4641 /**
4642 * <p>Removes the element at the specified position from the specified array.
4643 * All subsequent elements are shifted to the left (subtracts one from
4644 * their indices).</p>
4645 *
4646 * <p>This method returns a new array with the same elements of the input
4647 * array except the element on the specified position. The component
4648 * type of the returned array is always the same as that of the input
4649 * array.</p>
4650 *
4651 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4652 * will be thrown, because in that case no valid index can be specified.</p>
4653 *
4654 * <pre>
4655 * ArrayUtils.remove([1.1], 0) = []
4656 * ArrayUtils.remove([2.5, 6.0], 0) = [6.0]
4657 * ArrayUtils.remove([2.5, 6.0], 1) = [2.5]
4658 * ArrayUtils.remove([2.5, 6.0, 3.8], 1) = [2.5, 3.8]
4659 * </pre>
4660 *
4661 * @param array the array to remove the element from, may not be {@code null}
4662 * @param index the position of the element to be removed
4663 * @return A new array containing the existing elements except the element
4664 * at the specified position.
4665 * @throws IndexOutOfBoundsException if the index is out of range
4666 * (index < 0 || index >= array.length), or if the array is {@code null}.
4667 * @since 2.1
4668 */
4669 public static float[] remove(float[] array, int index) {
4670 return (float[]) remove((Object) array, index);
4671 }
4672
4673 /**
4674 * <p>Removes the first occurrence of the specified element from the
4675 * specified array. All subsequent elements are shifted to the left
4676 * (subtracts one from their indices). If the array doesn't contains
4677 * such an element, no elements are removed from the array.</p>
4678 *
4679 * <p>This method returns a new array with the same elements of the input
4680 * array except the first occurrence of the specified element. The component
4681 * type of the returned array is always the same as that of the input
4682 * array.</p>
4683 *
4684 * <pre>
4685 * ArrayUtils.removeElement(null, 1.1) = null
4686 * ArrayUtils.removeElement([], 1.1) = []
4687 * ArrayUtils.removeElement([1.1], 1.2) = [1.1]
4688 * ArrayUtils.removeElement([1.1, 2.3], 1.1) = [2.3]
4689 * ArrayUtils.removeElement([1.1, 2.3, 1.1], 1.1) = [2.3, 1.1]
4690 * </pre>
4691 *
4692 * @param array the array to remove the element from, may be {@code null}
4693 * @param element the element to be removed
4694 * @return A new array containing the existing elements except the first
4695 * occurrence of the specified element.
4696 * @since 2.1
4697 */
4698 public static float[] removeElement(float[] array, float element) {
4699 int index = indexOf(array, element);
4700 if (index == INDEX_NOT_FOUND) {
4701 return clone(array);
4702 }
4703 return remove(array, index);
4704 }
4705
4706 /**
4707 * <p>Removes the element at the specified position from the specified array.
4708 * All subsequent elements are shifted to the left (subtracts one from
4709 * their indices).</p>
4710 *
4711 * <p>This method returns a new array with the same elements of the input
4712 * array except the element on the specified position. The component
4713 * type of the returned array is always the same as that of the input
4714 * array.</p>
4715 *
4716 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4717 * will be thrown, because in that case no valid index can be specified.</p>
4718 *
4719 * <pre>
4720 * ArrayUtils.remove([1], 0) = []
4721 * ArrayUtils.remove([2, 6], 0) = [6]
4722 * ArrayUtils.remove([2, 6], 1) = [2]
4723 * ArrayUtils.remove([2, 6, 3], 1) = [2, 3]
4724 * </pre>
4725 *
4726 * @param array the array to remove the element from, may not be {@code null}
4727 * @param index the position of the element to be removed
4728 * @return A new array containing the existing elements except the element
4729 * at the specified position.
4730 * @throws IndexOutOfBoundsException if the index is out of range
4731 * (index < 0 || index >= array.length), or if the array is {@code null}.
4732 * @since 2.1
4733 */
4734 public static int[] remove(int[] array, int index) {
4735 return (int[]) remove((Object) array, index);
4736 }
4737
4738 /**
4739 * <p>Removes the first occurrence of the specified element from the
4740 * specified array. All subsequent elements are shifted to the left
4741 * (subtracts one from their indices). If the array doesn't contains
4742 * such an element, no elements are removed from the array.</p>
4743 *
4744 * <p>This method returns a new array with the same elements of the input
4745 * array except the first occurrence of the specified element. The component
4746 * type of the returned array is always the same as that of the input
4747 * array.</p>
4748 *
4749 * <pre>
4750 * ArrayUtils.removeElement(null, 1) = null
4751 * ArrayUtils.removeElement([], 1) = []
4752 * ArrayUtils.removeElement([1], 2) = [1]
4753 * ArrayUtils.removeElement([1, 3], 1) = [3]
4754 * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1]
4755 * </pre>
4756 *
4757 * @param array the array to remove the element from, may be {@code null}
4758 * @param element the element to be removed
4759 * @return A new array containing the existing elements except the first
4760 * occurrence of the specified element.
4761 * @since 2.1
4762 */
4763 public static int[] removeElement(int[] array, int element) {
4764 int index = indexOf(array, element);
4765 if (index == INDEX_NOT_FOUND) {
4766 return clone(array);
4767 }
4768 return remove(array, index);
4769 }
4770
4771 /**
4772 * <p>Removes the element at the specified position from the specified array.
4773 * All subsequent elements are shifted to the left (subtracts one from
4774 * their indices).</p>
4775 *
4776 * <p>This method returns a new array with the same elements of the input
4777 * array except the element on the specified position. The component
4778 * type of the returned array is always the same as that of the input
4779 * array.</p>
4780 *
4781 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4782 * will be thrown, because in that case no valid index can be specified.</p>
4783 *
4784 * <pre>
4785 * ArrayUtils.remove([1], 0) = []
4786 * ArrayUtils.remove([2, 6], 0) = [6]
4787 * ArrayUtils.remove([2, 6], 1) = [2]
4788 * ArrayUtils.remove([2, 6, 3], 1) = [2, 3]
4789 * </pre>
4790 *
4791 * @param array the array to remove the element from, may not be {@code null}
4792 * @param index the position of the element to be removed
4793 * @return A new array containing the existing elements except the element
4794 * at the specified position.
4795 * @throws IndexOutOfBoundsException if the index is out of range
4796 * (index < 0 || index >= array.length), or if the array is {@code null}.
4797 * @since 2.1
4798 */
4799 public static long[] remove(long[] array, int index) {
4800 return (long[]) remove((Object) array, index);
4801 }
4802
4803 /**
4804 * <p>Removes the first occurrence of the specified element from the
4805 * specified array. All subsequent elements are shifted to the left
4806 * (subtracts one from their indices). If the array doesn't contains
4807 * such an element, no elements are removed from the array.</p>
4808 *
4809 * <p>This method returns a new array with the same elements of the input
4810 * array except the first occurrence of the specified element. The component
4811 * type of the returned array is always the same as that of the input
4812 * array.</p>
4813 *
4814 * <pre>
4815 * ArrayUtils.removeElement(null, 1) = null
4816 * ArrayUtils.removeElement([], 1) = []
4817 * ArrayUtils.removeElement([1], 2) = [1]
4818 * ArrayUtils.removeElement([1, 3], 1) = [3]
4819 * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1]
4820 * </pre>
4821 *
4822 * @param array the array to remove the element from, may be {@code null}
4823 * @param element the element to be removed
4824 * @return A new array containing the existing elements except the first
4825 * occurrence of the specified element.
4826 * @since 2.1
4827 */
4828 public static long[] removeElement(long[] array, long element) {
4829 int index = indexOf(array, element);
4830 if (index == INDEX_NOT_FOUND) {
4831 return clone(array);
4832 }
4833 return remove(array, index);
4834 }
4835
4836 /**
4837 * <p>Removes the element at the specified position from the specified array.
4838 * All subsequent elements are shifted to the left (subtracts one from
4839 * their indices).</p>
4840 *
4841 * <p>This method returns a new array with the same elements of the input
4842 * array except the element on the specified position. The component
4843 * type of the returned array is always the same as that of the input
4844 * array.</p>
4845 *
4846 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4847 * will be thrown, because in that case no valid index can be specified.</p>
4848 *
4849 * <pre>
4850 * ArrayUtils.remove([1], 0) = []
4851 * ArrayUtils.remove([2, 6], 0) = [6]
4852 * ArrayUtils.remove([2, 6], 1) = [2]
4853 * ArrayUtils.remove([2, 6, 3], 1) = [2, 3]
4854 * </pre>
4855 *
4856 * @param array the array to remove the element from, may not be {@code null}
4857 * @param index the position of the element to be removed
4858 * @return A new array containing the existing elements except the element
4859 * at the specified position.
4860 * @throws IndexOutOfBoundsException if the index is out of range
4861 * (index < 0 || index >= array.length), or if the array is {@code null}.
4862 * @since 2.1
4863 */
4864 public static short[] remove(short[] array, int index) {
4865 return (short[]) remove((Object) array, index);
4866 }
4867
4868 /**
4869 * <p>Removes the first occurrence of the specified element from the
4870 * specified array. All subsequent elements are shifted to the left
4871 * (subtracts one from their indices). If the array doesn't contains
4872 * such an element, no elements are removed from the array.</p>
4873 *
4874 * <p>This method returns a new array with the same elements of the input
4875 * array except the first occurrence of the specified element. The component
4876 * type of the returned array is always the same as that of the input
4877 * array.</p>
4878 *
4879 * <pre>
4880 * ArrayUtils.removeElement(null, 1) = null
4881 * ArrayUtils.removeElement([], 1) = []
4882 * ArrayUtils.removeElement([1], 2) = [1]
4883 * ArrayUtils.removeElement([1, 3], 1) = [3]
4884 * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1]
4885 * </pre>
4886 *
4887 * @param array the array to remove the element from, may be {@code null}
4888 * @param element the element to be removed
4889 * @return A new array containing the existing elements except the first
4890 * occurrence of the specified element.
4891 * @since 2.1
4892 */
4893 public static short[] removeElement(short[] array, short element) {
4894 int index = indexOf(array, element);
4895 if (index == INDEX_NOT_FOUND) {
4896 return clone(array);
4897 }
4898 return remove(array, index);
4899 }
4900
4901 /**
4902 * <p>Removes the element at the specified position from the specified array.
4903 * All subsequent elements are shifted to the left (subtracts one from
4904 * their indices).</p>
4905 *
4906 * <p>This method returns a new array with the same elements of the input
4907 * array except the element on the specified position. The component
4908 * type of the returned array is always the same as that of the input
4909 * array.</p>
4910 *
4911 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4912 * will be thrown, because in that case no valid index can be specified.</p>
4913 *
4914 * @param array the array to remove the element from, may not be {@code null}
4915 * @param index the position of the element to be removed
4916 * @return A new array containing the existing elements except the element
4917 * at the specified position.
4918 * @throws IndexOutOfBoundsException if the index is out of range
4919 * (index < 0 || index >= array.length), or if the array is {@code null}.
4920 * @since 2.1
4921 */
4922 private static Object remove(Object array, int index) {
4923 int length = getLength(array);
4924 if (index < 0 || index >= length) {
4925 throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
4926 }
4927
4928 Object result = Array.newInstance(array.getClass().getComponentType(), length - 1);
4929 System.arraycopy(array, 0, result, 0, index);
4930 if (index < length - 1) {
4931 System.arraycopy(array, index + 1, result, index, length - index - 1);
4932 }
4933
4934 return result;
4935 }
4936
4937 /**
4938 * <p>Removes the elements at the specified positions from the specified array.
4939 * All remaining elements are shifted to the left.</p>
4940 *
4941 * <p>This method returns a new array with the same elements of the input
4942 * array except those at the specified positions. The component
4943 * type of the returned array is always the same as that of the input
4944 * array.</p>
4945 *
4946 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
4947 * will be thrown, because in that case no valid index can be specified.</p>
4948 *
4949 * <pre>
4950 * ArrayUtils.removeAll(["a", "b", "c"], 0, 2) = ["b"]
4951 * ArrayUtils.removeAll(["a", "b", "c"], 1, 2) = ["a"]
4952 * </pre>
4953 *
4954 * @param <T> the component type of the array
4955 * @param array the array to remove the element from, may not be {@code null}
4956 * @param indices the positions of the elements to be removed
4957 * @return A new array containing the existing elements except those
4958 * at the specified positions.
4959 * @throws IndexOutOfBoundsException if any index is out of range
4960 * (index < 0 || index >= array.length), or if the array is {@code null}.
4961 * @since 3.0.1
4962 */
4963 @SuppressWarnings("unchecked")
4964 // removeAll() always creates an array of the same type as its input
4965 public static <T> T[] removeAll(T[] array, int... indices) {
4966 return (T[]) removeAll((Object) array, clone(indices));
4967 }
4968
4969 /**
4970 * <p>Removes occurrences of specified elements, in specified quantities,
4971 * from the specified array. All subsequent elements are shifted left.
4972 * For any element-to-be-removed specified in greater quantities than
4973 * contained in the original array, no change occurs beyond the
4974 * removal of the existing matching items.</p>
4975 *
4976 * <p>This method returns a new array with the same elements of the input
4977 * array except for the earliest-encountered occurrences of the specified
4978 * elements. The component type of the returned array is always the same
4979 * as that of the input array.</p>
4980 *
4981 * <pre>
4982 * ArrayUtils.removeElements(null, "a", "b") = null
4983 * ArrayUtils.removeElements([], "a", "b") = []
4984 * ArrayUtils.removeElements(["a"], "b", "c") = ["a"]
4985 * ArrayUtils.removeElements(["a", "b"], "a", "c") = ["b"]
4986 * ArrayUtils.removeElements(["a", "b", "a"], "a") = ["b", "a"]
4987 * ArrayUtils.removeElements(["a", "b", "a"], "a", "a") = ["b"]
4988 * </pre>
4989 *
4990 * @param <T> the component type of the array
4991 * @param array the array to remove the element from, may be {@code null}
4992 * @param values the elements to be removed
4993 * @return A new array containing the existing elements except the
4994 * earliest-encountered occurrences of the specified elements.
4995 * @since 3.0.1
4996 */
4997 public static <T> T[] removeElements(T[] array, T... values) {
4998 if (isEmpty(array) || isEmpty(values)) {
4999 return clone(array);
5000 }
5001 HashMap<T, MutableInt> occurrences = new HashMap<T, MutableInt>(values.length);
5002 for (T v : values) {
5003 MutableInt count = occurrences.get(v);
5004 if (count == null) {
5005 occurrences.put(v, new MutableInt(1));
5006 } else {
5007 count.increment();
5008 }
5009 }
5010 HashSet<Integer> toRemove = new HashSet<Integer>();
5011 for (Map.Entry<T, MutableInt> e : occurrences.entrySet()) {
5012 T v = e.getKey();
5013 int found = 0;
5014 for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
5015 found = indexOf(array, v, found);
5016 if (found < 0) {
5017 break;
5018 }
5019 toRemove.add(found++);
5020 }
5021 }
5022 return removeAll(array, extractIndices(toRemove));
5023 }
5024
5025 /**
5026 * <p>Removes the elements at the specified positions from the specified array.
5027 * All remaining elements are shifted to the left.</p>
5028 *
5029 * <p>This method returns a new array with the same elements of the input
5030 * array except those at the specified positions. The component
5031 * type of the returned array is always the same as that of the input
5032 * array.</p>
5033 *
5034 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
5035 * will be thrown, because in that case no valid index can be specified.</p>
5036 *
5037 * <pre>
5038 * ArrayUtils.removeAll([1], 0) = []
5039 * ArrayUtils.removeAll([2, 6], 0) = [6]
5040 * ArrayUtils.removeAll([2, 6], 0, 1) = []
5041 * ArrayUtils.removeAll([2, 6, 3], 1, 2) = [2]
5042 * ArrayUtils.removeAll([2, 6, 3], 0, 2) = [6]
5043 * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
5044 * </pre>
5045 *
5046 * @param array the array to remove the element from, may not be {@code null}
5047 * @param indices the positions of the elements to be removed
5048 * @return A new array containing the existing elements except those
5049 * at the specified positions.
5050 * @throws IndexOutOfBoundsException if any index is out of range
5051 * (index < 0 || index >= array.length), or if the array is {@code null}.
5052 * @since 3.0.1
5053 */
5054 public static byte[] removeAll(byte[] array, int... indices) {
5055 return (byte[]) removeAll((Object) array, clone(indices));
5056 }
5057
5058 /**
5059 * <p>Removes occurrences of specified elements, in specified quantities,
5060 * from the specified array. All subsequent elements are shifted left.
5061 * For any element-to-be-removed specified in greater quantities than
5062 * contained in the original array, no change occurs beyond the
5063 * removal of the existing matching items.</p>
5064 *
5065 * <p>This method returns a new array with the same elements of the input
5066 * array except for the earliest-encountered occurrences of the specified
5067 * elements. The component type of the returned array is always the same
5068 * as that of the input array.</p>
5069 *
5070 * <pre>
5071 * ArrayUtils.removeElements(null, 1, 2) = null
5072 * ArrayUtils.removeElements([], 1, 2) = []
5073 * ArrayUtils.removeElements([1], 2, 3) = [1]
5074 * ArrayUtils.removeElements([1, 3], 1, 2) = [3]
5075 * ArrayUtils.removeElements([1, 3, 1], 1) = [3, 1]
5076 * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
5077 * </pre>
5078 *
5079 * @param array the array to remove the element from, may be {@code null}
5080 * @param values the elements to be removed
5081 * @return A new array containing the existing elements except the
5082 * earliest-encountered occurrences of the specified elements.
5083 * @since 3.0.1
5084 */
5085 public static byte[] removeElements(byte[] array, byte... values) {
5086 if (isEmpty(array) || isEmpty(values)) {
5087 return clone(array);
5088 }
5089 HashMap<Byte, MutableInt> occurrences = new HashMap<Byte, MutableInt>(values.length);
5090 for (byte v : values) {
5091 Byte boxed = Byte.valueOf(v);
5092 MutableInt count = occurrences.get(boxed);
5093 if (count == null) {
5094 occurrences.put(boxed, new MutableInt(1));
5095 } else {
5096 count.increment();
5097 }
5098 }
5099 HashSet<Integer> toRemove = new HashSet<Integer>();
5100 for (Map.Entry<Byte, MutableInt> e : occurrences.entrySet()) {
5101 Byte v = e.getKey();
5102 int found = 0;
5103 for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
5104 found = indexOf(array, v.byteValue(), found);
5105 if (found < 0) {
5106 break;
5107 }
5108 toRemove.add(found++);
5109 }
5110 }
5111 return removeAll(array, extractIndices(toRemove));
5112 }
5113
5114 /**
5115 * <p>Removes the elements at the specified positions from the specified array.
5116 * All remaining elements are shifted to the left.</p>
5117 *
5118 * <p>This method returns a new array with the same elements of the input
5119 * array except those at the specified positions. The component
5120 * type of the returned array is always the same as that of the input
5121 * array.</p>
5122 *
5123 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
5124 * will be thrown, because in that case no valid index can be specified.</p>
5125 *
5126 * <pre>
5127 * ArrayUtils.removeAll([1], 0) = []
5128 * ArrayUtils.removeAll([2, 6], 0) = [6]
5129 * ArrayUtils.removeAll([2, 6], 0, 1) = []
5130 * ArrayUtils.removeAll([2, 6, 3], 1, 2) = [2]
5131 * ArrayUtils.removeAll([2, 6, 3], 0, 2) = [6]
5132 * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
5133 * </pre>
5134 *
5135 * @param array the array to remove the element from, may not be {@code null}
5136 * @param indices the positions of the elements to be removed
5137 * @return A new array containing the existing elements except those
5138 * at the specified positions.
5139 * @throws IndexOutOfBoundsException if any index is out of range
5140 * (index < 0 || index >= array.length), or if the array is {@code null}.
5141 * @since 3.0.1
5142 */
5143 public static short[] removeAll(short[] array, int... indices) {
5144 return (short[]) removeAll((Object) array, clone(indices));
5145 }
5146
5147 /**
5148 * <p>Removes occurrences of specified elements, in specified quantities,
5149 * from the specified array. All subsequent elements are shifted left.
5150 * For any element-to-be-removed specified in greater quantities than
5151 * contained in the original array, no change occurs beyond the
5152 * removal of the existing matching items.</p>
5153 *
5154 * <p>This method returns a new array with the same elements of the input
5155 * array except for the earliest-encountered occurrences of the specified
5156 * elements. The component type of the returned array is always the same
5157 * as that of the input array.</p>
5158 *
5159 * <pre>
5160 * ArrayUtils.removeElements(null, 1, 2) = null
5161 * ArrayUtils.removeElements([], 1, 2) = []
5162 * ArrayUtils.removeElements([1], 2, 3) = [1]
5163 * ArrayUtils.removeElements([1, 3], 1, 2) = [3]
5164 * ArrayUtils.removeElements([1, 3, 1], 1) = [3, 1]
5165 * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
5166 * </pre>
5167 *
5168 * @param array the array to remove the element from, may be {@code null}
5169 * @param values the elements to be removed
5170 * @return A new array containing the existing elements except the
5171 * earliest-encountered occurrences of the specified elements.
5172 * @since 3.0.1
5173 */
5174 public static short[] removeElements(short[] array, short... values) {
5175 if (isEmpty(array) || isEmpty(values)) {
5176 return clone(array);
5177 }
5178 HashMap<Short, MutableInt> occurrences = new HashMap<Short, MutableInt>(values.length);
5179 for (short v : values) {
5180 Short boxed = Short.valueOf(v);
5181 MutableInt count = occurrences.get(boxed);
5182 if (count == null) {
5183 occurrences.put(boxed, new MutableInt(1));
5184 } else {
5185 count.increment();
5186 }
5187 }
5188 HashSet<Integer> toRemove = new HashSet<Integer>();
5189 for (Map.Entry<Short, MutableInt> e : occurrences.entrySet()) {
5190 Short v = e.getKey();
5191 int found = 0;
5192 for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
5193 found = indexOf(array, v.shortValue(), found);
5194 if (found < 0) {
5195 break;
5196 }
5197 toRemove.add(found++);
5198 }
5199 }
5200 return removeAll(array, extractIndices(toRemove));
5201 }
5202
5203 /**
5204 * <p>Removes the elements at the specified positions from the specified array.
5205 * All remaining elements are shifted to the left.</p>
5206 *
5207 * <p>This method returns a new array with the same elements of the input
5208 * array except those at the specified positions. The component
5209 * type of the returned array is always the same as that of the input
5210 * array.</p>
5211 *
5212 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
5213 * will be thrown, because in that case no valid index can be specified.</p>
5214 *
5215 * <pre>
5216 * ArrayUtils.removeAll([1], 0) = []
5217 * ArrayUtils.removeAll([2, 6], 0) = [6]
5218 * ArrayUtils.removeAll([2, 6], 0, 1) = []
5219 * ArrayUtils.removeAll([2, 6, 3], 1, 2) = [2]
5220 * ArrayUtils.removeAll([2, 6, 3], 0, 2) = [6]
5221 * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
5222 * </pre>
5223 *
5224 * @param array the array to remove the element from, may not be {@code null}
5225 * @param indices the positions of the elements to be removed
5226 * @return A new array containing the existing elements except those
5227 * at the specified positions.
5228 * @throws IndexOutOfBoundsException if any index is out of range
5229 * (index < 0 || index >= array.length), or if the array is {@code null}.
5230 * @since 3.0.1
5231 */
5232 public static int[] removeAll(int[] array, int... indices) {
5233 return (int[]) removeAll((Object) array, clone(indices));
5234 }
5235
5236 /**
5237 * <p>Removes occurrences of specified elements, in specified quantities,
5238 * from the specified array. All subsequent elements are shifted left.
5239 * For any element-to-be-removed specified in greater quantities than
5240 * contained in the original array, no change occurs beyond the
5241 * removal of the existing matching items.</p>
5242 *
5243 * <p>This method returns a new array with the same elements of the input
5244 * array except for the earliest-encountered occurrences of the specified
5245 * elements. The component type of the returned array is always the same
5246 * as that of the input array.</p>
5247 *
5248 * <pre>
5249 * ArrayUtils.removeElements(null, 1, 2) = null
5250 * ArrayUtils.removeElements([], 1, 2) = []
5251 * ArrayUtils.removeElements([1], 2, 3) = [1]
5252 * ArrayUtils.removeElements([1, 3], 1, 2) = [3]
5253 * ArrayUtils.removeElements([1, 3, 1], 1) = [3, 1]
5254 * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
5255 * </pre>
5256 *
5257 * @param array the array to remove the element from, may be {@code null}
5258 * @param values the elements to be removed
5259 * @return A new array containing the existing elements except the
5260 * earliest-encountered occurrences of the specified elements.
5261 * @since 3.0.1
5262 */
5263 public static int[] removeElements(int[] array, int... values) {
5264 if (isEmpty(array) || isEmpty(values)) {
5265 return clone(array);
5266 }
5267 HashMap<Integer, MutableInt> occurrences = new HashMap<Integer, MutableInt>(values.length);
5268 for (int v : values) {
5269 Integer boxed = Integer.valueOf(v);
5270 MutableInt count = occurrences.get(boxed);
5271 if (count == null) {
5272 occurrences.put(boxed, new MutableInt(1));
5273 } else {
5274 count.increment();
5275 }
5276 }
5277 HashSet<Integer> toRemove = new HashSet<Integer>();
5278 for (Map.Entry<Integer, MutableInt> e : occurrences.entrySet()) {
5279 Integer v = e.getKey();
5280 int found = 0;
5281 for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
5282 found = indexOf(array, v.intValue(), found);
5283 if (found < 0) {
5284 break;
5285 }
5286 toRemove.add(found++);
5287 }
5288 }
5289 return removeAll(array, extractIndices(toRemove));
5290 }
5291
5292 /**
5293 * <p>Removes the elements at the specified positions from the specified array.
5294 * All remaining elements are shifted to the left.</p>
5295 *
5296 * <p>This method returns a new array with the same elements of the input
5297 * array except those at the specified positions. The component
5298 * type of the returned array is always the same as that of the input
5299 * array.</p>
5300 *
5301 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
5302 * will be thrown, because in that case no valid index can be specified.</p>
5303 *
5304 * <pre>
5305 * ArrayUtils.removeAll([1], 0) = []
5306 * ArrayUtils.removeAll([2, 6], 0) = [6]
5307 * ArrayUtils.removeAll([2, 6], 0, 1) = []
5308 * ArrayUtils.removeAll([2, 6, 3], 1, 2) = [2]
5309 * ArrayUtils.removeAll([2, 6, 3], 0, 2) = [6]
5310 * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
5311 * </pre>
5312 *
5313 * @param array the array to remove the element from, may not be {@code null}
5314 * @param indices the positions of the elements to be removed
5315 * @return A new array containing the existing elements except those
5316 * at the specified positions.
5317 * @throws IndexOutOfBoundsException if any index is out of range
5318 * (index < 0 || index >= array.length), or if the array is {@code null}.
5319 * @since 3.0.1
5320 */
5321 public static char[] removeAll(char[] array, int... indices) {
5322 return (char[]) removeAll((Object) array, clone(indices));
5323 }
5324
5325 /**
5326 * <p>Removes occurrences of specified elements, in specified quantities,
5327 * from the specified array. All subsequent elements are shifted left.
5328 * For any element-to-be-removed specified in greater quantities than
5329 * contained in the original array, no change occurs beyond the
5330 * removal of the existing matching items.</p>
5331 *
5332 * <p>This method returns a new array with the same elements of the input
5333 * array except for the earliest-encountered occurrences of the specified
5334 * elements. The component type of the returned array is always the same
5335 * as that of the input array.</p>
5336 *
5337 * <pre>
5338 * ArrayUtils.removeElements(null, 1, 2) = null
5339 * ArrayUtils.removeElements([], 1, 2) = []
5340 * ArrayUtils.removeElements([1], 2, 3) = [1]
5341 * ArrayUtils.removeElements([1, 3], 1, 2) = [3]
5342 * ArrayUtils.removeElements([1, 3, 1], 1) = [3, 1]
5343 * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
5344 * </pre>
5345 *
5346 * @param array the array to remove the element from, may be {@code null}
5347 * @param values the elements to be removed
5348 * @return A new array containing the existing elements except the
5349 * earliest-encountered occurrences of the specified elements.
5350 * @since 3.0.1
5351 */
5352 public static char[] removeElements(char[] array, char... values) {
5353 if (isEmpty(array) || isEmpty(values)) {
5354 return clone(array);
5355 }
5356 HashMap<Character, MutableInt> occurrences = new HashMap<Character, MutableInt>(values.length);
5357 for (char v : values) {
5358 Character boxed = Character.valueOf(v);
5359 MutableInt count = occurrences.get(boxed);
5360 if (count == null) {
5361 occurrences.put(boxed, new MutableInt(1));
5362 } else {
5363 count.increment();
5364 }
5365 }
5366 HashSet<Integer> toRemove = new HashSet<Integer>();
5367 for (Map.Entry<Character, MutableInt> e : occurrences.entrySet()) {
5368 Character v = e.getKey();
5369 int found = 0;
5370 for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
5371 found = indexOf(array, v.charValue(), found);
5372 if (found < 0) {
5373 break;
5374 }
5375 toRemove.add(found++);
5376 }
5377 }
5378 return removeAll(array, extractIndices(toRemove));
5379 }
5380
5381 /**
5382 * <p>Removes the elements at the specified positions from the specified array.
5383 * All remaining elements are shifted to the left.</p>
5384 *
5385 * <p>This method returns a new array with the same elements of the input
5386 * array except those at the specified positions. The component
5387 * type of the returned array is always the same as that of the input
5388 * array.</p>
5389 *
5390 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
5391 * will be thrown, because in that case no valid index can be specified.</p>
5392 *
5393 * <pre>
5394 * ArrayUtils.removeAll([1], 0) = []
5395 * ArrayUtils.removeAll([2, 6], 0) = [6]
5396 * ArrayUtils.removeAll([2, 6], 0, 1) = []
5397 * ArrayUtils.removeAll([2, 6, 3], 1, 2) = [2]
5398 * ArrayUtils.removeAll([2, 6, 3], 0, 2) = [6]
5399 * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
5400 * </pre>
5401 *
5402 * @param array the array to remove the element from, may not be {@code null}
5403 * @param indices the positions of the elements to be removed
5404 * @return A new array containing the existing elements except those
5405 * at the specified positions.
5406 * @throws IndexOutOfBoundsException if any index is out of range
5407 * (index < 0 || index >= array.length), or if the array is {@code null}.
5408 * @since 3.0.1
5409 */
5410 public static long[] removeAll(long[] array, int... indices) {
5411 return (long[]) removeAll((Object) array, clone(indices));
5412 }
5413
5414 /**
5415 * <p>Removes occurrences of specified elements, in specified quantities,
5416 * from the specified array. All subsequent elements are shifted left.
5417 * For any element-to-be-removed specified in greater quantities than
5418 * contained in the original array, no change occurs beyond the
5419 * removal of the existing matching items.</p>
5420 *
5421 * <p>This method returns a new array with the same elements of the input
5422 * array except for the earliest-encountered occurrences of the specified
5423 * elements. The component type of the returned array is always the same
5424 * as that of the input array.</p>
5425 *
5426 * <pre>
5427 * ArrayUtils.removeElements(null, 1, 2) = null
5428 * ArrayUtils.removeElements([], 1, 2) = []
5429 * ArrayUtils.removeElements([1], 2, 3) = [1]
5430 * ArrayUtils.removeElements([1, 3], 1, 2) = [3]
5431 * ArrayUtils.removeElements([1, 3, 1], 1) = [3, 1]
5432 * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
5433 * </pre>
5434 *
5435 * @param array the array to remove the element from, may be {@code null}
5436 * @param values the elements to be removed
5437 * @return A new array containing the existing elements except the
5438 * earliest-encountered occurrences of the specified elements.
5439 * @since 3.0.1
5440 */
5441 public static long[] removeElements(long[] array, long... values) {
5442 if (isEmpty(array) || isEmpty(values)) {
5443 return clone(array);
5444 }
5445 HashMap<Long, MutableInt> occurrences = new HashMap<Long, MutableInt>(values.length);
5446 for (long v : values) {
5447 Long boxed = Long.valueOf(v);
5448 MutableInt count = occurrences.get(boxed);
5449 if (count == null) {
5450 occurrences.put(boxed, new MutableInt(1));
5451 } else {
5452 count.increment();
5453 }
5454 }
5455 HashSet<Integer> toRemove = new HashSet<Integer>();
5456 for (Map.Entry<Long, MutableInt> e : occurrences.entrySet()) {
5457 Long v = e.getKey();
5458 int found = 0;
5459 for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
5460 found = indexOf(array, v.longValue(), found);
5461 if (found < 0) {
5462 break;
5463 }
5464 toRemove.add(found++);
5465 }
5466 }
5467 return removeAll(array, extractIndices(toRemove));
5468 }
5469
5470 /**
5471 * <p>Removes the elements at the specified positions from the specified array.
5472 * All remaining elements are shifted to the left.</p>
5473 *
5474 * <p>This method returns a new array with the same elements of the input
5475 * array except those at the specified positions. The component
5476 * type of the returned array is always the same as that of the input
5477 * array.</p>
5478 *
5479 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
5480 * will be thrown, because in that case no valid index can be specified.</p>
5481 *
5482 * <pre>
5483 * ArrayUtils.removeAll([1], 0) = []
5484 * ArrayUtils.removeAll([2, 6], 0) = [6]
5485 * ArrayUtils.removeAll([2, 6], 0, 1) = []
5486 * ArrayUtils.removeAll([2, 6, 3], 1, 2) = [2]
5487 * ArrayUtils.removeAll([2, 6, 3], 0, 2) = [6]
5488 * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
5489 * </pre>
5490 *
5491 * @param array the array to remove the element from, may not be {@code null}
5492 * @param indices the positions of the elements to be removed
5493 * @return A new array containing the existing elements except those
5494 * at the specified positions.
5495 * @throws IndexOutOfBoundsException if any index is out of range
5496 * (index < 0 || index >= array.length), or if the array is {@code null}.
5497 * @since 3.0.1
5498 */
5499 public static float[] removeAll(float[] array, int... indices) {
5500 return (float[]) removeAll((Object) array, clone(indices));
5501 }
5502
5503 /**
5504 * <p>Removes occurrences of specified elements, in specified quantities,
5505 * from the specified array. All subsequent elements are shifted left.
5506 * For any element-to-be-removed specified in greater quantities than
5507 * contained in the original array, no change occurs beyond the
5508 * removal of the existing matching items.</p>
5509 *
5510 * <p>This method returns a new array with the same elements of the input
5511 * array except for the earliest-encountered occurrences of the specified
5512 * elements. The component type of the returned array is always the same
5513 * as that of the input array.</p>
5514 *
5515 * <pre>
5516 * ArrayUtils.removeElements(null, 1, 2) = null
5517 * ArrayUtils.removeElements([], 1, 2) = []
5518 * ArrayUtils.removeElements([1], 2, 3) = [1]
5519 * ArrayUtils.removeElements([1, 3], 1, 2) = [3]
5520 * ArrayUtils.removeElements([1, 3, 1], 1) = [3, 1]
5521 * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
5522 * </pre>
5523 *
5524 * @param array the array to remove the element from, may be {@code null}
5525 * @param values the elements to be removed
5526 * @return A new array containing the existing elements except the
5527 * earliest-encountered occurrences of the specified elements.
5528 * @since 3.0.1
5529 */
5530 public static float[] removeElements(float[] array, float... values) {
5531 if (isEmpty(array) || isEmpty(values)) {
5532 return clone(array);
5533 }
5534 HashMap<Float, MutableInt> occurrences = new HashMap<Float, MutableInt>(values.length);
5535 for (float v : values) {
5536 Float boxed = Float.valueOf(v);
5537 MutableInt count = occurrences.get(boxed);
5538 if (count == null) {
5539 occurrences.put(boxed, new MutableInt(1));
5540 } else {
5541 count.increment();
5542 }
5543 }
5544 HashSet<Integer> toRemove = new HashSet<Integer>();
5545 for (Map.Entry<Float, MutableInt> e : occurrences.entrySet()) {
5546 Float v = e.getKey();
5547 int found = 0;
5548 for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
5549 found = indexOf(array, v.floatValue(), found);
5550 if (found < 0) {
5551 break;
5552 }
5553 toRemove.add(found++);
5554 }
5555 }
5556 return removeAll(array, extractIndices(toRemove));
5557 }
5558
5559 /**
5560 * <p>Removes the elements at the specified positions from the specified array.
5561 * All remaining elements are shifted to the left.</p>
5562 *
5563 * <p>This method returns a new array with the same elements of the input
5564 * array except those at the specified positions. The component
5565 * type of the returned array is always the same as that of the input
5566 * array.</p>
5567 *
5568 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
5569 * will be thrown, because in that case no valid index can be specified.</p>
5570 *
5571 * <pre>
5572 * ArrayUtils.removeAll([1], 0) = []
5573 * ArrayUtils.removeAll([2, 6], 0) = [6]
5574 * ArrayUtils.removeAll([2, 6], 0, 1) = []
5575 * ArrayUtils.removeAll([2, 6, 3], 1, 2) = [2]
5576 * ArrayUtils.removeAll([2, 6, 3], 0, 2) = [6]
5577 * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
5578 * </pre>
5579 *
5580 * @param array the array to remove the element from, may not be {@code null}
5581 * @param indices the positions of the elements to be removed
5582 * @return A new array containing the existing elements except those
5583 * at the specified positions.
5584 * @throws IndexOutOfBoundsException if any index is out of range
5585 * (index < 0 || index >= array.length), or if the array is {@code null}.
5586 * @since 3.0.1
5587 */
5588 public static double[] removeAll(double[] array, int... indices) {
5589 return (double[]) removeAll((Object) array, clone(indices));
5590 }
5591
5592 /**
5593 * <p>Removes occurrences of specified elements, in specified quantities,
5594 * from the specified array. All subsequent elements are shifted left.
5595 * For any element-to-be-removed specified in greater quantities than
5596 * contained in the original array, no change occurs beyond the
5597 * removal of the existing matching items.</p>
5598 *
5599 * <p>This method returns a new array with the same elements of the input
5600 * array except for the earliest-encountered occurrences of the specified
5601 * elements. The component type of the returned array is always the same
5602 * as that of the input array.</p>
5603 *
5604 * <pre>
5605 * ArrayUtils.removeElements(null, 1, 2) = null
5606 * ArrayUtils.removeElements([], 1, 2) = []
5607 * ArrayUtils.removeElements([1], 2, 3) = [1]
5608 * ArrayUtils.removeElements([1, 3], 1, 2) = [3]
5609 * ArrayUtils.removeElements([1, 3, 1], 1) = [3, 1]
5610 * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
5611 * </pre>
5612 *
5613 * @param array the array to remove the element from, may be {@code null}
5614 * @param values the elements to be removed
5615 * @return A new array containing the existing elements except the
5616 * earliest-encountered occurrences of the specified elements.
5617 * @since 3.0.1
5618 */
5619 public static double[] removeElements(double[] array, double... values) {
5620 if (isEmpty(array) || isEmpty(values)) {
5621 return clone(array);
5622 }
5623 HashMap<Double, MutableInt> occurrences = new HashMap<Double, MutableInt>(values.length);
5624 for (double v : values) {
5625 Double boxed = Double.valueOf(v);
5626 MutableInt count = occurrences.get(boxed);
5627 if (count == null) {
5628 occurrences.put(boxed, new MutableInt(1));
5629 } else {
5630 count.increment();
5631 }
5632 }
5633 HashSet<Integer> toRemove = new HashSet<Integer>();
5634 for (Map.Entry<Double, MutableInt> e : occurrences.entrySet()) {
5635 Double v = e.getKey();
5636 int found = 0;
5637 for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
5638 found = indexOf(array, v.doubleValue(), found);
5639 if (found < 0) {
5640 break;
5641 }
5642 toRemove.add(found++);
5643 }
5644 }
5645 return removeAll(array, extractIndices(toRemove));
5646 }
5647
5648 /**
5649 * <p>Removes the elements at the specified positions from the specified array.
5650 * All remaining elements are shifted to the left.</p>
5651 *
5652 * <p>This method returns a new array with the same elements of the input
5653 * array except those at the specified positions. The component
5654 * type of the returned array is always the same as that of the input
5655 * array.</p>
5656 *
5657 * <p>If the input array is {@code null}, an IndexOutOfBoundsException
5658 * will be thrown, because in that case no valid index can be specified.</p>
5659 *
5660 * <pre>
5661 * ArrayUtils.removeAll([true, false, true], 0, 2) = [false]
5662 * ArrayUtils.removeAll([true, false, true], 1, 2) = [true]
5663 * </pre>
5664 *
5665 * @param array the array to remove the element from, may not be {@code null}
5666 * @param indices the positions of the elements to be removed
5667 * @return A new array containing the existing elements except those
5668 * at the specified positions.
5669 * @throws IndexOutOfBoundsException if any index is out of range
5670 * (index < 0 || index >= array.length), or if the array is {@code null}.
5671 * @since 3.0.1
5672 */
5673 public static boolean[] removeAll(boolean[] array, int... indices) {
5674 return (boolean[]) removeAll((Object) array, clone(indices));
5675 }
5676
5677 /**
5678 * <p>Removes occurrences of specified elements, in specified quantities,
5679 * from the specified array. All subsequent elements are shifted left.
5680 * For any element-to-be-removed specified in greater quantities than
5681 * contained in the original array, no change occurs beyond the
5682 * removal of the existing matching items.</p>
5683 *
5684 * <p>This method returns a new array with the same elements of the input
5685 * array except for the earliest-encountered occurrences of the specified
5686 * elements. The component type of the returned array is always the same
5687 * as that of the input array.</p>
5688 *
5689 * <pre>
5690 * ArrayUtils.removeElements(null, true, false) = null
5691 * ArrayUtils.removeElements([], true, false) = []
5692 * ArrayUtils.removeElements([true], false, false) = [true]
5693 * ArrayUtils.removeElements([true, false], true, true) = [false]
5694 * ArrayUtils.removeElements([true, false, true], true) = [false, true]
5695 * ArrayUtils.removeElements([true, false, true], true, true) = [false]
5696 * </pre>
5697 *
5698 * @param array the array to remove the element from, may be {@code null}
5699 * @param values the elements to be removed
5700 * @return A new array containing the existing elements except the
5701 * earliest-encountered occurrences of the specified elements.
5702 * @since 3.0.1
5703 */
5704 public static boolean[] removeElements(boolean[] array, boolean... values) {
5705 if (isEmpty(array) || isEmpty(values)) {
5706 return clone(array);
5707 }
5708 HashMap<Boolean, MutableInt> occurrences = new HashMap<Boolean, MutableInt>(values.length);
5709 for (boolean v : values) {
5710 Boolean boxed = Boolean.valueOf(v);
5711 MutableInt count = occurrences.get(boxed);
5712 if (count == null) {
5713 occurrences.put(boxed, new MutableInt(1));
5714 } else {
5715 count.increment();
5716 }
5717 }
5718 HashSet<Integer> toRemove = new HashSet<Integer>();
5719 for (Map.Entry<Boolean, MutableInt> e : occurrences.entrySet()) {
5720 Boolean v = e.getKey();
5721 int found = 0;
5722 for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
5723 found = indexOf(array, v.booleanValue(), found);
5724 if (found < 0) {
5725 break;
5726 }
5727 toRemove.add(found++);
5728 }
5729 }
5730 return removeAll(array, extractIndices(toRemove));
5731 }
5732
5733 /**
5734 * Removes multiple array elements specified by index.
5735 * @param array source
5736 * @param indices to remove, WILL BE SORTED--so only clones of user-owned arrays!
5737 * @return new array of same type minus elements specified by unique values of {@code indices}
5738 * @since 3.0.1
5739 */
5740 private static Object removeAll(Object array, int... indices) {
5741 int length = getLength(array);
5742 int diff = 0;
5743
5744 if (isNotEmpty(indices)) {
5745 Arrays.sort(indices);
5746
5747 int i = indices.length;
5748 int prevIndex = length;
5749 while (--i >= 0) {
5750 int index = indices[i];
5751 if (index < 0 || index >= length) {
5752 throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
5753 }
5754 if (index >= prevIndex) {
5755 continue;
5756 }
5757 diff++;
5758 prevIndex = index;
5759 }
5760 }
5761 Object result = Array.newInstance(array.getClass().getComponentType(), length - diff);
5762 if (diff < length) {
5763 int end = length;
5764 int dest = length - diff;
5765 for (int i = indices.length - 1; i >= 0; i--) {
5766 int index = indices[i];
5767 if (end - index > 1) {
5768 int cp = end - index - 1;
5769 dest -= cp;
5770 System.arraycopy(array, index + 1, result, dest, cp);
5771 }
5772 end = index;
5773 }
5774 if (end > 0) {
5775 System.arraycopy(array, 0, result, 0, end);
5776 }
5777 }
5778 return result;
5779 }
5780
5781 /**
5782 * Extract a set of Integer indices into an int[].
5783 * @param coll {@code HashSet} of {@code Integer}
5784 * @return int[]
5785 * @since 3.0.1
5786 */
5787 private static int[] extractIndices(HashSet<Integer> coll) {
5788 int[] result = new int[coll.size()];
5789 int i = 0;
5790 for (Integer index : coll) {
5791 result[i++] = index.intValue();
5792 }
5793 return result;
5794 }
5795 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 /**
19 * <p>Operations on bit-mapped fields.</p>
20 *
21 * @since 2.0
22 * @version $Id: BitField.java 1088899 2011-04-05 05:31:27Z bayard $
23 */
24 public class BitField {
25
26 private final int _mask;
27 private final int _shift_count;
28
29 /**
30 * <p>Creates a BitField instance.</p>
31 *
32 * @param mask the mask specifying which bits apply to this
33 * BitField. Bits that are set in this mask are the bits
34 * that this BitField operates on
35 */
36 public BitField(int mask) {
37 _mask = mask;
38 int count = 0;
39 int bit_pattern = mask;
40
41 if (bit_pattern != 0) {
42 while ((bit_pattern & 1) == 0) {
43 count++;
44 bit_pattern >>= 1;
45 }
46 }
47 _shift_count = count;
48 }
49
50 /**
51 * <p>Obtains the value for the specified BitField, appropriately
52 * shifted right.</p>
53 *
54 * <p>Many users of a BitField will want to treat the specified
55 * bits as an int value, and will not want to be aware that the
56 * value is stored as a BitField (and so shifted left so many
57 * bits).</p>
58 *
59 * @see #setValue(int,int)
60 * @param holder the int data containing the bits we're interested
61 * in
62 * @return the selected bits, shifted right appropriately
63 */
64 public int getValue(int holder) {
65 return getRawValue(holder) >> _shift_count;
66 }
67
68 /**
69 * <p>Obtains the value for the specified BitField, appropriately
70 * shifted right, as a short.</p>
71 *
72 * <p>Many users of a BitField will want to treat the specified
73 * bits as an int value, and will not want to be aware that the
74 * value is stored as a BitField (and so shifted left so many
75 * bits).</p>
76 *
77 * @see #setShortValue(short,short)
78 * @param holder the short data containing the bits we're
79 * interested in
80 * @return the selected bits, shifted right appropriately
81 */
82 public short getShortValue(short holder) {
83 return (short) getValue(holder);
84 }
85
86 /**
87 * <p>Obtains the value for the specified BitField, unshifted.</p>
88 *
89 * @param holder the int data containing the bits we're
90 * interested in
91 * @return the selected bits
92 */
93 public int getRawValue(int holder) {
94 return holder & _mask;
95 }
96
97 /**
98 * <p>Obtains the value for the specified BitField, unshifted.</p>
99 *
100 * @param holder the short data containing the bits we're
101 * interested in
102 * @return the selected bits
103 */
104 public short getShortRawValue(short holder) {
105 return (short) getRawValue(holder);
106 }
107
108 /**
109 * <p>Returns whether the field is set or not.</p>
110 *
111 * <p>This is most commonly used for a single-bit field, which is
112 * often used to represent a boolean value; the results of using
113 * it for a multi-bit field is to determine whether *any* of its
114 * bits are set.</p>
115 *
116 * @param holder the int data containing the bits we're interested
117 * in
118 * @return {@code true} if any of the bits are set,
119 * else {@code false}
120 */
121 public boolean isSet(int holder) {
122 return (holder & _mask) != 0;
123 }
124
125 /**
126 * <p>Returns whether all of the bits are set or not.</p>
127 *
128 * <p>This is a stricter test than {@link #isSet(int)},
129 * in that all of the bits in a multi-bit set must be set
130 * for this method to return {@code true}.</p>
131 *
132 * @param holder the int data containing the bits we're
133 * interested in
134 * @return {@code true} if all of the bits are set,
135 * else {@code false}
136 */
137 public boolean isAllSet(int holder) {
138 return (holder & _mask) == _mask;
139 }
140
141 /**
142 * <p>Replaces the bits with new values.</p>
143 *
144 * @see #getValue(int)
145 * @param holder the int data containing the bits we're
146 * interested in
147 * @param value the new value for the specified bits
148 * @return the value of holder with the bits from the value
149 * parameter replacing the old bits
150 */
151 public int setValue(int holder, int value) {
152 return (holder & ~_mask) | ((value << _shift_count) & _mask);
153 }
154
155 /**
156 * <p>Replaces the bits with new values.</p>
157 *
158 * @see #getShortValue(short)
159 * @param holder the short data containing the bits we're
160 * interested in
161 * @param value the new value for the specified bits
162 * @return the value of holder with the bits from the value
163 * parameter replacing the old bits
164 */
165 public short setShortValue(short holder, short value) {
166 return (short) setValue(holder, value);
167 }
168
169 /**
170 * <p>Clears the bits.</p>
171 *
172 * @param holder the int data containing the bits we're
173 * interested in
174 * @return the value of holder with the specified bits cleared
175 * (set to {@code 0})
176 */
177 public int clear(int holder) {
178 return holder & ~_mask;
179 }
180
181 /**
182 * <p>Clears the bits.</p>
183 *
184 * @param holder the short data containing the bits we're
185 * interested in
186 * @return the value of holder with the specified bits cleared
187 * (set to {@code 0})
188 */
189 public short clearShort(short holder) {
190 return (short) clear(holder);
191 }
192
193 /**
194 * <p>Clears the bits.</p>
195 *
196 * @param holder the byte data containing the bits we're
197 * interested in
198 *
199 * @return the value of holder with the specified bits cleared
200 * (set to {@code 0})
201 */
202 public byte clearByte(byte holder) {
203 return (byte) clear(holder);
204 }
205
206 /**
207 * <p>Sets the bits.</p>
208 *
209 * @param holder the int data containing the bits we're
210 * interested in
211 * @return the value of holder with the specified bits set
212 * to {@code 1}
213 */
214 public int set(int holder) {
215 return holder | _mask;
216 }
217
218 /**
219 * <p>Sets the bits.</p>
220 *
221 * @param holder the short data containing the bits we're
222 * interested in
223 * @return the value of holder with the specified bits set
224 * to {@code 1}
225 */
226 public short setShort(short holder) {
227 return (short) set(holder);
228 }
229
230 /**
231 * <p>Sets the bits.</p>
232 *
233 * @param holder the byte data containing the bits we're
234 * interested in
235 *
236 * @return the value of holder with the specified bits set
237 * to {@code 1}
238 */
239 public byte setByte(byte holder) {
240 return (byte) set(holder);
241 }
242
243 /**
244 * <p>Sets a boolean BitField.</p>
245 *
246 * @param holder the int data containing the bits we're
247 * interested in
248 * @param flag indicating whether to set or clear the bits
249 * @return the value of holder with the specified bits set or
250 * cleared
251 */
252 public int setBoolean(int holder, boolean flag) {
253 return flag ? set(holder) : clear(holder);
254 }
255
256 /**
257 * <p>Sets a boolean BitField.</p>
258 *
259 * @param holder the short data containing the bits we're
260 * interested in
261 * @param flag indicating whether to set or clear the bits
262 * @return the value of holder with the specified bits set or
263 * cleared
264 */
265 public short setShortBoolean(short holder, boolean flag) {
266 return flag ? setShort(holder) : clearShort(holder);
267 }
268
269 /**
270 * <p>Sets a boolean BitField.</p>
271 *
272 * @param holder the byte data containing the bits we're
273 * interested in
274 * @param flag indicating whether to set or clear the bits
275 * @return the value of holder with the specified bits set or
276 * cleared
277 */
278 public byte setByteBoolean(byte holder, boolean flag) {
279 return flag ? setByte(holder) : clearByte(holder);
280 }
281
282 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import org.apache.commons.lang3.math.NumberUtils;
19
20 /**
21 * <p>Operations on boolean primitives and Boolean objects.</p>
22 *
23 * <p>This class tries to handle {@code null} input gracefully.
24 * An exception will not be thrown for a {@code null} input.
25 * Each method documents its behaviour in more detail.</p>
26 *
27 * <p>#ThreadSafe#</p>
28 * @since 2.0
29 * @version $Id: BooleanUtils.java 1153484 2011-08-03 13:39:42Z ggregory $
30 */
31 public class BooleanUtils {
32
33 /**
34 * <p>{@code BooleanUtils} instances should NOT be constructed in standard programming.
35 * Instead, the class should be used as {@code BooleanUtils.negate(true);}.</p>
36 *
37 * <p>This constructor is public to permit tools that require a JavaBean instance
38 * to operate.</p>
39 */
40 public BooleanUtils() {
41 super();
42 }
43
44 // Boolean utilities
45 //--------------------------------------------------------------------------
46 /**
47 * <p>Negates the specified boolean.</p>
48 *
49 * <p>If {@code null} is passed in, {@code null} will be returned.</p>
50 *
51 * <p>NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean. </p>
52 *
53 * <pre>
54 * BooleanUtils.negate(Boolean.TRUE) = Boolean.FALSE;
55 * BooleanUtils.negate(Boolean.FALSE) = Boolean.TRUE;
56 * BooleanUtils.negate(null) = null;
57 * </pre>
58 *
59 * @param bool the Boolean to negate, may be null
60 * @return the negated Boolean, or {@code null} if {@code null} input
61 */
62 public static Boolean negate(Boolean bool) {
63 if (bool == null) {
64 return null;
65 }
66 return bool.booleanValue() ? Boolean.FALSE : Boolean.TRUE;
67 }
68
69 // boolean Boolean methods
70 //-----------------------------------------------------------------------
71 /**
72 * <p>Checks if a {@code Boolean} value is {@code true},
73 * handling {@code null} by returning {@code false}.</p>
74 *
75 * <pre>
76 * BooleanUtils.isTrue(Boolean.TRUE) = true
77 * BooleanUtils.isTrue(Boolean.FALSE) = false
78 * BooleanUtils.isTrue(null) = false
79 * </pre>
80 *
81 * @param bool the boolean to check, null returns {@code false}
82 * @return {@code true} only if the input is non-null and true
83 * @since 2.1
84 */
85 public static boolean isTrue(Boolean bool) {
86 return Boolean.TRUE.equals(bool);
87 }
88
89 /**
90 * <p>Checks if a {@code Boolean} value is <i>not</i> {@code true},
91 * handling {@code null} by returning {@code true}.</p>
92 *
93 * <pre>
94 * BooleanUtils.isNotTrue(Boolean.TRUE) = false
95 * BooleanUtils.isNotTrue(Boolean.FALSE) = true
96 * BooleanUtils.isNotTrue(null) = true
97 * </pre>
98 *
99 * @param bool the boolean to check, null returns {@code true}
100 * @return {@code true} if the input is null or false
101 * @since 2.3
102 */
103 public static boolean isNotTrue(Boolean bool) {
104 return !isTrue(bool);
105 }
106
107 /**
108 * <p>Checks if a {@code Boolean} value is {@code false},
109 * handling {@code null} by returning {@code false}.</p>
110 *
111 * <pre>
112 * BooleanUtils.isFalse(Boolean.TRUE) = false
113 * BooleanUtils.isFalse(Boolean.FALSE) = true
114 * BooleanUtils.isFalse(null) = false
115 * </pre>
116 *
117 * @param bool the boolean to check, null returns {@code false}
118 * @return {@code true} only if the input is non-null and false
119 * @since 2.1
120 */
121 public static boolean isFalse(Boolean bool) {
122 return Boolean.FALSE.equals(bool);
123 }
124
125 /**
126 * <p>Checks if a {@code Boolean} value is <i>not</i> {@code false},
127 * handling {@code null} by returning {@code true}.</p>
128 *
129 * <pre>
130 * BooleanUtils.isNotFalse(Boolean.TRUE) = true
131 * BooleanUtils.isNotFalse(Boolean.FALSE) = false
132 * BooleanUtils.isNotFalse(null) = true
133 * </pre>
134 *
135 * @param bool the boolean to check, null returns {@code true}
136 * @return {@code true} if the input is null or true
137 * @since 2.3
138 */
139 public static boolean isNotFalse(Boolean bool) {
140 return !isFalse(bool);
141 }
142
143 //-----------------------------------------------------------------------
144 /**
145 * <p>Converts a Boolean to a boolean handling {@code null}
146 * by returning {@code false}.</p>
147 *
148 * <pre>
149 * BooleanUtils.toBoolean(Boolean.TRUE) = true
150 * BooleanUtils.toBoolean(Boolean.FALSE) = false
151 * BooleanUtils.toBoolean(null) = false
152 * </pre>
153 *
154 * @param bool the boolean to convert
155 * @return {@code true} or {@code false}, {@code null} returns {@code false}
156 */
157 public static boolean toBoolean(Boolean bool) {
158 return bool != null && bool.booleanValue();
159 }
160
161 /**
162 * <p>Converts a Boolean to a boolean handling {@code null}.</p>
163 *
164 * <pre>
165 * BooleanUtils.toBooleanDefaultIfNull(Boolean.TRUE, false) = true
166 * BooleanUtils.toBooleanDefaultIfNull(Boolean.FALSE, true) = false
167 * BooleanUtils.toBooleanDefaultIfNull(null, true) = true
168 * </pre>
169 *
170 * @param bool the boolean to convert
171 * @param valueIfNull the boolean value to return if {@code null}
172 * @return {@code true} or {@code false}
173 */
174 public static boolean toBooleanDefaultIfNull(Boolean bool, boolean valueIfNull) {
175 if (bool == null) {
176 return valueIfNull;
177 }
178 return bool.booleanValue();
179 }
180
181 // Integer to Boolean methods
182 //-----------------------------------------------------------------------
183 /**
184 * <p>Converts an int to a boolean using the convention that {@code zero}
185 * is {@code false}.</p>
186 *
187 * <pre>
188 * BooleanUtils.toBoolean(0) = false
189 * BooleanUtils.toBoolean(1) = true
190 * BooleanUtils.toBoolean(2) = true
191 * </pre>
192 *
193 * @param value the int to convert
194 * @return {@code true} if non-zero, {@code false}
195 * if zero
196 */
197 public static boolean toBoolean(int value) {
198 return value != 0;
199 }
200
201 /**
202 * <p>Converts an int to a Boolean using the convention that {@code zero}
203 * is {@code false}.</p>
204 *
205 * <pre>
206 * BooleanUtils.toBoolean(0) = Boolean.FALSE
207 * BooleanUtils.toBoolean(1) = Boolean.TRUE
208 * BooleanUtils.toBoolean(2) = Boolean.TRUE
209 * </pre>
210 *
211 * @param value the int to convert
212 * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero,
213 * {@code null} if {@code null}
214 */
215 public static Boolean toBooleanObject(int value) {
216 return value == 0 ? Boolean.FALSE : Boolean.TRUE;
217 }
218
219 /**
220 * <p>Converts an Integer to a Boolean using the convention that {@code zero}
221 * is {@code false}.</p>
222 *
223 * <p>{@code null} will be converted to {@code null}.</p>
224 *
225 * <p>NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean. </p>
226 *
227 * <pre>
228 * BooleanUtils.toBoolean(Integer.valueOf(0)) = Boolean.FALSE
229 * BooleanUtils.toBoolean(Integer.valueOf(1)) = Boolean.TRUE
230 * BooleanUtils.toBoolean(Integer.valueOf(null)) = null
231 * </pre>
232 *
233 * @param value the Integer to convert
234 * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero,
235 * {@code null} if {@code null} input
236 */
237 public static Boolean toBooleanObject(Integer value) {
238 if (value == null) {
239 return null;
240 }
241 return value.intValue() == 0 ? Boolean.FALSE : Boolean.TRUE;
242 }
243
244 /**
245 * <p>Converts an int to a boolean specifying the conversion values.</p>
246 *
247 * <pre>
248 * BooleanUtils.toBoolean(0, 1, 0) = false
249 * BooleanUtils.toBoolean(1, 1, 0) = true
250 * BooleanUtils.toBoolean(2, 1, 2) = false
251 * BooleanUtils.toBoolean(2, 2, 0) = true
252 * </pre>
253 *
254 * @param value the Integer to convert
255 * @param trueValue the value to match for {@code true}
256 * @param falseValue the value to match for {@code false}
257 * @return {@code true} or {@code false}
258 * @throws IllegalArgumentException if no match
259 */
260 public static boolean toBoolean(int value, int trueValue, int falseValue) {
261 if (value == trueValue) {
262 return true;
263 }
264 if (value == falseValue) {
265 return false;
266 }
267 // no match
268 throw new IllegalArgumentException("The Integer did not match either specified value");
269 }
270
271 /**
272 * <p>Converts an Integer to a boolean specifying the conversion values.</p>
273 *
274 * <pre>
275 * BooleanUtils.toBoolean(Integer.valueOf(0), Integer.valueOf(1), Integer.valueOf(0)) = false
276 * BooleanUtils.toBoolean(Integer.valueOf(1), Integer.valueOf(1), Integer.valueOf(0)) = true
277 * BooleanUtils.toBoolean(Integer.valueOf(2), Integer.valueOf(1), Integer.valueOf(2)) = false
278 * BooleanUtils.toBoolean(Integer.valueOf(2), Integer.valueOf(2), Integer.valueOf(0)) = true
279 * BooleanUtils.toBoolean(null, null, Integer.valueOf(0)) = true
280 * </pre>
281 *
282 * @param value the Integer to convert
283 * @param trueValue the value to match for {@code true}, may be {@code null}
284 * @param falseValue the value to match for {@code false}, may be {@code null}
285 * @return {@code true} or {@code false}
286 * @throws IllegalArgumentException if no match
287 */
288 public static boolean toBoolean(Integer value, Integer trueValue, Integer falseValue) {
289 if (value == null) {
290 if (trueValue == null) {
291 return true;
292 }
293 if (falseValue == null) {
294 return false;
295 }
296 } else if (value.equals(trueValue)) {
297 return true;
298 } else if (value.equals(falseValue)) {
299 return false;
300 }
301 // no match
302 throw new IllegalArgumentException("The Integer did not match either specified value");
303 }
304
305 /**
306 * <p>Converts an int to a Boolean specifying the conversion values.</p>
307 *
308 * <p>NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean. </p>
309 *
310 * <pre>
311 * BooleanUtils.toBooleanObject(0, 0, 2, 3) = Boolean.TRUE
312 * BooleanUtils.toBooleanObject(2, 1, 2, 3) = Boolean.FALSE
313 * BooleanUtils.toBooleanObject(3, 1, 2, 3) = null
314 * </pre>
315 *
316 * @param value the Integer to convert
317 * @param trueValue the value to match for {@code true}
318 * @param falseValue the value to match for {@code false}
319 * @param nullValue the value to to match for {@code null}
320 * @return Boolean.TRUE, Boolean.FALSE, or {@code null}
321 * @throws IllegalArgumentException if no match
322 */
323 public static Boolean toBooleanObject(int value, int trueValue, int falseValue, int nullValue) {
324 if (value == trueValue) {
325 return Boolean.TRUE;
326 }
327 if (value == falseValue) {
328 return Boolean.FALSE;
329 }
330 if (value == nullValue) {
331 return null;
332 }
333 // no match
334 throw new IllegalArgumentException("The Integer did not match any specified value");
335 }
336
337 /**
338 * <p>Converts an Integer to a Boolean specifying the conversion values.</p>
339 *
340 * <p>NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean. </p>
341 *
342 * <pre>
343 * BooleanUtils.toBooleanObject(Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(2), Integer.valueOf(3)) = Boolean.TRUE
344 * BooleanUtils.toBooleanObject(Integer.valueOf(2), Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)) = Boolean.FALSE
345 * BooleanUtils.toBooleanObject(Integer.valueOf(3), Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)) = null
346 * </pre>
347 *
348 * @param value the Integer to convert
349 * @param trueValue the value to match for {@code true}, may be {@code null}
350 * @param falseValue the value to match for {@code false}, may be {@code null}
351 * @param nullValue the value to to match for {@code null}, may be {@code null}
352 * @return Boolean.TRUE, Boolean.FALSE, or {@code null}
353 * @throws IllegalArgumentException if no match
354 */
355 public static Boolean toBooleanObject(Integer value, Integer trueValue, Integer falseValue, Integer nullValue) {
356 if (value == null) {
357 if (trueValue == null) {
358 return Boolean.TRUE;
359 }
360 if (falseValue == null) {
361 return Boolean.FALSE;
362 }
363 if (nullValue == null) {
364 return null;
365 }
366 } else if (value.equals(trueValue)) {
367 return Boolean.TRUE;
368 } else if (value.equals(falseValue)) {
369 return Boolean.FALSE;
370 } else if (value.equals(nullValue)) {
371 return null;
372 }
373 // no match
374 throw new IllegalArgumentException("The Integer did not match any specified value");
375 }
376
377 // Boolean to Integer methods
378 //-----------------------------------------------------------------------
379 /**
380 * <p>Converts a boolean to an int using the convention that
381 * {@code zero} is {@code false}.</p>
382 *
383 * <pre>
384 * BooleanUtils.toInteger(true) = 1
385 * BooleanUtils.toInteger(false) = 0
386 * </pre>
387 *
388 * @param bool the boolean to convert
389 * @return one if {@code true}, zero if {@code false}
390 */
391 public static int toInteger(boolean bool) {
392 return bool ? 1 : 0;
393 }
394
395 /**
396 * <p>Converts a boolean to an Integer using the convention that
397 * {@code zero} is {@code false}.</p>
398 *
399 * <pre>
400 * BooleanUtils.toIntegerObject(true) = Integer.valueOf(1)
401 * BooleanUtils.toIntegerObject(false) = Integer.valueOf(0)
402 * </pre>
403 *
404 * @param bool the boolean to convert
405 * @return one if {@code true}, zero if {@code false}
406 */
407 public static Integer toIntegerObject(boolean bool) {
408 return bool ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO;
409 }
410
411 /**
412 * <p>Converts a Boolean to a Integer using the convention that
413 * {@code zero} is {@code false}.</p>
414 *
415 * <p>{@code null} will be converted to {@code null}.</p>
416 *
417 * <pre>
418 * BooleanUtils.toIntegerObject(Boolean.TRUE) = Integer.valueOf(1)
419 * BooleanUtils.toIntegerObject(Boolean.FALSE) = Integer.valueOf(0)
420 * </pre>
421 *
422 * @param bool the Boolean to convert
423 * @return one if Boolean.TRUE, zero if Boolean.FALSE, {@code null} if {@code null}
424 */
425 public static Integer toIntegerObject(Boolean bool) {
426 if (bool == null) {
427 return null;
428 }
429 return bool.booleanValue() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO;
430 }
431
432 /**
433 * <p>Converts a boolean to an int specifying the conversion values.</p>
434 *
435 * <pre>
436 * BooleanUtils.toInteger(true, 1, 0) = 1
437 * BooleanUtils.toInteger(false, 1, 0) = 0
438 * </pre>
439 *
440 * @param bool the to convert
441 * @param trueValue the value to return if {@code true}
442 * @param falseValue the value to return if {@code false}
443 * @return the appropriate value
444 */
445 public static int toInteger(boolean bool, int trueValue, int falseValue) {
446 return bool ? trueValue : falseValue;
447 }
448
449 /**
450 * <p>Converts a Boolean to an int specifying the conversion values.</p>
451 *
452 * <pre>
453 * BooleanUtils.toInteger(Boolean.TRUE, 1, 0, 2) = 1
454 * BooleanUtils.toInteger(Boolean.FALSE, 1, 0, 2) = 0
455 * BooleanUtils.toInteger(null, 1, 0, 2) = 2
456 * </pre>
457 *
458 * @param bool the Boolean to convert
459 * @param trueValue the value to return if {@code true}
460 * @param falseValue the value to return if {@code false}
461 * @param nullValue the value to return if {@code null}
462 * @return the appropriate value
463 */
464 public static int toInteger(Boolean bool, int trueValue, int falseValue, int nullValue) {
465 if (bool == null) {
466 return nullValue;
467 }
468 return bool.booleanValue() ? trueValue : falseValue;
469 }
470
471 /**
472 * <p>Converts a boolean to an Integer specifying the conversion values.</p>
473 *
474 * <pre>
475 * BooleanUtils.toIntegerObject(true, Integer.valueOf(1), Integer.valueOf(0)) = Integer.valueOf(1)
476 * BooleanUtils.toIntegerObject(false, Integer.valueOf(1), Integer.valueOf(0)) = Integer.valueOf(0)
477 * </pre>
478 *
479 * @param bool the to convert
480 * @param trueValue the value to return if {@code true}, may be {@code null}
481 * @param falseValue the value to return if {@code false}, may be {@code null}
482 * @return the appropriate value
483 */
484 public static Integer toIntegerObject(boolean bool, Integer trueValue, Integer falseValue) {
485 return bool ? trueValue : falseValue;
486 }
487
488 /**
489 * <p>Converts a Boolean to an Integer specifying the conversion values.</p>
490 *
491 * <pre>
492 * BooleanUtils.toIntegerObject(Boolean.TRUE, Integer.valueOf(1), Integer.valueOf(0), Integer.valueOf(2)) = Integer.valueOf(1)
493 * BooleanUtils.toIntegerObject(Boolean.FALSE, Integer.valueOf(1), Integer.valueOf(0), Integer.valueOf(2)) = Integer.valueOf(0)
494 * BooleanUtils.toIntegerObject(null, Integer.valueOf(1), Integer.valueOf(0), Integer.valueOf(2)) = Integer.valueOf(2)
495 * </pre>
496 *
497 * @param bool the Boolean to convert
498 * @param trueValue the value to return if {@code true}, may be {@code null}
499 * @param falseValue the value to return if {@code false}, may be {@code null}
500 * @param nullValue the value to return if {@code null}, may be {@code null}
501 * @return the appropriate value
502 */
503 public static Integer toIntegerObject(Boolean bool, Integer trueValue, Integer falseValue, Integer nullValue) {
504 if (bool == null) {
505 return nullValue;
506 }
507 return bool.booleanValue() ? trueValue : falseValue;
508 }
509
510 // String to Boolean methods
511 //-----------------------------------------------------------------------
512 /**
513 * <p>Converts a String to a Boolean.</p>
514 *
515 * <p>{@code 'true'}, {@code 'on'} or {@code 'yes'}
516 * (case insensitive) will return {@code true}.
517 * {@code 'false'}, {@code 'off'} or {@code 'no'}
518 * (case insensitive) will return {@code false}.
519 * Otherwise, {@code null} is returned.</p>
520 *
521 * <p>NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean. </p>
522 *
523 * <pre>
524 * BooleanUtils.toBooleanObject(null) = null
525 * BooleanUtils.toBooleanObject("true") = Boolean.TRUE
526 * BooleanUtils.toBooleanObject("false") = Boolean.FALSE
527 * BooleanUtils.toBooleanObject("on") = Boolean.TRUE
528 * BooleanUtils.toBooleanObject("ON") = Boolean.TRUE
529 * BooleanUtils.toBooleanObject("off") = Boolean.FALSE
530 * BooleanUtils.toBooleanObject("oFf") = Boolean.FALSE
531 * BooleanUtils.toBooleanObject("blue") = null
532 * </pre>
533 *
534 * @param str the String to check
535 * @return the Boolean value of the string, {@code null} if no match or {@code null} input
536 */
537 public static Boolean toBooleanObject(String str) {
538 // Previously used equalsIgnoreCase, which was fast for interned 'true'.
539 // Non interned 'true' matched 15 times slower.
540 //
541 // Optimisation provides same performance as before for interned 'true'.
542 // Similar performance for null, 'false', and other strings not length 2/3/4.
543 // 'true'/'TRUE' match 4 times slower, 'tRUE'/'True' 7 times slower.
544 if (str == "true") {
545 return Boolean.TRUE;
546 }
547 if (str == null) {
548 return null;
549 }
550 switch (str.length()) {
551 case 1: {
552 char ch0 = str.charAt(0);
553 if ((ch0 == 'y' || ch0 == 'Y') ||
554 (ch0 == 't' || ch0 == 'T')) {
555 return Boolean.TRUE;
556 }
557 if ((ch0 == 'n' || ch0 == 'N') ||
558 (ch0 == 'f' || ch0 == 'F')) {
559 return Boolean.FALSE;
560 }
561 break;
562 }
563 case 2: {
564 char ch0 = str.charAt(0);
565 char ch1 = str.charAt(1);
566 if ((ch0 == 'o' || ch0 == 'O') &&
567 (ch1 == 'n' || ch1 == 'N') ) {
568 return Boolean.TRUE;
569 }
570 if ((ch0 == 'n' || ch0 == 'N') &&
571 (ch1 == 'o' || ch1 == 'O') ) {
572 return Boolean.FALSE;
573 }
574 break;
575 }
576 case 3: {
577 char ch0 = str.charAt(0);
578 char ch1 = str.charAt(1);
579 char ch2 = str.charAt(2);
580 if ((ch0 == 'y' || ch0 == 'Y') &&
581 (ch1 == 'e' || ch1 == 'E') &&
582 (ch2 == 's' || ch2 == 'S') ) {
583 return Boolean.TRUE;
584 }
585 if ((ch0 == 'o' || ch0 == 'O') &&
586 (ch1 == 'f' || ch1 == 'F') &&
587 (ch2 == 'f' || ch2 == 'F') ) {
588 return Boolean.FALSE;
589 }
590 break;
591 }
592 case 4: {
593 char ch0 = str.charAt(0);
594 char ch1 = str.charAt(1);
595 char ch2 = str.charAt(2);
596 char ch3 = str.charAt(3);
597 if ((ch0 == 't' || ch0 == 'T') &&
598 (ch1 == 'r' || ch1 == 'R') &&
599 (ch2 == 'u' || ch2 == 'U') &&
600 (ch3 == 'e' || ch3 == 'E') ) {
601 return Boolean.TRUE;
602 }
603 break;
604 }
605 case 5: {
606 char ch0 = str.charAt(0);
607 char ch1 = str.charAt(1);
608 char ch2 = str.charAt(2);
609 char ch3 = str.charAt(3);
610 char ch4 = str.charAt(4);
611 if ((ch0 == 'f' || ch0 == 'F') &&
612 (ch1 == 'a' || ch1 == 'A') &&
613 (ch2 == 'l' || ch2 == 'L') &&
614 (ch3 == 's' || ch3 == 'S') &&
615 (ch4 == 'e' || ch4 == 'E') ) {
616 return Boolean.FALSE;
617 }
618 break;
619 }
620 }
621
622 return null;
623 }
624
625 /**
626 * <p>Converts a String to a Boolean throwing an exception if no match.</p>
627 *
628 * <p>NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean. </p>
629 *
630 * <pre>
631 * BooleanUtils.toBooleanObject("true", "true", "false", "null") = Boolean.TRUE
632 * BooleanUtils.toBooleanObject("false", "true", "false", "null") = Boolean.FALSE
633 * BooleanUtils.toBooleanObject("null", "true", "false", "null") = null
634 * </pre>
635 *
636 * @param str the String to check
637 * @param trueString the String to match for {@code true} (case sensitive), may be {@code null}
638 * @param falseString the String to match for {@code false} (case sensitive), may be {@code null}
639 * @param nullString the String to match for {@code null} (case sensitive), may be {@code null}
640 * @return the Boolean value of the string, {@code null} if either the String matches {@code nullString}
641 * or if {@code null} input and {@code nullString} is {@code null}
642 * @throws IllegalArgumentException if the String doesn't match
643 */
644 public static Boolean toBooleanObject(String str, String trueString, String falseString, String nullString) {
645 if (str == null) {
646 if (trueString == null) {
647 return Boolean.TRUE;
648 }
649 if (falseString == null) {
650 return Boolean.FALSE;
651 }
652 if (nullString == null) {
653 return null;
654 }
655 } else if (str.equals(trueString)) {
656 return Boolean.TRUE;
657 } else if (str.equals(falseString)) {
658 return Boolean.FALSE;
659 } else if (str.equals(nullString)) {
660 return null;
661 }
662 // no match
663 throw new IllegalArgumentException("The String did not match any specified value");
664 }
665
666 // String to boolean methods
667 //-----------------------------------------------------------------------
668 /**
669 * <p>Converts a String to a boolean (optimised for performance).</p>
670 *
671 * <p>{@code 'true'}, {@code 'on'} or {@code 'yes'}
672 * (case insensitive) will return {@code true}. Otherwise,
673 * {@code false} is returned.</p>
674 *
675 * <p>This method performs 4 times faster (JDK1.4) than
676 * {@code Boolean.valueOf(String)}. However, this method accepts
677 * 'on' and 'yes' as true values.
678 *
679 * <pre>
680 * BooleanUtils.toBoolean(null) = false
681 * BooleanUtils.toBoolean("true") = true
682 * BooleanUtils.toBoolean("TRUE") = true
683 * BooleanUtils.toBoolean("tRUe") = true
684 * BooleanUtils.toBoolean("on") = true
685 * BooleanUtils.toBoolean("yes") = true
686 * BooleanUtils.toBoolean("false") = false
687 * BooleanUtils.toBoolean("x gti") = false
688 * </pre>
689 *
690 * @param str the String to check
691 * @return the boolean value of the string, {@code false} if no match or the String is null
692 */
693 public static boolean toBoolean(String str) {
694 return toBooleanObject(str) == Boolean.TRUE;
695 }
696
697 /**
698 * <p>Converts a String to a Boolean throwing an exception if no match found.</p>
699 *
700 * <pre>
701 * BooleanUtils.toBoolean("true", "true", "false") = true
702 * BooleanUtils.toBoolean("false", "true", "false") = false
703 * </pre>
704 *
705 * @param str the String to check
706 * @param trueString the String to match for {@code true} (case sensitive), may be {@code null}
707 * @param falseString the String to match for {@code false} (case sensitive), may be {@code null}
708 * @return the boolean value of the string
709 * @throws IllegalArgumentException if the String doesn't match
710 */
711 public static boolean toBoolean(String str, String trueString, String falseString) {
712 if (str == trueString) {
713 return true;
714 } else if (str == falseString) {
715 return false;
716 } else if (str != null) {
717 if (str.equals(trueString)) {
718 return true;
719 } else if (str.equals(falseString)) {
720 return false;
721 }
722 }
723 // no match
724 throw new IllegalArgumentException("The String did not match either specified value");
725 }
726
727 // Boolean to String methods
728 //-----------------------------------------------------------------------
729 /**
730 * <p>Converts a Boolean to a String returning {@code 'true'},
731 * {@code 'false'}, or {@code null}.</p>
732 *
733 * <pre>
734 * BooleanUtils.toStringTrueFalse(Boolean.TRUE) = "true"
735 * BooleanUtils.toStringTrueFalse(Boolean.FALSE) = "false"
736 * BooleanUtils.toStringTrueFalse(null) = null;
737 * </pre>
738 *
739 * @param bool the Boolean to check
740 * @return {@code 'true'}, {@code 'false'}, or {@code null}
741 */
742 public static String toStringTrueFalse(Boolean bool) {
743 return toString(bool, "true", "false", null);
744 }
745
746 /**
747 * <p>Converts a Boolean to a String returning {@code 'on'},
748 * {@code 'off'}, or {@code null}.</p>
749 *
750 * <pre>
751 * BooleanUtils.toStringOnOff(Boolean.TRUE) = "on"
752 * BooleanUtils.toStringOnOff(Boolean.FALSE) = "off"
753 * BooleanUtils.toStringOnOff(null) = null;
754 * </pre>
755 *
756 * @param bool the Boolean to check
757 * @return {@code 'on'}, {@code 'off'}, or {@code null}
758 */
759 public static String toStringOnOff(Boolean bool) {
760 return toString(bool, "on", "off", null);
761 }
762
763 /**
764 * <p>Converts a Boolean to a String returning {@code 'yes'},
765 * {@code 'no'}, or {@code null}.</p>
766 *
767 * <pre>
768 * BooleanUtils.toStringYesNo(Boolean.TRUE) = "yes"
769 * BooleanUtils.toStringYesNo(Boolean.FALSE) = "no"
770 * BooleanUtils.toStringYesNo(null) = null;
771 * </pre>
772 *
773 * @param bool the Boolean to check
774 * @return {@code 'yes'}, {@code 'no'}, or {@code null}
775 */
776 public static String toStringYesNo(Boolean bool) {
777 return toString(bool, "yes", "no", null);
778 }
779
780 /**
781 * <p>Converts a Boolean to a String returning one of the input Strings.</p>
782 *
783 * <pre>
784 * BooleanUtils.toString(Boolean.TRUE, "true", "false", null) = "true"
785 * BooleanUtils.toString(Boolean.FALSE, "true", "false", null) = "false"
786 * BooleanUtils.toString(null, "true", "false", null) = null;
787 * </pre>
788 *
789 * @param bool the Boolean to check
790 * @param trueString the String to return if {@code true}, may be {@code null}
791 * @param falseString the String to return if {@code false}, may be {@code null}
792 * @param nullString the String to return if {@code null}, may be {@code null}
793 * @return one of the three input Strings
794 */
795 public static String toString(Boolean bool, String trueString, String falseString, String nullString) {
796 if (bool == null) {
797 return nullString;
798 }
799 return bool.booleanValue() ? trueString : falseString;
800 }
801
802 // boolean to String methods
803 //-----------------------------------------------------------------------
804 /**
805 * <p>Converts a boolean to a String returning {@code 'true'}
806 * or {@code 'false'}.</p>
807 *
808 * <pre>
809 * BooleanUtils.toStringTrueFalse(true) = "true"
810 * BooleanUtils.toStringTrueFalse(false) = "false"
811 * </pre>
812 *
813 * @param bool the Boolean to check
814 * @return {@code 'true'}, {@code 'false'}, or {@code null}
815 */
816 public static String toStringTrueFalse(boolean bool) {
817 return toString(bool, "true", "false");
818 }
819
820 /**
821 * <p>Converts a boolean to a String returning {@code 'on'}
822 * or {@code 'off'}.</p>
823 *
824 * <pre>
825 * BooleanUtils.toStringOnOff(true) = "on"
826 * BooleanUtils.toStringOnOff(false) = "off"
827 * </pre>
828 *
829 * @param bool the Boolean to check
830 * @return {@code 'on'}, {@code 'off'}, or {@code null}
831 */
832 public static String toStringOnOff(boolean bool) {
833 return toString(bool, "on", "off");
834 }
835
836 /**
837 * <p>Converts a boolean to a String returning {@code 'yes'}
838 * or {@code 'no'}.</p>
839 *
840 * <pre>
841 * BooleanUtils.toStringYesNo(true) = "yes"
842 * BooleanUtils.toStringYesNo(false) = "no"
843 * </pre>
844 *
845 * @param bool the Boolean to check
846 * @return {@code 'yes'}, {@code 'no'}, or {@code null}
847 */
848 public static String toStringYesNo(boolean bool) {
849 return toString(bool, "yes", "no");
850 }
851
852 /**
853 * <p>Converts a boolean to a String returning one of the input Strings.</p>
854 *
855 * <pre>
856 * BooleanUtils.toString(true, "true", "false") = "true"
857 * BooleanUtils.toString(false, "true", "false") = "false"
858 * </pre>
859 *
860 * @param bool the Boolean to check
861 * @param trueString the String to return if {@code true}, may be {@code null}
862 * @param falseString the String to return if {@code false}, may be {@code null}
863 * @return one of the two input Strings
864 */
865 public static String toString(boolean bool, String trueString, String falseString) {
866 return bool ? trueString : falseString;
867 }
868
869 // logical operations
870 // ----------------------------------------------------------------------
871 /**
872 * <p>Performs an and on a set of booleans.</p>
873 *
874 * <pre>
875 * BooleanUtils.and(true, true) = true
876 * BooleanUtils.and(false, false) = false
877 * BooleanUtils.and(true, false) = false
878 * BooleanUtils.and(true, true, false) = false
879 * BooleanUtils.and(true, true, true) = true
880 * </pre>
881 *
882 * @param array an array of {@code boolean}s
883 * @return {@code true} if the and is successful.
884 * @throws IllegalArgumentException if {@code array} is {@code null}
885 * @throws IllegalArgumentException if {@code array} is empty.
886 * @since 3.0.1
887 */
888 public static boolean and(boolean... array) {
889 // Validates input
890 if (array == null) {
891 throw new IllegalArgumentException("The Array must not be null");
892 }
893 if (array.length == 0) {
894 throw new IllegalArgumentException("Array is empty");
895 }
896 for (boolean element : array) {
897 if (!element) {
898 return false;
899 }
900 }
901 return true;
902 }
903
904 /**
905 * <p>Performs an and on an array of Booleans.</p>
906 *
907 * <pre>
908 * BooleanUtils.and(Boolean.TRUE, Boolean.TRUE) = Boolean.TRUE
909 * BooleanUtils.and(Boolean.FALSE, Boolean.FALSE) = Boolean.FALSE
910 * BooleanUtils.and(Boolean.TRUE, Boolean.FALSE) = Boolean.FALSE
911 * BooleanUtils.and(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE) = Boolean.TRUE
912 * BooleanUtils.and(Boolean.FALSE, Boolean.FALSE, Boolean.TRUE) = Boolean.FALSE
913 * BooleanUtils.and(Boolean.TRUE, Boolean.FALSE, Boolean.TRUE) = Boolean.FALSE
914 * </pre>
915 *
916 * @param array an array of {@code Boolean}s
917 * @return {@code true} if the and is successful.
918 * @throws IllegalArgumentException if {@code array} is {@code null}
919 * @throws IllegalArgumentException if {@code array} is empty.
920 * @throws IllegalArgumentException if {@code array} contains a {@code null}
921 * @since 3.0.1
922 */
923 public static Boolean and(Boolean... array) {
924 if (array == null) {
925 throw new IllegalArgumentException("The Array must not be null");
926 }
927 if (array.length == 0) {
928 throw new IllegalArgumentException("Array is empty");
929 }
930 try {
931 boolean[] primitive = ArrayUtils.toPrimitive(array);
932 return and(primitive) ? Boolean.TRUE : Boolean.FALSE;
933 } catch (NullPointerException ex) {
934 throw new IllegalArgumentException("The array must not contain any null elements");
935 }
936 }
937
938 /**
939 * <p>Performs an or on a set of booleans.</p>
940 *
941 * <pre>
942 * BooleanUtils.or(true, true) = true
943 * BooleanUtils.or(false, false) = false
944 * BooleanUtils.or(true, false) = true
945 * BooleanUtils.or(true, true, false) = true
946 * BooleanUtils.or(true, true, true) = true
947 * BooleanUtils.or(false, false, false) = false
948 * </pre>
949 *
950 * @param array an array of {@code boolean}s
951 * @return {@code true} if the or is successful.
952 * @throws IllegalArgumentException if {@code array} is {@code null}
953 * @throws IllegalArgumentException if {@code array} is empty.
954 * @since 3.0.1
955 */
956 public static boolean or(boolean... array) {
957 // Validates input
958 if (array == null) {
959 throw new IllegalArgumentException("The Array must not be null");
960 }
961 if (array.length == 0) {
962 throw new IllegalArgumentException("Array is empty");
963 }
964 for (boolean element : array) {
965 if (element) {
966 return true;
967 }
968 }
969 return false;
970 }
971
972 /**
973 * <p>Performs an or on an array of Booleans.</p>
974 *
975 * <pre>
976 * BooleanUtils.or(Boolean.TRUE, Boolean.TRUE) = Boolean.TRUE
977 * BooleanUtils.or(Boolean.FALSE, Boolean.FALSE) = Boolean.FALSE
978 * BooleanUtils.or(Boolean.TRUE, Boolean.FALSE) = Boolean.TRUE
979 * BooleanUtils.or(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE) = Boolean.TRUE
980 * BooleanUtils.or(Boolean.FALSE, Boolean.FALSE, Boolean.TRUE) = Boolean.TRUE
981 * BooleanUtils.or(Boolean.TRUE, Boolean.FALSE, Boolean.TRUE) = Boolean.TRUE
982 * BooleanUtils.or(Boolean.FALSE, Boolean.FALSE, Boolean.FALSE) = Boolean.FALSE
983 * </pre>
984 *
985 * @param array an array of {@code Boolean}s
986 * @return {@code true} if the or is successful.
987 * @throws IllegalArgumentException if {@code array} is {@code null}
988 * @throws IllegalArgumentException if {@code array} is empty.
989 * @throws IllegalArgumentException if {@code array} contains a {@code null}
990 * @since 3.0.1
991 */
992 public static Boolean or(Boolean... array) {
993 if (array == null) {
994 throw new IllegalArgumentException("The Array must not be null");
995 }
996 if (array.length == 0) {
997 throw new IllegalArgumentException("Array is empty");
998 }
999 try {
1000 boolean[] primitive = ArrayUtils.toPrimitive(array);
1001 return or(primitive) ? Boolean.TRUE : Boolean.FALSE;
1002 } catch (NullPointerException ex) {
1003 throw new IllegalArgumentException("The array must not contain any null elements");
1004 }
1005 }
1006
1007 /**
1008 * <p>Performs an xor on a set of booleans.</p>
1009 *
1010 * <pre>
1011 * BooleanUtils.xor(true, true) = false
1012 * BooleanUtils.xor(false, false) = false
1013 * BooleanUtils.xor(true, false) = true
1014 * BooleanUtils.xor(true, true) = false
1015 * BooleanUtils.xor(false, false) = false
1016 * BooleanUtils.xor(true, false) = true
1017 * </pre>
1018 *
1019 * @param array an array of {@code boolean}s
1020 * @return {@code true} if the xor is successful.
1021 * @throws IllegalArgumentException if {@code array} is {@code null}
1022 * @throws IllegalArgumentException if {@code array} is empty.
1023 */
1024 public static boolean xor(boolean... array) {
1025 // Validates input
1026 if (array == null) {
1027 throw new IllegalArgumentException("The Array must not be null");
1028 }
1029 if (array.length == 0) {
1030 throw new IllegalArgumentException("Array is empty");
1031 }
1032
1033 // Loops through array, comparing each item
1034 int trueCount = 0;
1035 for (boolean element : array) {
1036 // If item is true, and trueCount is < 1, increments count
1037 // Else, xor fails
1038 if (element) {
1039 if (trueCount < 1) {
1040 trueCount++;
1041 } else {
1042 return false;
1043 }
1044 }
1045 }
1046
1047 // Returns true if there was exactly 1 true item
1048 return trueCount == 1;
1049 }
1050
1051 /**
1052 * <p>Performs an xor on an array of Booleans.</p>
1053 *
1054 * <pre>
1055 * BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE }) = Boolean.FALSE
1056 * BooleanUtils.xor(new Boolean[] { Boolean.FALSE, Boolean.FALSE }) = Boolean.FALSE
1057 * BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE }) = Boolean.TRUE
1058 * </pre>
1059 *
1060 * @param array an array of {@code Boolean}s
1061 * @return {@code true} if the xor is successful.
1062 * @throws IllegalArgumentException if {@code array} is {@code null}
1063 * @throws IllegalArgumentException if {@code array} is empty.
1064 * @throws IllegalArgumentException if {@code array} contains a {@code null}
1065 */
1066 public static Boolean xor(Boolean... array) {
1067 if (array == null) {
1068 throw new IllegalArgumentException("The Array must not be null");
1069 }
1070 if (array.length == 0) {
1071 throw new IllegalArgumentException("Array is empty");
1072 }
1073 try {
1074 boolean[] primitive = ArrayUtils.toPrimitive(array);
1075 return xor(primitive) ? Boolean.TRUE : Boolean.FALSE;
1076 } catch (NullPointerException ex) {
1077 throw new IllegalArgumentException("The array must not contain any null elements");
1078 }
1079 }
1080
1081 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3;
18
19 import java.nio.charset.Charset;
20 import java.nio.charset.IllegalCharsetNameException;
21
22 /**
23 * <p>Character encoding names required of every implementation of the Java platform.</p>
24 *
25 * <p>According to <a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/package-summary.html#charenc">JRE character
26 * encoding names</a>:</p>
27 *
28 * <p><cite>Every implementation of the Java platform is required to support the following character encodings.
29 * Consult the release documentation for your implementation to see if any other encodings are supported.
30 * </cite></p>
31 *
32 * @see <a href="http://download.oracle.com/javase/1.3/docs/guide/intl/encoding.doc.html">JRE character encoding names</a>
33 * @since 2.1
34 * @version $Id: CharEncoding.java 1088899 2011-04-05 05:31:27Z bayard $
35 */
36 public class CharEncoding {
37
38 /**
39 * <p>ISO Latin Alphabet #1, also known as ISO-LATIN-1.</p>
40 *
41 * <p>Every implementation of the Java platform is required to support this character encoding.</p>
42 */
43 public static final String ISO_8859_1 = "ISO-8859-1";
44
45 /**
46 * <p>Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block
47 * of the Unicode character set.</p>
48 *
49 * <p>Every implementation of the Java platform is required to support this character encoding.</p>
50 */
51 public static final String US_ASCII = "US-ASCII";
52
53 /**
54 * <p>Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial
55 * byte-order mark (either order accepted on input, big-endian used on output).</p>
56 *
57 * <p>Every implementation of the Java platform is required to support this character encoding.</p>
58 */
59 public static final String UTF_16 = "UTF-16";
60
61 /**
62 * <p>Sixteen-bit Unicode Transformation Format, big-endian byte order.</p>
63 *
64 * <p>Every implementation of the Java platform is required to support this character encoding.</p>
65 */
66 public static final String UTF_16BE = "UTF-16BE";
67
68 /**
69 * <p>Sixteen-bit Unicode Transformation Format, little-endian byte order.</p>
70 *
71 * <p>Every implementation of the Java platform is required to support this character encoding.</p>
72 */
73 public static final String UTF_16LE = "UTF-16LE";
74
75 /**
76 * <p>Eight-bit Unicode Transformation Format.</p>
77 *
78 * <p>Every implementation of the Java platform is required to support this character encoding.</p>
79 */
80 public static final String UTF_8 = "UTF-8";
81
82 //-----------------------------------------------------------------------
83 /**
84 * <p>Returns whether the named charset is supported.</p>
85 *
86 * <p>This is similar to <a
87 * href="http://download.oracle.com/javase/1.4.2/docs/api/java/nio/charset/Charset.html#isSupported%28java.lang.String%29">
88 * java.nio.charset.Charset.isSupported(String)</a> but handles more formats</p>
89 *
90 * @param name the name of the requested charset; may be either a canonical name or an alias, null returns false
91 * @return {@code true} if the charset is available in the current Java virtual machine
92 */
93 public static boolean isSupported(String name) {
94 if (name == null) {
95 return false;
96 }
97 try {
98 return Charset.isSupported(name);
99 } catch (IllegalCharsetNameException ex) {
100 return false;
101 }
102 }
103
104 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.io.Serializable;
19 import java.util.Iterator;
20 import java.util.NoSuchElementException;
21
22 /**
23 * <p>A contiguous range of characters, optionally negated.</p>
24 *
25 * <p>Instances are immutable.</p>
26 *
27 * <p>#ThreadSafe#</p>
28 * @since 1.0
29 * @version $Id: CharRange.java 1090427 2011-04-08 20:17:10Z bayard $
30 */
31 // TODO: This is no longer public and will be removed later as CharSet is moved
32 // to depend on Range.
33 final class CharRange implements Iterable<Character>, Serializable {
34
35 /**
36 * Required for serialization support. Lang version 2.0.
37 *
38 * @see java.io.Serializable
39 */
40 private static final long serialVersionUID = 8270183163158333422L;
41
42 /** The first character, inclusive, in the range. */
43 private final char start;
44 /** The last character, inclusive, in the range. */
45 private final char end;
46 /** True if the range is everything except the characters specified. */
47 private final boolean negated;
48
49 /** Cached toString. */
50 private transient String iToString;
51
52 /**
53 * <p>Constructs a {@code CharRange} over a set of characters,
54 * optionally negating the range.</p>
55 *
56 * <p>A negated range includes everything except that defined by the
57 * start and end characters.</p>
58 *
59 * <p>If start and end are in the wrong order, they are reversed.
60 * Thus {@code a-e} is the same as {@code e-a}.</p>
61 *
62 * @param start first character, inclusive, in this range
63 * @param end last character, inclusive, in this range
64 * @param negated true to express everything except the range
65 */
66 private CharRange(char start, char end, boolean negated) {
67 super();
68 if (start > end) {
69 char temp = start;
70 start = end;
71 end = temp;
72 }
73
74 this.start = start;
75 this.end = end;
76 this.negated = negated;
77 }
78
79 /**
80 * <p>Constructs a {@code CharRange} over a single character.</p>
81 *
82 * @param ch only character in this range
83 * @return the new CharRange object
84 * @see CharRange#CharRange(char, char, boolean)
85 * @since 2.5
86 */
87 public static CharRange is(char ch) {
88 return new CharRange(ch, ch, false);
89 }
90
91 /**
92 * <p>Constructs a negated {@code CharRange} over a single character.</p>
93 *
94 * @param ch only character in this range
95 * @return the new CharRange object
96 * @see CharRange#CharRange(char, char, boolean)
97 * @since 2.5
98 */
99 public static CharRange isNot(char ch) {
100 return new CharRange(ch, ch, true);
101 }
102
103 /**
104 * <p>Constructs a {@code CharRange} over a set of characters.</p>
105 *
106 * @param start first character, inclusive, in this range
107 * @param end last character, inclusive, in this range
108 * @return the new CharRange object
109 * @see CharRange#CharRange(char, char, boolean)
110 * @since 2.5
111 */
112 public static CharRange isIn(char start, char end) {
113 return new CharRange(start, end, false);
114 }
115
116 /**
117 * <p>Constructs a negated {@code CharRange} over a set of characters.</p>
118 *
119 * @param start first character, inclusive, in this range
120 * @param end last character, inclusive, in this range
121 * @return the new CharRange object
122 * @see CharRange#CharRange(char, char, boolean)
123 * @since 2.5
124 */
125 public static CharRange isNotIn(char start, char end) {
126 return new CharRange(start, end, true);
127 }
128
129 // Accessors
130 //-----------------------------------------------------------------------
131 /**
132 * <p>Gets the start character for this character range.</p>
133 *
134 * @return the start char (inclusive)
135 */
136 public char getStart() {
137 return this.start;
138 }
139
140 /**
141 * <p>Gets the end character for this character range.</p>
142 *
143 * @return the end char (inclusive)
144 */
145 public char getEnd() {
146 return this.end;
147 }
148
149 /**
150 * <p>Is this {@code CharRange} negated.</p>
151 *
152 * <p>A negated range includes everything except that defined by the
153 * start and end characters.</p>
154 *
155 * @return {@code true} if negated
156 */
157 public boolean isNegated() {
158 return negated;
159 }
160
161 // Contains
162 //-----------------------------------------------------------------------
163 /**
164 * <p>Is the character specified contained in this range.</p>
165 *
166 * @param ch the character to check
167 * @return {@code true} if this range contains the input character
168 */
169 public boolean contains(char ch) {
170 return (ch >= start && ch <= end) != negated;
171 }
172
173 /**
174 * <p>Are all the characters of the passed in range contained in
175 * this range.</p>
176 *
177 * @param range the range to check against
178 * @return {@code true} if this range entirely contains the input range
179 * @throws IllegalArgumentException if {@code null} input
180 */
181 public boolean contains(CharRange range) {
182 if (range == null) {
183 throw new IllegalArgumentException("The Range must not be null");
184 }
185 if (negated) {
186 if (range.negated) {
187 return start >= range.start && end <= range.end;
188 }
189 return range.end < start || range.start > end;
190 }
191 if (range.negated) {
192 return start == 0 && end == Character.MAX_VALUE;
193 }
194 return start <= range.start && end >= range.end;
195 }
196
197 // Basics
198 //-----------------------------------------------------------------------
199 /**
200 * <p>Compares two CharRange objects, returning true if they represent
201 * exactly the same range of characters defined in the same way.</p>
202 *
203 * @param obj the object to compare to
204 * @return true if equal
205 */
206 @Override
207 public boolean equals(Object obj) {
208 if (obj == this) {
209 return true;
210 }
211 if (obj instanceof CharRange == false) {
212 return false;
213 }
214 CharRange other = (CharRange) obj;
215 return start == other.start && end == other.end && negated == other.negated;
216 }
217
218 /**
219 * <p>Gets a hashCode compatible with the equals method.</p>
220 *
221 * @return a suitable hashCode
222 */
223 @Override
224 public int hashCode() {
225 return 83 + start + 7 * end + (negated ? 1 : 0);
226 }
227
228 /**
229 * <p>Gets a string representation of the character range.</p>
230 *
231 * @return string representation of this range
232 */
233 @Override
234 public String toString() {
235 if (iToString == null) {
236 StringBuilder buf = new StringBuilder(4);
237 if (isNegated()) {
238 buf.append('^');
239 }
240 buf.append(start);
241 if (start != end) {
242 buf.append('-');
243 buf.append(end);
244 }
245 iToString = buf.toString();
246 }
247 return iToString;
248 }
249
250 // Expansions
251 //-----------------------------------------------------------------------
252 /**
253 * <p>Returns an iterator which can be used to walk through the characters described by this range.</p>
254 *
255 * <p>#NotThreadSafe# the iterator is not threadsafe</p>
256 * @return an iterator to the chars represented by this range
257 * @since 2.5
258 */
259 public Iterator<Character> iterator() {
260 return new CharacterIterator(this);
261 }
262
263 /**
264 * Character {@link Iterator}.
265 * <p>#NotThreadSafe#</p>
266 */
267 private static class CharacterIterator implements Iterator<Character> {
268 /** The current character */
269 private char current;
270
271 private final CharRange range;
272 private boolean hasNext;
273
274 /**
275 * Construct a new iterator for the character range.
276 *
277 * @param r The character range
278 */
279 private CharacterIterator(CharRange r) {
280 range = r;
281 hasNext = true;
282
283 if (range.negated) {
284 if (range.start == 0) {
285 if (range.end == Character.MAX_VALUE) {
286 // This range is an empty set
287 hasNext = false;
288 } else {
289 current = (char) (range.end + 1);
290 }
291 } else {
292 current = 0;
293 }
294 } else {
295 current = range.start;
296 }
297 }
298
299 /**
300 * Prepare the next character in the range.
301 */
302 private void prepareNext() {
303 if (range.negated) {
304 if (current == Character.MAX_VALUE) {
305 hasNext = false;
306 } else if (current + 1 == range.start) {
307 if (range.end == Character.MAX_VALUE) {
308 hasNext = false;
309 } else {
310 current = (char) (range.end + 1);
311 }
312 } else {
313 current = (char) (current + 1);
314 }
315 } else if (current < range.end) {
316 current = (char) (current + 1);
317 } else {
318 hasNext = false;
319 }
320 }
321
322 /**
323 * Has the iterator not reached the end character yet?
324 *
325 * @return {@code true} if the iterator has yet to reach the character date
326 */
327 public boolean hasNext() {
328 return hasNext;
329 }
330
331 /**
332 * Return the next character in the iteration
333 *
334 * @return {@code Character} for the next character
335 */
336 public Character next() {
337 if (hasNext == false) {
338 throw new NoSuchElementException();
339 }
340 char cur = current;
341 prepareNext();
342 return Character.valueOf(cur);
343 }
344
345 /**
346 * Always throws UnsupportedOperationException.
347 *
348 * @throws UnsupportedOperationException
349 * @see java.util.Iterator#remove()
350 */
351 public void remove() {
352 throw new UnsupportedOperationException();
353 }
354 }
355 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 /**
19 * <p>Operations on {@link java.lang.CharSequence} that are
20 * {@code null} safe.</p>
21 *
22 * @see java.lang.CharSequence
23 * @since 3.0
24 * @version $Id: CharSequenceUtils.java 1091471 2011-04-12 15:34:43Z scolebourne $
25 */
26 public class CharSequenceUtils {
27
28 /**
29 * <p>{@code CharSequenceUtils} instances should NOT be constructed in
30 * standard programming. </p>
31 *
32 * <p>This constructor is public to permit tools that require a JavaBean
33 * instance to operate.</p>
34 */
35 public CharSequenceUtils() {
36 super();
37 }
38
39 //-----------------------------------------------------------------------
40 /**
41 * <p>Returns a new {@code CharSequence} that is a subsequence of this
42 * sequence starting with the {@code char} value at the specified index.</p>
43 *
44 * <p>This provides the {@code CharSequence} equivalent to {@link String#substring(int)}.
45 * The length (in {@code char}) of the returned sequence is {@code length() - start},
46 * so if {@code start == end} then an empty sequence is returned.</p>
47 *
48 * @param cs the specified subsequence, null returns null
49 * @param start the start index, inclusive, valid
50 * @return a new subsequence, may be null
51 * @throws IndexOutOfBoundsException if {@code start} is negative or if
52 * {@code start} is greater than {@code length()}
53 */
54 public static CharSequence subSequence(CharSequence cs, int start) {
55 return cs == null ? null : cs.subSequence(start, cs.length());
56 }
57
58 //-----------------------------------------------------------------------
59 /**
60 * <p>Finds the first index in the {@code CharSequence} that matches the
61 * specified character.</p>
62 *
63 * @param cs the {@code CharSequence} to be processed, not null
64 * @param searchChar the char to be searched for
65 * @param start the start index, negative starts at the string start
66 * @return the index where the search char was found, -1 if not found
67 */
68 static int indexOf(CharSequence cs, int searchChar, int start) {
69 if (cs instanceof String) {
70 return ((String) cs).indexOf(searchChar, start);
71 } else {
72 int sz = cs.length();
73 if (start < 0) {
74 start = 0;
75 }
76 for (int i = start; i < sz; i++) {
77 if (cs.charAt(i) == searchChar) {
78 return i;
79 }
80 }
81 return -1;
82 }
83 }
84
85 /**
86 * Used by the indexOf(CharSequence methods) as a green implementation of indexOf.
87 *
88 * @param cs the {@code CharSequence} to be processed
89 * @param searchChar the {@code CharSequence} to be searched for
90 * @param start the start index
91 * @return the index where the search sequence was found
92 */
93 static int indexOf(CharSequence cs, CharSequence searchChar, int start) {
94 return cs.toString().indexOf(searchChar.toString(), start);
95 // if (cs instanceof String && searchChar instanceof String) {
96 // // TODO: Do we assume searchChar is usually relatively small;
97 // // If so then calling toString() on it is better than reverting to
98 // // the green implementation in the else block
99 // return ((String) cs).indexOf((String) searchChar, start);
100 // } else {
101 // // TODO: Implement rather than convert to String
102 // return cs.toString().indexOf(searchChar.toString(), start);
103 // }
104 }
105
106 /**
107 * <p>Finds the last index in the {@code CharSequence} that matches the
108 * specified character.</p>
109 *
110 * @param cs the {@code CharSequence} to be processed
111 * @param searchChar the char to be searched for
112 * @param start the start index, negative returns -1, beyond length starts at end
113 * @return the index where the search char was found, -1 if not found
114 */
115 static int lastIndexOf(CharSequence cs, int searchChar, int start) {
116 if (cs instanceof String) {
117 return ((String) cs).lastIndexOf(searchChar, start);
118 } else {
119 int sz = cs.length();
120 if (start < 0) {
121 return -1;
122 }
123 if (start >= sz) {
124 start = sz - 1;
125 }
126 for (int i = start; i >= 0; --i) {
127 if (cs.charAt(i) == searchChar) {
128 return i;
129 }
130 }
131 return -1;
132 }
133 }
134
135 /**
136 * Used by the lastIndexOf(CharSequence methods) as a green implementation of lastIndexOf
137 *
138 * @param cs the {@code CharSequence} to be processed
139 * @param searchChar the {@code CharSequence} to be searched for
140 * @param start the start index
141 * @return the index where the search sequence was found
142 */
143 static int lastIndexOf(CharSequence cs, CharSequence searchChar, int start) {
144 return cs.toString().lastIndexOf(searchChar.toString(), start);
145 // if (cs instanceof String && searchChar instanceof String) {
146 // // TODO: Do we assume searchChar is usually relatively small;
147 // // If so then calling toString() on it is better than reverting to
148 // // the green implementation in the else block
149 // return ((String) cs).lastIndexOf((String) searchChar, start);
150 // } else {
151 // // TODO: Implement rather than convert to String
152 // return cs.toString().lastIndexOf(searchChar.toString(), start);
153 // }
154 }
155
156 /**
157 * Green implementation of toCharArray.
158 *
159 * @param cs the {@code CharSequence} to be processed
160 * @return the resulting char array
161 */
162 static char[] toCharArray(CharSequence cs) {
163 if (cs instanceof String) {
164 return ((String) cs).toCharArray();
165 } else {
166 int sz = cs.length();
167 char[] array = new char[cs.length()];
168 for (int i = 0; i < sz; i++) {
169 array[i] = cs.charAt(i);
170 }
171 return array;
172 }
173 }
174
175 /**
176 * Green implementation of regionMatches.
177 *
178 * @param cs the {@code CharSequence} to be processed
179 * @param ignoreCase whether or not to be case insensitive
180 * @param thisStart the index to start on the {@code cs} CharSequence
181 * @param substring the {@code CharSequence} to be looked for
182 * @param start the index to start on the {@code substring} CharSequence
183 * @param length character length of the region
184 * @return whether the region matched
185 */
186 static boolean regionMatches(CharSequence cs, boolean ignoreCase, int thisStart,
187 CharSequence substring, int start, int length) {
188 if (cs instanceof String && substring instanceof String) {
189 return ((String) cs).regionMatches(ignoreCase, thisStart, ((String) substring), start, length);
190 } else {
191 // TODO: Implement rather than convert to String
192 return cs.toString().regionMatches(ignoreCase, thisStart, substring.toString(), start, length);
193 }
194 }
195
196 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.io.Serializable;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.Map;
23 import java.util.Set;
24
25 /**
26 * <p>A set of characters.</p>
27 *
28 * <p>Instances are immutable, but instances of subclasses may not be.</p>
29 *
30 * <p>#ThreadSafe#</p>
31 * @since 1.0
32 * @version $Id: CharSet.java 1090427 2011-04-08 20:17:10Z bayard $
33 */
34 public class CharSet implements Serializable {
35
36 /**
37 * Required for serialization support. Lang version 2.0.
38 *
39 * @see java.io.Serializable
40 */
41 private static final long serialVersionUID = 5947847346149275958L;
42
43 /**
44 * A CharSet defining no characters.
45 * @since 2.0
46 */
47 public static final CharSet EMPTY = new CharSet((String) null);
48
49 /**
50 * A CharSet defining ASCII alphabetic characters "a-zA-Z".
51 * @since 2.0
52 */
53 public static final CharSet ASCII_ALPHA = new CharSet("a-zA-Z");
54
55 /**
56 * A CharSet defining ASCII alphabetic characters "a-z".
57 * @since 2.0
58 */
59 public static final CharSet ASCII_ALPHA_LOWER = new CharSet("a-z");
60
61 /**
62 * A CharSet defining ASCII alphabetic characters "A-Z".
63 * @since 2.0
64 */
65 public static final CharSet ASCII_ALPHA_UPPER = new CharSet("A-Z");
66
67 /**
68 * A CharSet defining ASCII alphabetic characters "0-9".
69 * @since 2.0
70 */
71 public static final CharSet ASCII_NUMERIC = new CharSet("0-9");
72
73 /**
74 * A Map of the common cases used in the factory.
75 * Subclasses can add more common patterns if desired
76 * @since 2.0
77 */
78 protected static final Map<String, CharSet> COMMON = Collections.synchronizedMap(new HashMap<String, CharSet>());
79
80 static {
81 COMMON.put(null, EMPTY);
82 COMMON.put("", EMPTY);
83 COMMON.put("a-zA-Z", ASCII_ALPHA);
84 COMMON.put("A-Za-z", ASCII_ALPHA);
85 COMMON.put("a-z", ASCII_ALPHA_LOWER);
86 COMMON.put("A-Z", ASCII_ALPHA_UPPER);
87 COMMON.put("0-9", ASCII_NUMERIC);
88 }
89
90 /** The set of CharRange objects. */
91 private final Set<CharRange> set = Collections.synchronizedSet(new HashSet<CharRange>());
92
93 //-----------------------------------------------------------------------
94 /**
95 * <p>Factory method to create a new CharSet using a special syntax.</p>
96 *
97 * <ul>
98 * <li>{@code null} or empty string ("")
99 * - set containing no characters</li>
100 * <li>Single character, such as "a"
101 * - set containing just that character</li>
102 * <li>Multi character, such as "a-e"
103 * - set containing characters from one character to the other</li>
104 * <li>Negated, such as "^a" or "^a-e"
105 * - set containing all characters except those defined</li>
106 * <li>Combinations, such as "abe-g"
107 * - set containing all the characters from the individual sets</li>
108 * </ul>
109 *
110 * <p>The matching order is:</p>
111 * <ol>
112 * <li>Negated multi character range, such as "^a-e"
113 * <li>Ordinary multi character range, such as "a-e"
114 * <li>Negated single character, such as "^a"
115 * <li>Ordinary single character, such as "a"
116 * </ol>
117 * <p>Matching works left to right. Once a match is found the
118 * search starts again from the next character.</p>
119 *
120 * <p>If the same range is defined twice using the same syntax, only
121 * one range will be kept.
122 * Thus, "a-ca-c" creates only one range of "a-c".</p>
123 *
124 * <p>If the start and end of a range are in the wrong order,
125 * they are reversed. Thus "a-e" is the same as "e-a".
126 * As a result, "a-ee-a" would create only one range,
127 * as the "a-e" and "e-a" are the same.</p>
128 *
129 * <p>The set of characters represented is the union of the specified ranges.</p>
130 *
131 * <p>All CharSet objects returned by this method will be immutable.</p>
132 *
133 * @param setStrs Strings to merge into the set, may be null
134 * @return a CharSet instance
135 * @since 2.4
136 */
137 public static CharSet getInstance(String... setStrs) {
138 if (setStrs == null) {
139 return null;
140 }
141 if (setStrs.length == 1) {
142 CharSet common = COMMON.get(setStrs[0]);
143 if (common != null) {
144 return common;
145 }
146 }
147 return new CharSet(setStrs);
148 }
149
150 //-----------------------------------------------------------------------
151 /**
152 * <p>Constructs a new CharSet using the set syntax.
153 * Each string is merged in with the set.</p>
154 *
155 * @param set Strings to merge into the initial set
156 * @throws NullPointerException if set is {@code null}
157 */
158 protected CharSet(String... set) {
159 super();
160 int sz = set.length;
161 for (int i = 0; i < sz; i++) {
162 add(set[i]);
163 }
164 }
165
166 //-----------------------------------------------------------------------
167 /**
168 * <p>Add a set definition string to the {@code CharSet}.</p>
169 *
170 * @param str set definition string
171 */
172 protected void add(String str) {
173 if (str == null) {
174 return;
175 }
176
177 int len = str.length();
178 int pos = 0;
179 while (pos < len) {
180 int remainder = (len - pos);
181 if (remainder >= 4 && str.charAt(pos) == '^' && str.charAt(pos + 2) == '-') {
182 // negated range
183 set.add(CharRange.isNotIn(str.charAt(pos + 1), str.charAt(pos + 3)));
184 pos += 4;
185 } else if (remainder >= 3 && str.charAt(pos + 1) == '-') {
186 // range
187 set.add(CharRange.isIn(str.charAt(pos), str.charAt(pos + 2)));
188 pos += 3;
189 } else if (remainder >= 2 && str.charAt(pos) == '^') {
190 // negated char
191 set.add(CharRange.isNot(str.charAt(pos + 1)));
192 pos += 2;
193 } else {
194 // char
195 set.add(CharRange.is(str.charAt(pos)));
196 pos += 1;
197 }
198 }
199 }
200
201 //-----------------------------------------------------------------------
202 /**
203 * <p>Gets the internal set as an array of CharRange objects.</p>
204 *
205 * @return an array of immutable CharRange objects
206 * @since 2.0
207 */
208 // NOTE: This is no longer public as CharRange is no longer a public class.
209 // It may be replaced when CharSet moves to Range.
210 /*public*/ CharRange[] getCharRanges() {
211 return set.toArray(new CharRange[set.size()]);
212 }
213
214 //-----------------------------------------------------------------------
215 /**
216 * <p>Does the {@code CharSet} contain the specified
217 * character {@code ch}.</p>
218 *
219 * @param ch the character to check for
220 * @return {@code true} if the set contains the characters
221 */
222 public boolean contains(char ch) {
223 for (CharRange range : set) {
224 if (range.contains(ch)) {
225 return true;
226 }
227 }
228 return false;
229 }
230
231 // Basics
232 //-----------------------------------------------------------------------
233 /**
234 * <p>Compares two {@code CharSet} objects, returning true if they represent
235 * exactly the same set of characters defined in the same way.</p>
236 *
237 * <p>The two sets {@code abc} and {@code a-c} are <i>not</i>
238 * equal according to this method.</p>
239 *
240 * @param obj the object to compare to
241 * @return true if equal
242 * @since 2.0
243 */
244 @Override
245 public boolean equals(Object obj) {
246 if (obj == this) {
247 return true;
248 }
249 if (obj instanceof CharSet == false) {
250 return false;
251 }
252 CharSet other = (CharSet) obj;
253 return set.equals(other.set);
254 }
255
256 /**
257 * <p>Gets a hash code compatible with the equals method.</p>
258 *
259 * @return a suitable hash code
260 * @since 2.0
261 */
262 @Override
263 public int hashCode() {
264 return 89 + set.hashCode();
265 }
266
267 /**
268 * <p>Gets a string representation of the set.</p>
269 *
270 * @return string representation of the set
271 */
272 @Override
273 public String toString() {
274 return set.toString();
275 }
276
277 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 /**
19 * <p>Operations on {@code CharSet} instances.</p>
20 *
21 * <p>This class handles {@code null} input gracefully.
22 * An exception will not be thrown for a {@code null} input.
23 * Each method documents its behaviour in more detail.</p>
24 *
25 * <p>#ThreadSafe#</p>
26 * @see CharSet
27 * @since 1.0
28 * @version $Id: CharSetUtils.java 1144916 2011-07-10 17:50:21Z ggregory $
29 */
30 public class CharSetUtils {
31
32 /**
33 * <p>CharSetUtils instances should NOT be constructed in standard programming.
34 * Instead, the class should be used as {@code CharSetUtils.evaluateSet(null);}.</p>
35 *
36 * <p>This constructor is public to permit tools that require a JavaBean instance
37 * to operate.</p>
38 */
39 public CharSetUtils() {
40 super();
41 }
42
43 // Squeeze
44 //-----------------------------------------------------------------------
45 /**
46 * <p>Squeezes any repetitions of a character that is mentioned in the
47 * supplied set.</p>
48 *
49 * <pre>
50 * CharSetUtils.squeeze(null, *) = null
51 * CharSetUtils.squeeze("", *) = ""
52 * CharSetUtils.squeeze(*, null) = *
53 * CharSetUtils.squeeze(*, "") = *
54 * CharSetUtils.squeeze("hello", "k-p") = "helo"
55 * CharSetUtils.squeeze("hello", "a-e") = "hello"
56 * </pre>
57 *
58 * @see CharSet#getInstance(java.lang.String...) for set-syntax.
59 * @param str the string to squeeze, may be null
60 * @param set the character set to use for manipulation, may be null
61 * @return the modified String, {@code null} if null string input
62 */
63 public static String squeeze(String str, String... set) {
64 if (StringUtils.isEmpty(str) || deepEmpty(set)) {
65 return str;
66 }
67 CharSet chars = CharSet.getInstance(set);
68 StringBuilder buffer = new StringBuilder(str.length());
69 char[] chrs = str.toCharArray();
70 int sz = chrs.length;
71 char lastChar = ' ';
72 char ch = ' ';
73 for (int i = 0; i < sz; i++) {
74 ch = chrs[i];
75 // Compare with contains() last for performance.
76 if (ch == lastChar && i != 0 && chars.contains(ch)) {
77 continue;
78 }
79 buffer.append(ch);
80 lastChar = ch;
81 }
82 return buffer.toString();
83 }
84
85 // Count
86 //-----------------------------------------------------------------------
87 /**
88 * <p>Takes an argument in set-syntax, see evaluateSet,
89 * and returns the number of characters present in the specified string.</p>
90 *
91 * <pre>
92 * CharSetUtils.count(null, *) = 0
93 * CharSetUtils.count("", *) = 0
94 * CharSetUtils.count(*, null) = 0
95 * CharSetUtils.count(*, "") = 0
96 * CharSetUtils.count("hello", "k-p") = 3
97 * CharSetUtils.count("hello", "a-e") = 1
98 * </pre>
99 *
100 * @see CharSet#getInstance(java.lang.String...) for set-syntax.
101 * @param str String to count characters in, may be null
102 * @param set String[] set of characters to count, may be null
103 * @return the character count, zero if null string input
104 */
105 public static int count(String str, String... set) {
106 if (StringUtils.isEmpty(str) || deepEmpty(set)) {
107 return 0;
108 }
109 CharSet chars = CharSet.getInstance(set);
110 int count = 0;
111 for (char c : str.toCharArray()) {
112 if (chars.contains(c)) {
113 count++;
114 }
115 }
116 return count;
117 }
118
119 // Keep
120 //-----------------------------------------------------------------------
121 /**
122 * <p>Takes an argument in set-syntax, see evaluateSet,
123 * and keeps any of characters present in the specified string.</p>
124 *
125 * <pre>
126 * CharSetUtils.keep(null, *) = null
127 * CharSetUtils.keep("", *) = ""
128 * CharSetUtils.keep(*, null) = ""
129 * CharSetUtils.keep(*, "") = ""
130 * CharSetUtils.keep("hello", "hl") = "hll"
131 * CharSetUtils.keep("hello", "le") = "ell"
132 * </pre>
133 *
134 * @see CharSet#getInstance(java.lang.String...) for set-syntax.
135 * @param str String to keep characters from, may be null
136 * @param set String[] set of characters to keep, may be null
137 * @return the modified String, {@code null} if null string input
138 * @since 2.0
139 */
140 public static String keep(String str, String... set) {
141 if (str == null) {
142 return null;
143 }
144 if (str.length() == 0 || deepEmpty(set)) {
145 return "";
146 }
147 return modify(str, set, true);
148 }
149
150 // Delete
151 //-----------------------------------------------------------------------
152 /**
153 * <p>Takes an argument in set-syntax, see evaluateSet,
154 * and deletes any of characters present in the specified string.</p>
155 *
156 * <pre>
157 * CharSetUtils.delete(null, *) = null
158 * CharSetUtils.delete("", *) = ""
159 * CharSetUtils.delete(*, null) = *
160 * CharSetUtils.delete(*, "") = *
161 * CharSetUtils.delete("hello", "hl") = "eo"
162 * CharSetUtils.delete("hello", "le") = "ho"
163 * </pre>
164 *
165 * @see CharSet#getInstance(java.lang.String...) for set-syntax.
166 * @param str String to delete characters from, may be null
167 * @param set String[] set of characters to delete, may be null
168 * @return the modified String, {@code null} if null string input
169 */
170 public static String delete(String str, String... set) {
171 if (StringUtils.isEmpty(str) || deepEmpty(set)) {
172 return str;
173 }
174 return modify(str, set, false);
175 }
176
177 //-----------------------------------------------------------------------
178 /**
179 * Implementation of delete and keep
180 *
181 * @param str String to modify characters within
182 * @param set String[] set of characters to modify
183 * @param expect whether to evaluate on match, or non-match
184 * @return the modified String, not null
185 */
186 private static String modify(String str, String[] set, boolean expect) {
187 CharSet chars = CharSet.getInstance(set);
188 StringBuilder buffer = new StringBuilder(str.length());
189 char[] chrs = str.toCharArray();
190 int sz = chrs.length;
191 for(int i=0; i<sz; i++) {
192 if(chars.contains(chrs[i]) == expect) {
193 buffer.append(chrs[i]);
194 }
195 }
196 return buffer.toString();
197 }
198
199 /**
200 * Determines whether or not all the Strings in an array are
201 * empty or not.
202 *
203 * @param strings String[] whose elements are being checked for emptiness
204 * @return whether or not the String is empty
205 */
206 private static boolean deepEmpty(String[] strings) {
207 if (strings != null) {
208 for (String s : strings) {
209 if (StringUtils.isNotEmpty(s)) {
210 return false;
211 }
212 }
213 }
214 return true;
215 }
216 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 /**
19 * <p>Operations on char primitives and Character objects.</p>
20 *
21 * <p>This class tries to handle {@code null} input gracefully.
22 * An exception will not be thrown for a {@code null} input.
23 * Each method documents its behaviour in more detail.</p>
24 *
25 * <p>#ThreadSafe#</p>
26 * @since 2.1
27 * @version $Id: CharUtils.java 1153229 2011-08-02 18:04:51Z ggregory $
28 */
29 public class CharUtils {
30
31 private static final String CHAR_STRING =
32 "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" +
33 "\b\t\n\u000b\f\r\u000e\u000f" +
34 "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" +
35 "\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f" +
36 "\u0020\u0021\"\u0023\u0024\u0025\u0026\u0027" +
37 "\u0028\u0029\u002a\u002b\u002c\u002d\u002e\u002f" +
38 "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037" +
39 "\u0038\u0039\u003a\u003b\u003c\u003d\u003e\u003f" +
40 "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047" +
41 "\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f" +
42 "\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057" +
43 "\u0058\u0059\u005a\u005b\\\u005d\u005e\u005f" +
44 "\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067" +
45 "\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f" +
46 "\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077" +
47 "\u0078\u0079\u007a\u007b\u007c\u007d\u007e\u007f";
48
49 private static final String[] CHAR_STRING_ARRAY = new String[128];
50
51 /**
52 * {@code \u000a} linefeed LF ('\n').
53 *
54 * @see <a href="http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#101089">JLF: Escape Sequences
55 * for Character and String Literals</a>
56 * @since 2.2
57 */
58 public static final char LF = '\n';
59
60 /**
61 * {@code \u000d} carriage return CR ('\r').
62 *
63 * @see <a href="http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#101089">JLF: Escape Sequences
64 * for Character and String Literals</a>
65 * @since 2.2
66 */
67 public static final char CR = '\r';
68
69
70 static {
71 for (int i = 127; i >= 0; i--) {
72 CHAR_STRING_ARRAY[i] = CHAR_STRING.substring(i, i + 1);
73 }
74 }
75
76 /**
77 * <p>{@code CharUtils} instances should NOT be constructed in standard programming.
78 * Instead, the class should be used as {@code CharUtils.toString('c');}.</p>
79 *
80 * <p>This constructor is public to permit tools that require a JavaBean instance
81 * to operate.</p>
82 */
83 public CharUtils() {
84 super();
85 }
86
87 //-----------------------------------------------------------------------
88 /**
89 * <p>Converts the character to a Character.</p>
90 *
91 * <p>For ASCII 7 bit characters, this uses a cache that will return the
92 * same Character object each time.</p>
93 *
94 * <pre>
95 * CharUtils.toCharacterObject(' ') = ' '
96 * CharUtils.toCharacterObject('A') = 'A'
97 * </pre>
98 *
99 * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127.
100 * @param ch the character to convert
101 * @return a Character of the specified character
102 */
103 @Deprecated
104 public static Character toCharacterObject(char ch) {
105 return Character.valueOf(ch);
106 }
107
108 /**
109 * <p>Converts the String to a Character using the first character, returning
110 * null for empty Strings.</p>
111 *
112 * <p>For ASCII 7 bit characters, this uses a cache that will return the
113 * same Character object each time.</p>
114 *
115 * <pre>
116 * CharUtils.toCharacterObject(null) = null
117 * CharUtils.toCharacterObject("") = null
118 * CharUtils.toCharacterObject("A") = 'A'
119 * CharUtils.toCharacterObject("BA") = 'B'
120 * </pre>
121 *
122 * @param str the character to convert
123 * @return the Character value of the first letter of the String
124 */
125 public static Character toCharacterObject(String str) {
126 if (StringUtils.isEmpty(str)) {
127 return null;
128 }
129 return Character.valueOf(str.charAt(0));
130 }
131
132 //-----------------------------------------------------------------------
133 /**
134 * <p>Converts the Character to a char throwing an exception for {@code null}.</p>
135 *
136 * <pre>
137 * CharUtils.toChar(' ') = ' '
138 * CharUtils.toChar('A') = 'A'
139 * CharUtils.toChar(null) throws IllegalArgumentException
140 * </pre>
141 *
142 * @param ch the character to convert
143 * @return the char value of the Character
144 * @throws IllegalArgumentException if the Character is null
145 */
146 public static char toChar(Character ch) {
147 if (ch == null) {
148 throw new IllegalArgumentException("The Character must not be null");
149 }
150 return ch.charValue();
151 }
152
153 /**
154 * <p>Converts the Character to a char handling {@code null}.</p>
155 *
156 * <pre>
157 * CharUtils.toChar(null, 'X') = 'X'
158 * CharUtils.toChar(' ', 'X') = ' '
159 * CharUtils.toChar('A', 'X') = 'A'
160 * </pre>
161 *
162 * @param ch the character to convert
163 * @param defaultValue the value to use if the Character is null
164 * @return the char value of the Character or the default if null
165 */
166 public static char toChar(Character ch, char defaultValue) {
167 if (ch == null) {
168 return defaultValue;
169 }
170 return ch.charValue();
171 }
172
173 //-----------------------------------------------------------------------
174 /**
175 * <p>Converts the String to a char using the first character, throwing
176 * an exception on empty Strings.</p>
177 *
178 * <pre>
179 * CharUtils.toChar("A") = 'A'
180 * CharUtils.toChar("BA") = 'B'
181 * CharUtils.toChar(null) throws IllegalArgumentException
182 * CharUtils.toChar("") throws IllegalArgumentException
183 * </pre>
184 *
185 * @param str the character to convert
186 * @return the char value of the first letter of the String
187 * @throws IllegalArgumentException if the String is empty
188 */
189 public static char toChar(String str) {
190 if (StringUtils.isEmpty(str)) {
191 throw new IllegalArgumentException("The String must not be empty");
192 }
193 return str.charAt(0);
194 }
195
196 /**
197 * <p>Converts the String to a char using the first character, defaulting
198 * the value on empty Strings.</p>
199 *
200 * <pre>
201 * CharUtils.toChar(null, 'X') = 'X'
202 * CharUtils.toChar("", 'X') = 'X'
203 * CharUtils.toChar("A", 'X') = 'A'
204 * CharUtils.toChar("BA", 'X') = 'B'
205 * </pre>
206 *
207 * @param str the character to convert
208 * @param defaultValue the value to use if the Character is null
209 * @return the char value of the first letter of the String or the default if null
210 */
211 public static char toChar(String str, char defaultValue) {
212 if (StringUtils.isEmpty(str)) {
213 return defaultValue;
214 }
215 return str.charAt(0);
216 }
217
218 //-----------------------------------------------------------------------
219 /**
220 * <p>Converts the character to the Integer it represents, throwing an
221 * exception if the character is not numeric.</p>
222 *
223 * <p>This method coverts the char '1' to the int 1 and so on.</p>
224 *
225 * <pre>
226 * CharUtils.toIntValue('3') = 3
227 * CharUtils.toIntValue('A') throws IllegalArgumentException
228 * </pre>
229 *
230 * @param ch the character to convert
231 * @return the int value of the character
232 * @throws IllegalArgumentException if the character is not ASCII numeric
233 */
234 public static int toIntValue(char ch) {
235 if (isAsciiNumeric(ch) == false) {
236 throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'");
237 }
238 return ch - 48;
239 }
240
241 /**
242 * <p>Converts the character to the Integer it represents, throwing an
243 * exception if the character is not numeric.</p>
244 *
245 * <p>This method coverts the char '1' to the int 1 and so on.</p>
246 *
247 * <pre>
248 * CharUtils.toIntValue('3', -1) = 3
249 * CharUtils.toIntValue('A', -1) = -1
250 * </pre>
251 *
252 * @param ch the character to convert
253 * @param defaultValue the default value to use if the character is not numeric
254 * @return the int value of the character
255 */
256 public static int toIntValue(char ch, int defaultValue) {
257 if (isAsciiNumeric(ch) == false) {
258 return defaultValue;
259 }
260 return ch - 48;
261 }
262
263 /**
264 * <p>Converts the character to the Integer it represents, throwing an
265 * exception if the character is not numeric.</p>
266 *
267 * <p>This method coverts the char '1' to the int 1 and so on.</p>
268 *
269 * <pre>
270 * CharUtils.toIntValue('3') = 3
271 * CharUtils.toIntValue(null) throws IllegalArgumentException
272 * CharUtils.toIntValue('A') throws IllegalArgumentException
273 * </pre>
274 *
275 * @param ch the character to convert, not null
276 * @return the int value of the character
277 * @throws IllegalArgumentException if the Character is not ASCII numeric or is null
278 */
279 public static int toIntValue(Character ch) {
280 if (ch == null) {
281 throw new IllegalArgumentException("The character must not be null");
282 }
283 return toIntValue(ch.charValue());
284 }
285
286 /**
287 * <p>Converts the character to the Integer it represents, throwing an
288 * exception if the character is not numeric.</p>
289 *
290 * <p>This method coverts the char '1' to the int 1 and so on.</p>
291 *
292 * <pre>
293 * CharUtils.toIntValue(null, -1) = -1
294 * CharUtils.toIntValue('3', -1) = 3
295 * CharUtils.toIntValue('A', -1) = -1
296 * </pre>
297 *
298 * @param ch the character to convert
299 * @param defaultValue the default value to use if the character is not numeric
300 * @return the int value of the character
301 */
302 public static int toIntValue(Character ch, int defaultValue) {
303 if (ch == null) {
304 return defaultValue;
305 }
306 return toIntValue(ch.charValue(), defaultValue);
307 }
308
309 //-----------------------------------------------------------------------
310 /**
311 * <p>Converts the character to a String that contains the one character.</p>
312 *
313 * <p>For ASCII 7 bit characters, this uses a cache that will return the
314 * same String object each time.</p>
315 *
316 * <pre>
317 * CharUtils.toString(' ') = " "
318 * CharUtils.toString('A') = "A"
319 * </pre>
320 *
321 * @param ch the character to convert
322 * @return a String containing the one specified character
323 */
324 public static String toString(char ch) {
325 if (ch < 128) {
326 return CHAR_STRING_ARRAY[ch];
327 }
328 return new String(new char[] {ch});
329 }
330
331 /**
332 * <p>Converts the character to a String that contains the one character.</p>
333 *
334 * <p>For ASCII 7 bit characters, this uses a cache that will return the
335 * same String object each time.</p>
336 *
337 * <p>If {@code null} is passed in, {@code null} will be returned.</p>
338 *
339 * <pre>
340 * CharUtils.toString(null) = null
341 * CharUtils.toString(' ') = " "
342 * CharUtils.toString('A') = "A"
343 * </pre>
344 *
345 * @param ch the character to convert
346 * @return a String containing the one specified character
347 */
348 public static String toString(Character ch) {
349 if (ch == null) {
350 return null;
351 }
352 return toString(ch.charValue());
353 }
354
355 //--------------------------------------------------------------------------
356 /**
357 * <p>Converts the string to the Unicode format '\u0020'.</p>
358 *
359 * <p>This format is the Java source code format.</p>
360 *
361 * <pre>
362 * CharUtils.unicodeEscaped(' ') = "\u0020"
363 * CharUtils.unicodeEscaped('A') = "\u0041"
364 * </pre>
365 *
366 * @param ch the character to convert
367 * @return the escaped Unicode string
368 */
369 public static String unicodeEscaped(char ch) {
370 if (ch < 0x10) {
371 return "\\u000" + Integer.toHexString(ch);
372 } else if (ch < 0x100) {
373 return "\\u00" + Integer.toHexString(ch);
374 } else if (ch < 0x1000) {
375 return "\\u0" + Integer.toHexString(ch);
376 }
377 return "\\u" + Integer.toHexString(ch);
378 }
379
380 /**
381 * <p>Converts the string to the Unicode format '\u0020'.</p>
382 *
383 * <p>This format is the Java source code format.</p>
384 *
385 * <p>If {@code null} is passed in, {@code null} will be returned.</p>
386 *
387 * <pre>
388 * CharUtils.unicodeEscaped(null) = null
389 * CharUtils.unicodeEscaped(' ') = "\u0020"
390 * CharUtils.unicodeEscaped('A') = "\u0041"
391 * </pre>
392 *
393 * @param ch the character to convert, may be null
394 * @return the escaped Unicode string, null if null input
395 */
396 public static String unicodeEscaped(Character ch) {
397 if (ch == null) {
398 return null;
399 }
400 return unicodeEscaped(ch.charValue());
401 }
402
403 //--------------------------------------------------------------------------
404 /**
405 * <p>Checks whether the character is ASCII 7 bit.</p>
406 *
407 * <pre>
408 * CharUtils.isAscii('a') = true
409 * CharUtils.isAscii('A') = true
410 * CharUtils.isAscii('3') = true
411 * CharUtils.isAscii('-') = true
412 * CharUtils.isAscii('\n') = true
413 * CharUtils.isAscii('&copy;') = false
414 * </pre>
415 *
416 * @param ch the character to check
417 * @return true if less than 128
418 */
419 public static boolean isAscii(char ch) {
420 return ch < 128;
421 }
422
423 /**
424 * <p>Checks whether the character is ASCII 7 bit printable.</p>
425 *
426 * <pre>
427 * CharUtils.isAsciiPrintable('a') = true
428 * CharUtils.isAsciiPrintable('A') = true
429 * CharUtils.isAsciiPrintable('3') = true
430 * CharUtils.isAsciiPrintable('-') = true
431 * CharUtils.isAsciiPrintable('\n') = false
432 * CharUtils.isAsciiPrintable('&copy;') = false
433 * </pre>
434 *
435 * @param ch the character to check
436 * @return true if between 32 and 126 inclusive
437 */
438 public static boolean isAsciiPrintable(char ch) {
439 return ch >= 32 && ch < 127;
440 }
441
442 /**
443 * <p>Checks whether the character is ASCII 7 bit control.</p>
444 *
445 * <pre>
446 * CharUtils.isAsciiControl('a') = false
447 * CharUtils.isAsciiControl('A') = false
448 * CharUtils.isAsciiControl('3') = false
449 * CharUtils.isAsciiControl('-') = false
450 * CharUtils.isAsciiControl('\n') = true
451 * CharUtils.isAsciiControl('&copy;') = false
452 * </pre>
453 *
454 * @param ch the character to check
455 * @return true if less than 32 or equals 127
456 */
457 public static boolean isAsciiControl(char ch) {
458 return ch < 32 || ch == 127;
459 }
460
461 /**
462 * <p>Checks whether the character is ASCII 7 bit alphabetic.</p>
463 *
464 * <pre>
465 * CharUtils.isAsciiAlpha('a') = true
466 * CharUtils.isAsciiAlpha('A') = true
467 * CharUtils.isAsciiAlpha('3') = false
468 * CharUtils.isAsciiAlpha('-') = false
469 * CharUtils.isAsciiAlpha('\n') = false
470 * CharUtils.isAsciiAlpha('&copy;') = false
471 * </pre>
472 *
473 * @param ch the character to check
474 * @return true if between 65 and 90 or 97 and 122 inclusive
475 */
476 public static boolean isAsciiAlpha(char ch) {
477 return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
478 }
479
480 /**
481 * <p>Checks whether the character is ASCII 7 bit alphabetic upper case.</p>
482 *
483 * <pre>
484 * CharUtils.isAsciiAlphaUpper('a') = false
485 * CharUtils.isAsciiAlphaUpper('A') = true
486 * CharUtils.isAsciiAlphaUpper('3') = false
487 * CharUtils.isAsciiAlphaUpper('-') = false
488 * CharUtils.isAsciiAlphaUpper('\n') = false
489 * CharUtils.isAsciiAlphaUpper('&copy;') = false
490 * </pre>
491 *
492 * @param ch the character to check
493 * @return true if between 65 and 90 inclusive
494 */
495 public static boolean isAsciiAlphaUpper(char ch) {
496 return ch >= 'A' && ch <= 'Z';
497 }
498
499 /**
500 * <p>Checks whether the character is ASCII 7 bit alphabetic lower case.</p>
501 *
502 * <pre>
503 * CharUtils.isAsciiAlphaLower('a') = true
504 * CharUtils.isAsciiAlphaLower('A') = false
505 * CharUtils.isAsciiAlphaLower('3') = false
506 * CharUtils.isAsciiAlphaLower('-') = false
507 * CharUtils.isAsciiAlphaLower('\n') = false
508 * CharUtils.isAsciiAlphaLower('&copy;') = false
509 * </pre>
510 *
511 * @param ch the character to check
512 * @return true if between 97 and 122 inclusive
513 */
514 public static boolean isAsciiAlphaLower(char ch) {
515 return ch >= 'a' && ch <= 'z';
516 }
517
518 /**
519 * <p>Checks whether the character is ASCII 7 bit numeric.</p>
520 *
521 * <pre>
522 * CharUtils.isAsciiNumeric('a') = false
523 * CharUtils.isAsciiNumeric('A') = false
524 * CharUtils.isAsciiNumeric('3') = true
525 * CharUtils.isAsciiNumeric('-') = false
526 * CharUtils.isAsciiNumeric('\n') = false
527 * CharUtils.isAsciiNumeric('&copy;') = false
528 * </pre>
529 *
530 * @param ch the character to check
531 * @return true if between 48 and 57 inclusive
532 */
533 public static boolean isAsciiNumeric(char ch) {
534 return ch >= '0' && ch <= '9';
535 }
536
537 /**
538 * <p>Checks whether the character is ASCII 7 bit numeric.</p>
539 *
540 * <pre>
541 * CharUtils.isAsciiAlphanumeric('a') = true
542 * CharUtils.isAsciiAlphanumeric('A') = true
543 * CharUtils.isAsciiAlphanumeric('3') = true
544 * CharUtils.isAsciiAlphanumeric('-') = false
545 * CharUtils.isAsciiAlphanumeric('\n') = false
546 * CharUtils.isAsciiAlphanumeric('&copy;') = false
547 * </pre>
548 *
549 * @param ch the character to check
550 * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
551 */
552 public static boolean isAsciiAlphanumeric(char ch) {
553 return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9');
554 }
555
556 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.lang.reflect.Method;
19 import java.lang.reflect.Modifier;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.LinkedHashSet;
24 import java.util.List;
25 import java.util.Map;
26
27
28 /**
29 * <p>Operates on classes without using reflection.</p>
30 *
31 * <p>This class handles invalid {@code null} inputs as best it can.
32 * Each method documents its behaviour in more detail.</p>
33 *
34 * <p>The notion of a {@code canonical name} includes the human
35 * readable name for the type, for example {@code int[]}. The
36 * non-canonical method variants work with the JVM names, such as
37 * {@code [I}. </p>
38 *
39 * @since 2.0
40 * @version $Id: ClassUtils.java 1145035 2011-07-11 06:09:39Z bayard $
41 */
42 public class ClassUtils {
43
44 /**
45 * <p>The package separator character: <code>'&#x2e;' == {@value}</code>.</p>
46 */
47 public static final char PACKAGE_SEPARATOR_CHAR = '.';
48
49 /**
50 * <p>The package separator String: {@code "&#x2e;"}.</p>
51 */
52 public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
53
54 /**
55 * <p>The inner class separator character: <code>'$' == {@value}</code>.</p>
56 */
57 public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
58
59 /**
60 * <p>The inner class separator String: {@code "$"}.</p>
61 */
62 public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
63
64 /**
65 * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}.
66 */
67 private static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<Class<?>, Class<?>>();
68 static {
69 primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
70 primitiveWrapperMap.put(Byte.TYPE, Byte.class);
71 primitiveWrapperMap.put(Character.TYPE, Character.class);
72 primitiveWrapperMap.put(Short.TYPE, Short.class);
73 primitiveWrapperMap.put(Integer.TYPE, Integer.class);
74 primitiveWrapperMap.put(Long.TYPE, Long.class);
75 primitiveWrapperMap.put(Double.TYPE, Double.class);
76 primitiveWrapperMap.put(Float.TYPE, Float.class);
77 primitiveWrapperMap.put(Void.TYPE, Void.TYPE);
78 }
79
80 /**
81 * Maps wrapper {@code Class}es to their corresponding primitive types.
82 */
83 private static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<Class<?>, Class<?>>();
84 static {
85 for (Class<?> primitiveClass : primitiveWrapperMap.keySet()) {
86 Class<?> wrapperClass = primitiveWrapperMap.get(primitiveClass);
87 if (!primitiveClass.equals(wrapperClass)) {
88 wrapperPrimitiveMap.put(wrapperClass, primitiveClass);
89 }
90 }
91 }
92
93 /**
94 * Maps a primitive class name to its corresponding abbreviation used in array class names.
95 */
96 private static final Map<String, String> abbreviationMap = new HashMap<String, String>();
97
98 /**
99 * Maps an abbreviation used in array class names to corresponding primitive class name.
100 */
101 private static final Map<String, String> reverseAbbreviationMap = new HashMap<String, String>();
102
103 /**
104 * Add primitive type abbreviation to maps of abbreviations.
105 *
106 * @param primitive Canonical name of primitive type
107 * @param abbreviation Corresponding abbreviation of primitive type
108 */
109 private static void addAbbreviation(String primitive, String abbreviation) {
110 abbreviationMap.put(primitive, abbreviation);
111 reverseAbbreviationMap.put(abbreviation, primitive);
112 }
113
114 /**
115 * Feed abbreviation maps
116 */
117 static {
118 addAbbreviation("int", "I");
119 addAbbreviation("boolean", "Z");
120 addAbbreviation("float", "F");
121 addAbbreviation("long", "J");
122 addAbbreviation("short", "S");
123 addAbbreviation("byte", "B");
124 addAbbreviation("double", "D");
125 addAbbreviation("char", "C");
126 }
127
128 /**
129 * <p>ClassUtils instances should NOT be constructed in standard programming.
130 * Instead, the class should be used as
131 * {@code ClassUtils.getShortClassName(cls)}.</p>
132 *
133 * <p>This constructor is public to permit tools that require a JavaBean
134 * instance to operate.</p>
135 */
136 public ClassUtils() {
137 super();
138 }
139
140 // Short class name
141 // ----------------------------------------------------------------------
142 /**
143 * <p>Gets the class name minus the package name for an {@code Object}.</p>
144 *
145 * @param object the class to get the short name for, may be null
146 * @param valueIfNull the value to return if null
147 * @return the class name of the object without the package name, or the null value
148 */
149 public static String getShortClassName(Object object, String valueIfNull) {
150 if (object == null) {
151 return valueIfNull;
152 }
153 return getShortClassName(object.getClass());
154 }
155
156 /**
157 * <p>Gets the class name minus the package name from a {@code Class}.</p>
158 *
159 * <p>Consider using the Java 5 API {@link Class#getSimpleName()} instead.
160 * The one known difference is that this code will return {@code "Map.Entry"} while
161 * the {@code java.lang.Class} variant will simply return {@code "Entry"}. </p>
162 *
163 * @param cls the class to get the short name for.
164 * @return the class name without the package name or an empty string
165 */
166 public static String getShortClassName(Class<?> cls) {
167 if (cls == null) {
168 return StringUtils.EMPTY;
169 }
170 return getShortClassName(cls.getName());
171 }
172
173 /**
174 * <p>Gets the class name minus the package name from a String.</p>
175 *
176 * <p>The string passed in is assumed to be a class name - it is not checked.</p>
177
178 * <p>Note that this method differs from Class.getSimpleName() in that this will
179 * return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply
180 * return {@code "Entry"}. </p>
181 *
182 * @param className the className to get the short name for
183 * @return the class name of the class without the package name or an empty string
184 */
185 public static String getShortClassName(String className) {
186 if (className == null) {
187 return StringUtils.EMPTY;
188 }
189 if (className.length() == 0) {
190 return StringUtils.EMPTY;
191 }
192
193 StringBuilder arrayPrefix = new StringBuilder();
194
195 // Handle array encoding
196 if (className.startsWith("[")) {
197 while (className.charAt(0) == '[') {
198 className = className.substring(1);
199 arrayPrefix.append("[]");
200 }
201 // Strip Object type encoding
202 if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
203 className = className.substring(1, className.length() - 1);
204 }
205 }
206
207 if (reverseAbbreviationMap.containsKey(className)) {
208 className = reverseAbbreviationMap.get(className);
209 }
210
211 int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
212 int innerIdx = className.indexOf(
213 INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1);
214 String out = className.substring(lastDotIdx + 1);
215 if (innerIdx != -1) {
216 out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR);
217 }
218 return out + arrayPrefix;
219 }
220
221 /**
222 * <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
223 *
224 * @param cls the class for which to get the simple name.
225 * @return the simple class name.
226 * @since 3.0
227 * @see Class#getSimpleName()
228 */
229 public static String getSimpleName(Class<?> cls) {
230 if (cls == null) {
231 return StringUtils.EMPTY;
232 }
233 return cls.getSimpleName();
234 }
235
236 /**
237 * <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
238 *
239 * @param object the object for which to get the simple class name.
240 * @param valueIfNull the value to return if <code>object</code> is <code>null</code>
241 * @return the simple class name.
242 * @since 3.0
243 * @see Class#getSimpleName()
244 */
245 public static String getSimpleName(Object object, String valueIfNull) {
246 if (object == null) {
247 return valueIfNull;
248 }
249 return getSimpleName(object.getClass());
250 }
251
252 // Package name
253 // ----------------------------------------------------------------------
254 /**
255 * <p>Gets the package name of an {@code Object}.</p>
256 *
257 * @param object the class to get the package name for, may be null
258 * @param valueIfNull the value to return if null
259 * @return the package name of the object, or the null value
260 */
261 public static String getPackageName(Object object, String valueIfNull) {
262 if (object == null) {
263 return valueIfNull;
264 }
265 return getPackageName(object.getClass());
266 }
267
268 /**
269 * <p>Gets the package name of a {@code Class}.</p>
270 *
271 * @param cls the class to get the package name for, may be {@code null}.
272 * @return the package name or an empty string
273 */
274 public static String getPackageName(Class<?> cls) {
275 if (cls == null) {
276 return StringUtils.EMPTY;
277 }
278 return getPackageName(cls.getName());
279 }
280
281 /**
282 * <p>Gets the package name from a {@code String}.</p>
283 *
284 * <p>The string passed in is assumed to be a class name - it is not checked.</p>
285 * <p>If the class is unpackaged, return an empty string.</p>
286 *
287 * @param className the className to get the package name for, may be {@code null}
288 * @return the package name or an empty string
289 */
290 public static String getPackageName(String className) {
291 if (className == null || className.length() == 0) {
292 return StringUtils.EMPTY;
293 }
294
295 // Strip array encoding
296 while (className.charAt(0) == '[') {
297 className = className.substring(1);
298 }
299 // Strip Object type encoding
300 if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
301 className = className.substring(1);
302 }
303
304 int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
305 if (i == -1) {
306 return StringUtils.EMPTY;
307 }
308 return className.substring(0, i);
309 }
310
311 // Superclasses/Superinterfaces
312 // ----------------------------------------------------------------------
313 /**
314 * <p>Gets a {@code List} of superclasses for the given class.</p>
315 *
316 * @param cls the class to look up, may be {@code null}
317 * @return the {@code List} of superclasses in order going up from this one
318 * {@code null} if null input
319 */
320 public static List<Class<?>> getAllSuperclasses(Class<?> cls) {
321 if (cls == null) {
322 return null;
323 }
324 List<Class<?>> classes = new ArrayList<Class<?>>();
325 Class<?> superclass = cls.getSuperclass();
326 while (superclass != null) {
327 classes.add(superclass);
328 superclass = superclass.getSuperclass();
329 }
330 return classes;
331 }
332
333 /**
334 * <p>Gets a {@code List} of all interfaces implemented by the given
335 * class and its superclasses.</p>
336 *
337 * <p>The order is determined by looking through each interface in turn as
338 * declared in the source file and following its hierarchy up. Then each
339 * superclass is considered in the same way. Later duplicates are ignored,
340 * so the order is maintained.</p>
341 *
342 * @param cls the class to look up, may be {@code null}
343 * @return the {@code List} of interfaces in order,
344 * {@code null} if null input
345 */
346 public static List<Class<?>> getAllInterfaces(Class<?> cls) {
347 if (cls == null) {
348 return null;
349 }
350
351 LinkedHashSet<Class<?>> interfacesFound = new LinkedHashSet<Class<?>>();
352 getAllInterfaces(cls, interfacesFound);
353
354 return new ArrayList<Class<?>>(interfacesFound);
355 }
356
357 /**
358 * Get the interfaces for the specified class.
359 *
360 * @param cls the class to look up, may be {@code null}
361 * @param interfacesFound the {@code Set} of interfaces for the class
362 */
363 private static void getAllInterfaces(Class<?> cls, HashSet<Class<?>> interfacesFound) {
364 while (cls != null) {
365 Class<?>[] interfaces = cls.getInterfaces();
366
367 for (Class<?> i : interfaces) {
368 if (interfacesFound.add(i)) {
369 getAllInterfaces(i, interfacesFound);
370 }
371 }
372
373 cls = cls.getSuperclass();
374 }
375 }
376
377 // Convert list
378 // ----------------------------------------------------------------------
379 /**
380 * <p>Given a {@code List} of class names, this method converts them into classes.</p>
381 *
382 * <p>A new {@code List} is returned. If the class name cannot be found, {@code null}
383 * is stored in the {@code List}. If the class name in the {@code List} is
384 * {@code null}, {@code null} is stored in the output {@code List}.</p>
385 *
386 * @param classNames the classNames to change
387 * @return a {@code List} of Class objects corresponding to the class names,
388 * {@code null} if null input
389 * @throws ClassCastException if classNames contains a non String entry
390 */
391 public static List<Class<?>> convertClassNamesToClasses(List<String> classNames) {
392 if (classNames == null) {
393 return null;
394 }
395 List<Class<?>> classes = new ArrayList<Class<?>>(classNames.size());
396 for (String className : classNames) {
397 try {
398 classes.add(Class.forName(className));
399 } catch (Exception ex) {
400 classes.add(null);
401 }
402 }
403 return classes;
404 }
405
406 /**
407 * <p>Given a {@code List} of {@code Class} objects, this method converts
408 * them into class names.</p>
409 *
410 * <p>A new {@code List} is returned. {@code null} objects will be copied into
411 * the returned list as {@code null}.</p>
412 *
413 * @param classes the classes to change
414 * @return a {@code List} of class names corresponding to the Class objects,
415 * {@code null} if null input
416 * @throws ClassCastException if {@code classes} contains a non-{@code Class} entry
417 */
418 public static List<String> convertClassesToClassNames(List<Class<?>> classes) {
419 if (classes == null) {
420 return null;
421 }
422 List<String> classNames = new ArrayList<String>(classes.size());
423 for (Class<?> cls : classes) {
424 if (cls == null) {
425 classNames.add(null);
426 } else {
427 classNames.add(cls.getName());
428 }
429 }
430 return classNames;
431 }
432
433 // Is assignable
434 // ----------------------------------------------------------------------
435 /**
436 * <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
437 *
438 * <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
439 * Class pair in the input arrays. It can be used to check if a set of arguments
440 * (the first parameter) are suitably compatible with a set of method parameter types
441 * (the second parameter).</p>
442 *
443 * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
444 * method takes into account widenings of primitive classes and
445 * {@code null}s.</p>
446 *
447 * <p>Primitive widenings allow an int to be assigned to a {@code long},
448 * {@code float} or {@code double}. This method returns the correct
449 * result for these cases.</p>
450 *
451 * <p>{@code Null} may be assigned to any reference type. This method will
452 * return {@code true} if {@code null} is passed in and the toClass is
453 * non-primitive.</p>
454 *
455 * <p>Specifically, this method tests whether the type represented by the
456 * specified {@code Class} parameter can be converted to the type
457 * represented by this {@code Class} object via an identity conversion
458 * widening primitive or widening reference conversion. See
459 * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
460 * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
461 *
462 * <p><strong>Since Lang 3.0,</strong> this method will default behavior for
463 * calculating assignability between primitive and wrapper types <em>corresponding
464 * to the running Java version</em>; i.e. autoboxing will be the default
465 * behavior in VMs running Java versions >= 1.5.</p>
466 *
467 * @param classArray the array of Classes to check, may be {@code null}
468 * @param toClassArray the array of Classes to try to assign into, may be {@code null}
469 * @return {@code true} if assignment possible
470 */
471 public static boolean isAssignable(Class<?>[] classArray, Class<?>... toClassArray) {
472 return isAssignable(classArray, toClassArray, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5));
473 }
474
475 /**
476 * <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
477 *
478 * <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
479 * Class pair in the input arrays. It can be used to check if a set of arguments
480 * (the first parameter) are suitably compatible with a set of method parameter types
481 * (the second parameter).</p>
482 *
483 * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
484 * method takes into account widenings of primitive classes and
485 * {@code null}s.</p>
486 *
487 * <p>Primitive widenings allow an int to be assigned to a {@code long},
488 * {@code float} or {@code double}. This method returns the correct
489 * result for these cases.</p>
490 *
491 * <p>{@code Null} may be assigned to any reference type. This method will
492 * return {@code true} if {@code null} is passed in and the toClass is
493 * non-primitive.</p>
494 *
495 * <p>Specifically, this method tests whether the type represented by the
496 * specified {@code Class} parameter can be converted to the type
497 * represented by this {@code Class} object via an identity conversion
498 * widening primitive or widening reference conversion. See
499 * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
500 * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
501 *
502 * @param classArray the array of Classes to check, may be {@code null}
503 * @param toClassArray the array of Classes to try to assign into, may be {@code null}
504 * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
505 * @return {@code true} if assignment possible
506 */
507 public static boolean isAssignable(Class<?>[] classArray, Class<?>[] toClassArray, boolean autoboxing) {
508 if (ArrayUtils.isSameLength(classArray, toClassArray) == false) {
509 return false;
510 }
511 if (classArray == null) {
512 classArray = ArrayUtils.EMPTY_CLASS_ARRAY;
513 }
514 if (toClassArray == null) {
515 toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
516 }
517 for (int i = 0; i < classArray.length; i++) {
518 if (isAssignable(classArray[i], toClassArray[i], autoboxing) == false) {
519 return false;
520 }
521 }
522 return true;
523 }
524
525 /**
526 * <p>Checks if one {@code Class} can be assigned to a variable of
527 * another {@code Class}.</p>
528 *
529 * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
530 * this method takes into account widenings of primitive classes and
531 * {@code null}s.</p>
532 *
533 * <p>Primitive widenings allow an int to be assigned to a long, float or
534 * double. This method returns the correct result for these cases.</p>
535 *
536 * <p>{@code Null} may be assigned to any reference type. This method
537 * will return {@code true} if {@code null} is passed in and the
538 * toClass is non-primitive.</p>
539 *
540 * <p>Specifically, this method tests whether the type represented by the
541 * specified {@code Class} parameter can be converted to the type
542 * represented by this {@code Class} object via an identity conversion
543 * widening primitive or widening reference conversion. See
544 * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
545 * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
546 *
547 * <p><strong>Since Lang 3.0,</strong> this method will default behavior for
548 * calculating assignability between primitive and wrapper types <em>corresponding
549 * to the running Java version</em>; i.e. autoboxing will be the default
550 * behavior in VMs running Java versions >= 1.5.</p>
551 *
552 * @param cls the Class to check, may be null
553 * @param toClass the Class to try to assign into, returns false if null
554 * @return {@code true} if assignment possible
555 */
556 public static boolean isAssignable(Class<?> cls, Class<?> toClass) {
557 return isAssignable(cls, toClass, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5));
558 }
559
560 /**
561 * <p>Checks if one {@code Class} can be assigned to a variable of
562 * another {@code Class}.</p>
563 *
564 * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
565 * this method takes into account widenings of primitive classes and
566 * {@code null}s.</p>
567 *
568 * <p>Primitive widenings allow an int to be assigned to a long, float or
569 * double. This method returns the correct result for these cases.</p>
570 *
571 * <p>{@code Null} may be assigned to any reference type. This method
572 * will return {@code true} if {@code null} is passed in and the
573 * toClass is non-primitive.</p>
574 *
575 * <p>Specifically, this method tests whether the type represented by the
576 * specified {@code Class} parameter can be converted to the type
577 * represented by this {@code Class} object via an identity conversion
578 * widening primitive or widening reference conversion. See
579 * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
580 * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
581 *
582 * @param cls the Class to check, may be null
583 * @param toClass the Class to try to assign into, returns false if null
584 * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
585 * @return {@code true} if assignment possible
586 */
587 public static boolean isAssignable(Class<?> cls, Class<?> toClass, boolean autoboxing) {
588 if (toClass == null) {
589 return false;
590 }
591 // have to check for null, as isAssignableFrom doesn't
592 if (cls == null) {
593 return !(toClass.isPrimitive());
594 }
595 //autoboxing:
596 if (autoboxing) {
597 if (cls.isPrimitive() && !toClass.isPrimitive()) {
598 cls = primitiveToWrapper(cls);
599 if (cls == null) {
600 return false;
601 }
602 }
603 if (toClass.isPrimitive() && !cls.isPrimitive()) {
604 cls = wrapperToPrimitive(cls);
605 if (cls == null) {
606 return false;
607 }
608 }
609 }
610 if (cls.equals(toClass)) {
611 return true;
612 }
613 if (cls.isPrimitive()) {
614 if (toClass.isPrimitive() == false) {
615 return false;
616 }
617 if (Integer.TYPE.equals(cls)) {
618 return Long.TYPE.equals(toClass)
619 || Float.TYPE.equals(toClass)
620 || Double.TYPE.equals(toClass);
621 }
622 if (Long.TYPE.equals(cls)) {
623 return Float.TYPE.equals(toClass)
624 || Double.TYPE.equals(toClass);
625 }
626 if (Boolean.TYPE.equals(cls)) {
627 return false;
628 }
629 if (Double.TYPE.equals(cls)) {
630 return false;
631 }
632 if (Float.TYPE.equals(cls)) {
633 return Double.TYPE.equals(toClass);
634 }
635 if (Character.TYPE.equals(cls)) {
636 return Integer.TYPE.equals(toClass)
637 || Long.TYPE.equals(toClass)
638 || Float.TYPE.equals(toClass)
639 || Double.TYPE.equals(toClass);
640 }
641 if (Short.TYPE.equals(cls)) {
642 return Integer.TYPE.equals(toClass)
643 || Long.TYPE.equals(toClass)
644 || Float.TYPE.equals(toClass)
645 || Double.TYPE.equals(toClass);
646 }
647 if (Byte.TYPE.equals(cls)) {
648 return Short.TYPE.equals(toClass)
649 || Integer.TYPE.equals(toClass)
650 || Long.TYPE.equals(toClass)
651 || Float.TYPE.equals(toClass)
652 || Double.TYPE.equals(toClass);
653 }
654 // should never get here
655 return false;
656 }
657 return toClass.isAssignableFrom(cls);
658 }
659
660 /**
661 * <p>Converts the specified primitive Class object to its corresponding
662 * wrapper Class object.</p>
663 *
664 * <p>NOTE: From v2.2, this method handles {@code Void.TYPE},
665 * returning {@code Void.TYPE}.</p>
666 *
667 * @param cls the class to convert, may be null
668 * @return the wrapper class for {@code cls} or {@code cls} if
669 * {@code cls} is not a primitive. {@code null} if null input.
670 * @since 2.1
671 */
672 public static Class<?> primitiveToWrapper(Class<?> cls) {
673 Class<?> convertedClass = cls;
674 if (cls != null && cls.isPrimitive()) {
675 convertedClass = primitiveWrapperMap.get(cls);
676 }
677 return convertedClass;
678 }
679
680 /**
681 * <p>Converts the specified array of primitive Class objects to an array of
682 * its corresponding wrapper Class objects.</p>
683 *
684 * @param classes the class array to convert, may be null or empty
685 * @return an array which contains for each given class, the wrapper class or
686 * the original class if class is not a primitive. {@code null} if null input.
687 * Empty array if an empty array passed in.
688 * @since 2.1
689 */
690 public static Class<?>[] primitivesToWrappers(Class<?>... classes) {
691 if (classes == null) {
692 return null;
693 }
694
695 if (classes.length == 0) {
696 return classes;
697 }
698
699 Class<?>[] convertedClasses = new Class[classes.length];
700 for (int i = 0; i < classes.length; i++) {
701 convertedClasses[i] = primitiveToWrapper(classes[i]);
702 }
703 return convertedClasses;
704 }
705
706 /**
707 * <p>Converts the specified wrapper class to its corresponding primitive
708 * class.</p>
709 *
710 * <p>This method is the counter part of {@code primitiveToWrapper()}.
711 * If the passed in class is a wrapper class for a primitive type, this
712 * primitive type will be returned (e.g. {@code Integer.TYPE} for
713 * {@code Integer.class}). For other classes, or if the parameter is
714 * <b>null</b>, the return value is <b>null</b>.</p>
715 *
716 * @param cls the class to convert, may be <b>null</b>
717 * @return the corresponding primitive type if {@code cls} is a
718 * wrapper class, <b>null</b> otherwise
719 * @see #primitiveToWrapper(Class)
720 * @since 2.4
721 */
722 public static Class<?> wrapperToPrimitive(Class<?> cls) {
723 return wrapperPrimitiveMap.get(cls);
724 }
725
726 /**
727 * <p>Converts the specified array of wrapper Class objects to an array of
728 * its corresponding primitive Class objects.</p>
729 *
730 * <p>This method invokes {@code wrapperToPrimitive()} for each element
731 * of the passed in array.</p>
732 *
733 * @param classes the class array to convert, may be null or empty
734 * @return an array which contains for each given class, the primitive class or
735 * <b>null</b> if the original class is not a wrapper class. {@code null} if null input.
736 * Empty array if an empty array passed in.
737 * @see #wrapperToPrimitive(Class)
738 * @since 2.4
739 */
740 public static Class<?>[] wrappersToPrimitives(Class<?>... classes) {
741 if (classes == null) {
742 return null;
743 }
744
745 if (classes.length == 0) {
746 return classes;
747 }
748
749 Class<?>[] convertedClasses = new Class[classes.length];
750 for (int i = 0; i < classes.length; i++) {
751 convertedClasses[i] = wrapperToPrimitive(classes[i]);
752 }
753 return convertedClasses;
754 }
755
756 // Inner class
757 // ----------------------------------------------------------------------
758 /**
759 * <p>Is the specified class an inner class or static nested class.</p>
760 *
761 * @param cls the class to check, may be null
762 * @return {@code true} if the class is an inner or static nested class,
763 * false if not or {@code null}
764 */
765 public static boolean isInnerClass(Class<?> cls) {
766 return cls != null && cls.getEnclosingClass() != null;
767 }
768
769 // Class loading
770 // ----------------------------------------------------------------------
771 /**
772 * Returns the class represented by {@code className} using the
773 * {@code classLoader}. This implementation supports the syntaxes
774 * "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
775 * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
776 *
777 * @param classLoader the class loader to use to load the class
778 * @param className the class name
779 * @param initialize whether the class must be initialized
780 * @return the class represented by {@code className} using the {@code classLoader}
781 * @throws ClassNotFoundException if the class is not found
782 */
783 public static Class<?> getClass(
784 ClassLoader classLoader, String className, boolean initialize) throws ClassNotFoundException {
785 try {
786 Class<?> clazz;
787 if (abbreviationMap.containsKey(className)) {
788 String clsName = "[" + abbreviationMap.get(className);
789 clazz = Class.forName(clsName, initialize, classLoader).getComponentType();
790 } else {
791 clazz = Class.forName(toCanonicalName(className), initialize, classLoader);
792 }
793 return clazz;
794 } catch (ClassNotFoundException ex) {
795 // allow path separators (.) as inner class name separators
796 int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
797
798 if (lastDotIndex != -1) {
799 try {
800 return getClass(classLoader, className.substring(0, lastDotIndex) +
801 INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1),
802 initialize);
803 } catch (ClassNotFoundException ex2) { // NOPMD
804 // ignore exception
805 }
806 }
807
808 throw ex;
809 }
810 }
811
812 /**
813 * Returns the (initialized) class represented by {@code className}
814 * using the {@code classLoader}. This implementation supports
815 * the syntaxes "{@code java.util.Map.Entry[]}",
816 * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
817 * and "{@code [Ljava.util.Map$Entry;}".
818 *
819 * @param classLoader the class loader to use to load the class
820 * @param className the class name
821 * @return the class represented by {@code className} using the {@code classLoader}
822 * @throws ClassNotFoundException if the class is not found
823 */
824 public static Class<?> getClass(ClassLoader classLoader, String className) throws ClassNotFoundException {
825 return getClass(classLoader, className, true);
826 }
827
828 /**
829 * Returns the (initialized) class represented by {@code className}
830 * using the current thread's context class loader. This implementation
831 * supports the syntaxes "{@code java.util.Map.Entry[]}",
832 * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
833 * and "{@code [Ljava.util.Map$Entry;}".
834 *
835 * @param className the class name
836 * @return the class represented by {@code className} using the current thread's context class loader
837 * @throws ClassNotFoundException if the class is not found
838 */
839 public static Class<?> getClass(String className) throws ClassNotFoundException {
840 return getClass(className, true);
841 }
842
843 /**
844 * Returns the class represented by {@code className} using the
845 * current thread's context class loader. This implementation supports the
846 * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
847 * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
848 *
849 * @param className the class name
850 * @param initialize whether the class must be initialized
851 * @return the class represented by {@code className} using the current thread's context class loader
852 * @throws ClassNotFoundException if the class is not found
853 */
854 public static Class<?> getClass(String className, boolean initialize) throws ClassNotFoundException {
855 ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
856 ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL;
857 return getClass(loader, className, initialize );
858 }
859
860 // Public method
861 // ----------------------------------------------------------------------
862 /**
863 * <p>Returns the desired Method much like {@code Class.getMethod}, however
864 * it ensures that the returned Method is from a public class or interface and not
865 * from an anonymous inner class. This means that the Method is invokable and
866 * doesn't fall foul of Java bug
867 * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957">4071957</a>).
868 *
869 * <code><pre>Set set = Collections.unmodifiableSet(...);
870 * Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
871 * Object result = method.invoke(set, new Object[]);</pre></code>
872 * </p>
873 *
874 * @param cls the class to check, not null
875 * @param methodName the name of the method
876 * @param parameterTypes the list of parameters
877 * @return the method
878 * @throws NullPointerException if the class is null
879 * @throws SecurityException if a a security violation occured
880 * @throws NoSuchMethodException if the method is not found in the given class
881 * or if the metothod doen't conform with the requirements
882 */
883 public static Method getPublicMethod(Class<?> cls, String methodName, Class<?>... parameterTypes)
884 throws SecurityException, NoSuchMethodException {
885
886 Method declaredMethod = cls.getMethod(methodName, parameterTypes);
887 if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) {
888 return declaredMethod;
889 }
890
891 List<Class<?>> candidateClasses = new ArrayList<Class<?>>();
892 candidateClasses.addAll(getAllInterfaces(cls));
893 candidateClasses.addAll(getAllSuperclasses(cls));
894
895 for (Class<?> candidateClass : candidateClasses) {
896 if (!Modifier.isPublic(candidateClass.getModifiers())) {
897 continue;
898 }
899 Method candidateMethod;
900 try {
901 candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
902 } catch (NoSuchMethodException ex) {
903 continue;
904 }
905 if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
906 return candidateMethod;
907 }
908 }
909
910 throw new NoSuchMethodException("Can't find a public method for " +
911 methodName + " " + ArrayUtils.toString(parameterTypes));
912 }
913
914 // ----------------------------------------------------------------------
915 /**
916 * Converts a class name to a JLS style class name.
917 *
918 * @param className the class name
919 * @return the converted name
920 */
921 private static String toCanonicalName(String className) {
922 className = StringUtils.deleteWhitespace(className);
923 if (className == null) {
924 throw new NullPointerException("className must not be null.");
925 } else if (className.endsWith("[]")) {
926 StringBuilder classNameBuffer = new StringBuilder();
927 while (className.endsWith("[]")) {
928 className = className.substring(0, className.length() - 2);
929 classNameBuffer.append("[");
930 }
931 String abbreviation = abbreviationMap.get(className);
932 if (abbreviation != null) {
933 classNameBuffer.append(abbreviation);
934 } else {
935 classNameBuffer.append("L").append(className).append(";");
936 }
937 className = classNameBuffer.toString();
938 }
939 return className;
940 }
941
942 /**
943 * <p>Converts an array of {@code Object} in to an array of {@code Class} objects.
944 * If any of these objects is null, a null element will be inserted into the array.</p>
945 *
946 * <p>This method returns {@code null} for a {@code null} input array.</p>
947 *
948 * @param array an {@code Object} array
949 * @return a {@code Class} array, {@code null} if null array input
950 * @since 2.4
951 */
952 public static Class<?>[] toClass(Object... array) {
953 if (array == null) {
954 return null;
955 } else if (array.length == 0) {
956 return ArrayUtils.EMPTY_CLASS_ARRAY;
957 }
958 Class<?>[] classes = new Class[array.length];
959 for (int i = 0; i < array.length; i++) {
960 classes[i] = array[i] == null ? null : array[i].getClass();
961 }
962 return classes;
963 }
964
965 // Short canonical name
966 // ----------------------------------------------------------------------
967 /**
968 * <p>Gets the canonical name minus the package name for an {@code Object}.</p>
969 *
970 * @param object the class to get the short name for, may be null
971 * @param valueIfNull the value to return if null
972 * @return the canonical name of the object without the package name, or the null value
973 * @since 2.4
974 */
975 public static String getShortCanonicalName(Object object, String valueIfNull) {
976 if (object == null) {
977 return valueIfNull;
978 }
979 return getShortCanonicalName(object.getClass().getName());
980 }
981
982 /**
983 * <p>Gets the canonical name minus the package name from a {@code Class}.</p>
984 *
985 * @param cls the class to get the short name for.
986 * @return the canonical name without the package name or an empty string
987 * @since 2.4
988 */
989 public static String getShortCanonicalName(Class<?> cls) {
990 if (cls == null) {
991 return StringUtils.EMPTY;
992 }
993 return getShortCanonicalName(cls.getName());
994 }
995
996 /**
997 * <p>Gets the canonical name minus the package name from a String.</p>
998 *
999 * <p>The string passed in is assumed to be a canonical name - it is not checked.</p>
1000 *
1001 * @param canonicalName the class name to get the short name for
1002 * @return the canonical name of the class without the package name or an empty string
1003 * @since 2.4
1004 */
1005 public static String getShortCanonicalName(String canonicalName) {
1006 return ClassUtils.getShortClassName(getCanonicalName(canonicalName));
1007 }
1008
1009 // Package name
1010 // ----------------------------------------------------------------------
1011 /**
1012 * <p>Gets the package name from the canonical name of an {@code Object}.</p>
1013 *
1014 * @param object the class to get the package name for, may be null
1015 * @param valueIfNull the value to return if null
1016 * @return the package name of the object, or the null value
1017 * @since 2.4
1018 */
1019 public static String getPackageCanonicalName(Object object, String valueIfNull) {
1020 if (object == null) {
1021 return valueIfNull;
1022 }
1023 return getPackageCanonicalName(object.getClass().getName());
1024 }
1025
1026 /**
1027 * <p>Gets the package name from the canonical name of a {@code Class}.</p>
1028 *
1029 * @param cls the class to get the package name for, may be {@code null}.
1030 * @return the package name or an empty string
1031 * @since 2.4
1032 */
1033 public static String getPackageCanonicalName(Class<?> cls) {
1034 if (cls == null) {
1035 return StringUtils.EMPTY;
1036 }
1037 return getPackageCanonicalName(cls.getName());
1038 }
1039
1040 /**
1041 * <p>Gets the package name from the canonical name. </p>
1042 *
1043 * <p>The string passed in is assumed to be a canonical name - it is not checked.</p>
1044 * <p>If the class is unpackaged, return an empty string.</p>
1045 *
1046 * @param canonicalName the canonical name to get the package name for, may be {@code null}
1047 * @return the package name or an empty string
1048 * @since 2.4
1049 */
1050 public static String getPackageCanonicalName(String canonicalName) {
1051 return ClassUtils.getPackageName(getCanonicalName(canonicalName));
1052 }
1053
1054 /**
1055 * <p>Converts a given name of class into canonical format.
1056 * If name of class is not a name of array class it returns
1057 * unchanged name.</p>
1058 * <p>Example:
1059 * <ul>
1060 * <li>{@code getCanonicalName("[I") = "int[]"}</li>
1061 * <li>{@code getCanonicalName("[Ljava.lang.String;") = "java.lang.String[]"}</li>
1062 * <li>{@code getCanonicalName("java.lang.String") = "java.lang.String"}</li>
1063 * </ul>
1064 * </p>
1065 *
1066 * @param className the name of class
1067 * @return canonical form of class name
1068 * @since 2.4
1069 */
1070 private static String getCanonicalName(String className) {
1071 className = StringUtils.deleteWhitespace(className);
1072 if (className == null) {
1073 return null;
1074 } else {
1075 int dim = 0;
1076 while (className.startsWith("[")) {
1077 dim++;
1078 className = className.substring(1);
1079 }
1080 if (dim < 1) {
1081 return className;
1082 } else {
1083 if (className.startsWith("L")) {
1084 className = className.substring(
1085 1,
1086 className.endsWith(";")
1087 ? className.length() - 1
1088 : className.length());
1089 } else {
1090 if (className.length() > 0) {
1091 className = reverseAbbreviationMap.get(className.substring(0, 1));
1092 }
1093 }
1094 StringBuilder canonicalClassNameBuffer = new StringBuilder(className);
1095 for (int i = 0; i < dim; i++) {
1096 canonicalClassNameBuffer.append("[]");
1097 }
1098 return canonicalClassNameBuffer.toString();
1099 }
1100 }
1101 }
1102 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.EnumSet;
24
25 /**
26 * <p>Utility library to provide helper methods for Java enums.</p>
27 *
28 * <p>#ThreadSafe#</p>
29 *
30 * @since 3.0
31 * @version $Id: EnumUtils.java 1149320 2011-07-21 19:11:47Z mbenson $
32 */
33 public class EnumUtils {
34
35 /**
36 * This constructor is public to permit tools that require a JavaBean
37 * instance to operate.
38 */
39 public EnumUtils() {
40 }
41
42 /**
43 * <p>Gets the {@code Map} of enums by name.</p>
44 *
45 * <p>This method is useful when you need a map of enums by name.</p>
46 *
47 * @param <E> the type of the enumeration
48 * @param enumClass the class of the enum to query, not null
49 * @return the modifiable map of enum names to enums, never null
50 */
51 public static <E extends Enum<E>> Map<String, E> getEnumMap(Class<E> enumClass) {
52 Map<String, E> map = new LinkedHashMap<String, E>();
53 for (E e: enumClass.getEnumConstants()) {
54 map.put(e.name(), e);
55 }
56 return map;
57 }
58
59 /**
60 * <p>Gets the {@code List} of enums.</p>
61 *
62 * <p>This method is useful when you need a list of enums rather than an array.</p>
63 *
64 * @param <E> the type of the enumeration
65 * @param enumClass the class of the enum to query, not null
66 * @return the modifiable list of enums, never null
67 */
68 public static <E extends Enum<E>> List<E> getEnumList(Class<E> enumClass) {
69 return new ArrayList<E>(Arrays.asList(enumClass.getEnumConstants()));
70 }
71
72 /**
73 * <p>Checks if the specified name is a valid enum for the class.</p>
74 *
75 * <p>This method differs from {@link Enum#valueOf} in that checks if the name is
76 * a valid enum without needing to catch the exception.</p>
77 *
78 * @param <E> the type of the enumeration
79 * @param enumClass the class of the enum to query, not null
80 * @param enumName the enum name, null returns false
81 * @return true if the enum name is valid, otherwise false
82 */
83 public static <E extends Enum<E>> boolean isValidEnum(Class<E> enumClass, String enumName) {
84 if (enumName == null) {
85 return false;
86 }
87 try {
88 Enum.valueOf(enumClass, enumName);
89 return true;
90 } catch (IllegalArgumentException ex) {
91 return false;
92 }
93 }
94
95 /**
96 * <p>Gets the enum for the class, returning {@code null} if not found.</p>
97 *
98 * <p>This method differs from {@link Enum#valueOf} in that it does not throw an exception
99 * for an invalid enum name.</p>
100 *
101 * @param <E> the type of the enumeration
102 * @param enumClass the class of the enum to query, not null
103 * @param enumName the enum name, null returns null
104 * @return the enum, null if not found
105 */
106 public static <E extends Enum<E>> E getEnum(Class<E> enumClass, String enumName) {
107 if (enumName == null) {
108 return null;
109 }
110 try {
111 return Enum.valueOf(enumClass, enumName);
112 } catch (IllegalArgumentException ex) {
113 return null;
114 }
115 }
116
117 /**
118 * <p>Creates a long bit vector representation of the given subset of an Enum.</p>
119 *
120 * <p>This generates a value that is usable by {@link EnumUtils#processBitVector}.</p>
121 *
122 * <p>Do not use this method if you have more than 64 values in your Enum, as this
123 * would create a value greater than a long can hold.</p>
124 *
125 * @param enumClass the class of the enum we are working with, not {@code null}
126 * @param values the values we want to convert, not {@code null}
127 * @param <E> the type of the enumeration
128 * @return a long whose binary value represents the given set of enum values.
129 * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}
130 * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
131 * @since 3.0.1
132 */
133 public static <E extends Enum<E>> long generateBitVector(Class<E> enumClass, Iterable<E> values) {
134 checkBitVectorable(enumClass);
135 Validate.notNull(values);
136 long total = 0;
137 for (E constant : values) {
138 total |= (1 << constant.ordinal());
139 }
140 return total;
141 }
142
143 /**
144 * <p>Creates a long bit vector representation of the given array of Enum values.</p>
145 *
146 * <p>This generates a value that is usable by {@link EnumUtils#processBitVector}.</p>
147 *
148 * <p>Do not use this method if you have more than 64 values in your Enum, as this
149 * would create a value greater than a long can hold.</p>
150 *
151 * @param enumClass the class of the enum we are working with, not {@code null}
152 * @param values the values we want to convert, not {@code null}
153 * @param <E> the type of the enumeration
154 * @return a long whose binary value represents the given set of enum values.
155 * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}
156 * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
157 * @since 3.0.1
158 */
159 public static <E extends Enum<E>> long generateBitVector(Class<E> enumClass, E... values) {
160 Validate.noNullElements(values);
161 return generateBitVector(enumClass, Arrays.<E> asList(values));
162 }
163
164 /**
165 * <p>Convert a long value created by {@link EnumUtils#generateBitVector} into the set of
166 * enum values that it represents.</p>
167 *
168 * <p>If you store this value, beware any changes to the enum that would affect ordinal values.</p>
169 * @param enumClass the class of the enum we are working with, not {@code null}
170 * @param value the long value representation of a set of enum values
171 * @param <E> the type of the enumeration
172 * @return a set of enum values
173 * @throws NullPointerException if {@code enumClass} is {@code null}
174 * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
175 * @since 3.0.1
176 */
177 public static <E extends Enum<E>> EnumSet<E> processBitVector(Class<E> enumClass, long value) {
178 final E[] constants = checkBitVectorable(enumClass).getEnumConstants();
179 final EnumSet<E> results = EnumSet.noneOf(enumClass);
180 for (E constant : constants) {
181 if ((value & (1 << constant.ordinal())) != 0) {
182 results.add(constant);
183 }
184 }
185 return results;
186 }
187
188 /**
189 * Validate that {@code enumClass} is compatible with representation in a {@code long}.
190 * @param <E> the type of the enumeration
191 * @param enumClass to check
192 * @return {@code enumClass}
193 * @throws NullPointerException if {@code enumClass} is {@code null}
194 * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
195 * @since 3.0.1
196 */
197 private static <E extends Enum<E>> Class<E> checkBitVectorable(Class<E> enumClass) {
198 Validate.notNull(enumClass, "EnumClass must be defined.");
199
200 final E[] constants = enumClass.getEnumConstants();
201 Validate.isTrue(constants != null, "%s does not seem to be an Enum type", enumClass);
202 Validate.isTrue(constants.length <= Long.SIZE, "Cannot store %s %s values in %s bits", constants.length,
203 enumClass.getSimpleName(), Long.SIZE);
204
205 return enumClass;
206 }
207 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 /**
19 * <p>An enum representing all the versions of the Java specification.
20 * This is intended to mirror available values from the
21 * <em>java.specification.version</em> System property. </p>
22 *
23 * @since 3.0
24 * @version $Id: $
25 */
26 public enum JavaVersion {
27
28 /**
29 * The Java version reported by Android. This is not an official Java version number.
30 */
31 JAVA_0_9(1.5f, "0.9"),
32
33 /**
34 * Java 1.1.
35 */
36 JAVA_1_1(1.1f, "1.1"),
37
38 /**
39 * Java 1.2.
40 */
41 JAVA_1_2(1.2f, "1.2"),
42
43 /**
44 * Java 1.3.
45 */
46 JAVA_1_3(1.3f, "1.3"),
47
48 /**
49 * Java 1.4.
50 */
51 JAVA_1_4(1.4f, "1.4"),
52
53 /**
54 * Java 1.5.
55 */
56 JAVA_1_5(1.5f, "1.5"),
57
58 /**
59 * Java 1.6.
60 */
61 JAVA_1_6(1.6f, "1.6"),
62
63 /**
64 * Java 1.7.
65 */
66 JAVA_1_7(1.7f, "1.7"),
67
68 /**
69 * Java 1.8.
70 */
71 JAVA_1_8(1.8f, "1.8");
72
73 /**
74 * The float value.
75 */
76 private float value;
77 /**
78 * The standard name.
79 */
80 private String name;
81
82 /**
83 * Constructor.
84 *
85 * @param value the float value
86 * @param name the standard name, not null
87 */
88 JavaVersion(final float value, final String name) {
89 this.value = value;
90 this.name = name;
91 }
92
93 //-----------------------------------------------------------------------
94 /**
95 * <p>Whether this version of Java is at least the version of Java passed in.</p>
96 *
97 * <p>For example:<br />
98 * {@code myVersion.atLeast(JavaVersion.JAVA_1_4)}<p>
99 *
100 * @param requiredVersion the version to check against, not null
101 * @return true if this version is equal to or greater than the specified version
102 */
103 public boolean atLeast(JavaVersion requiredVersion) {
104 return this.value >= requiredVersion.value;
105 }
106
107 /**
108 * Transforms the given string with a Java version number to the
109 * corresponding constant of this enumeration class. This method is used
110 * internally.
111 *
112 * @param nom the Java version as string
113 * @return the corresponding enumeration constant or <b>null</b> if the
114 * version is unknown
115 */
116 // helper for static importing
117 static JavaVersion getJavaVersion(final String nom) {
118 return get(nom);
119 }
120
121 /**
122 * Transforms the given string with a Java version number to the
123 * corresponding constant of this enumeration class. This method is used
124 * internally.
125 *
126 * @param nom the Java version as string
127 * @return the corresponding enumeration constant or <b>null</b> if the
128 * version is unknown
129 */
130 static JavaVersion get(final String nom) {
131 if ("0.9".equals(nom)) {
132 return JAVA_0_9;
133 } else if ("1.1".equals(nom)) {
134 return JAVA_1_1;
135 } else if ("1.2".equals(nom)) {
136 return JAVA_1_2;
137 } else if ("1.3".equals(nom)) {
138 return JAVA_1_3;
139 } else if ("1.4".equals(nom)) {
140 return JAVA_1_4;
141 } else if ("1.5".equals(nom)) {
142 return JAVA_1_5;
143 } else if ("1.6".equals(nom)) {
144 return JAVA_1_6;
145 } else if ("1.7".equals(nom)) {
146 return JAVA_1_7;
147 } else if ("1.8".equals(nom)) {
148 return JAVA_1_8;
149 } else {
150 return null;
151 }
152 }
153
154 //-----------------------------------------------------------------------
155 /**
156 * <p>The string value is overridden to return the standard name.</p>
157 *
158 * <p>For example, <code>"1.5"</code>.</p>
159 *
160 * @return the name, not null
161 */
162 @Override
163 public String toString() {
164 return name;
165 }
166
167 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Locale;
24 import java.util.Set;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27
28 /**
29 * <p>Operations to assist when working with a {@link Locale}.</p>
30 *
31 * <p>This class tries to handle {@code null} input gracefully.
32 * An exception will not be thrown for a {@code null} input.
33 * Each method documents its behaviour in more detail.</p>
34 *
35 * @since 2.2
36 * @version $Id: LocaleUtils.java 1090563 2011-04-09 11:00:10Z sebb $
37 */
38 public class LocaleUtils {
39
40 /** Concurrent map of language locales by country. */
41 private static final ConcurrentMap<String, List<Locale>> cLanguagesByCountry =
42 new ConcurrentHashMap<String, List<Locale>>();
43
44 /** Concurrent map of country locales by language. */
45 private static final ConcurrentMap<String, List<Locale>> cCountriesByLanguage =
46 new ConcurrentHashMap<String, List<Locale>>();
47
48 /**
49 * <p>{@code LocaleUtils} instances should NOT be constructed in standard programming.
50 * Instead, the class should be used as {@code LocaleUtils.toLocale("en_GB");}.</p>
51 *
52 * <p>This constructor is public to permit tools that require a JavaBean instance
53 * to operate.</p>
54 */
55 public LocaleUtils() {
56 super();
57 }
58
59 //-----------------------------------------------------------------------
60 /**
61 * <p>Converts a String to a Locale.</p>
62 *
63 * <p>This method takes the string format of a locale and creates the
64 * locale object from it.</p>
65 *
66 * <pre>
67 * LocaleUtils.toLocale("en") = new Locale("en", "")
68 * LocaleUtils.toLocale("en_GB") = new Locale("en", "GB")
69 * LocaleUtils.toLocale("en_GB_xxx") = new Locale("en", "GB", "xxx") (#)
70 * </pre>
71 *
72 * <p>(#) The behaviour of the JDK variant constructor changed between JDK1.3 and JDK1.4.
73 * In JDK1.3, the constructor upper cases the variant, in JDK1.4, it doesn't.
74 * Thus, the result from getVariant() may vary depending on your JDK.</p>
75 *
76 * <p>This method validates the input strictly.
77 * The language code must be lowercase.
78 * The country code must be uppercase.
79 * The separator must be an underscore.
80 * The length must be correct.
81 * </p>
82 *
83 * @param str the locale String to convert, null returns null
84 * @return a Locale, null if null input
85 * @throws IllegalArgumentException if the string is an invalid format
86 */
87 public static Locale toLocale(String str) {
88 if (str == null) {
89 return null;
90 }
91 int len = str.length();
92 if (len != 2 && len != 5 && len < 7) {
93 throw new IllegalArgumentException("Invalid locale format: " + str);
94 }
95 char ch0 = str.charAt(0);
96 char ch1 = str.charAt(1);
97 if (ch0 < 'a' || ch0 > 'z' || ch1 < 'a' || ch1 > 'z') {
98 throw new IllegalArgumentException("Invalid locale format: " + str);
99 }
100 if (len == 2) {
101 return new Locale(str, "");
102 } else {
103 if (str.charAt(2) != '_') {
104 throw new IllegalArgumentException("Invalid locale format: " + str);
105 }
106 char ch3 = str.charAt(3);
107 if (ch3 == '_') {
108 return new Locale(str.substring(0, 2), "", str.substring(4));
109 }
110 char ch4 = str.charAt(4);
111 if (ch3 < 'A' || ch3 > 'Z' || ch4 < 'A' || ch4 > 'Z') {
112 throw new IllegalArgumentException("Invalid locale format: " + str);
113 }
114 if (len == 5) {
115 return new Locale(str.substring(0, 2), str.substring(3, 5));
116 } else {
117 if (str.charAt(5) != '_') {
118 throw new IllegalArgumentException("Invalid locale format: " + str);
119 }
120 return new Locale(str.substring(0, 2), str.substring(3, 5), str.substring(6));
121 }
122 }
123 }
124
125 //-----------------------------------------------------------------------
126 /**
127 * <p>Obtains the list of locales to search through when performing
128 * a locale search.</p>
129 *
130 * <pre>
131 * localeLookupList(Locale("fr","CA","xxx"))
132 * = [Locale("fr","CA","xxx"), Locale("fr","CA"), Locale("fr")]
133 * </pre>
134 *
135 * @param locale the locale to start from
136 * @return the unmodifiable list of Locale objects, 0 being locale, not null
137 */
138 public static List<Locale> localeLookupList(Locale locale) {
139 return localeLookupList(locale, locale);
140 }
141
142 //-----------------------------------------------------------------------
143 /**
144 * <p>Obtains the list of locales to search through when performing
145 * a locale search.</p>
146 *
147 * <pre>
148 * localeLookupList(Locale("fr", "CA", "xxx"), Locale("en"))
149 * = [Locale("fr","CA","xxx"), Locale("fr","CA"), Locale("fr"), Locale("en"]
150 * </pre>
151 *
152 * <p>The result list begins with the most specific locale, then the
153 * next more general and so on, finishing with the default locale.
154 * The list will never contain the same locale twice.</p>
155 *
156 * @param locale the locale to start from, null returns empty list
157 * @param defaultLocale the default locale to use if no other is found
158 * @return the unmodifiable list of Locale objects, 0 being locale, not null
159 */
160 public static List<Locale> localeLookupList(Locale locale, Locale defaultLocale) {
161 List<Locale> list = new ArrayList<Locale>(4);
162 if (locale != null) {
163 list.add(locale);
164 if (locale.getVariant().length() > 0) {
165 list.add(new Locale(locale.getLanguage(), locale.getCountry()));
166 }
167 if (locale.getCountry().length() > 0) {
168 list.add(new Locale(locale.getLanguage(), ""));
169 }
170 if (list.contains(defaultLocale) == false) {
171 list.add(defaultLocale);
172 }
173 }
174 return Collections.unmodifiableList(list);
175 }
176
177 //-----------------------------------------------------------------------
178 /**
179 * <p>Obtains an unmodifiable list of installed locales.</p>
180 *
181 * <p>This method is a wrapper around {@link Locale#getAvailableLocales()}.
182 * It is more efficient, as the JDK method must create a new array each
183 * time it is called.</p>
184 *
185 * @return the unmodifiable list of available locales
186 */
187 public static List<Locale> availableLocaleList() {
188 return SyncAvoid.AVAILABLE_LOCALE_LIST;
189 }
190
191 //-----------------------------------------------------------------------
192 /**
193 * <p>Obtains an unmodifiable set of installed locales.</p>
194 *
195 * <p>This method is a wrapper around {@link Locale#getAvailableLocales()}.
196 * It is more efficient, as the JDK method must create a new array each
197 * time it is called.</p>
198 *
199 * @return the unmodifiable set of available locales
200 */
201 public static Set<Locale> availableLocaleSet() {
202 return SyncAvoid.AVAILABLE_LOCALE_SET;
203 }
204
205 //-----------------------------------------------------------------------
206 /**
207 * <p>Checks if the locale specified is in the list of available locales.</p>
208 *
209 * @param locale the Locale object to check if it is available
210 * @return true if the locale is a known locale
211 */
212 public static boolean isAvailableLocale(Locale locale) {
213 return availableLocaleList().contains(locale);
214 }
215
216 //-----------------------------------------------------------------------
217 /**
218 * <p>Obtains the list of languages supported for a given country.</p>
219 *
220 * <p>This method takes a country code and searches to find the
221 * languages available for that country. Variant locales are removed.</p>
222 *
223 * @param countryCode the 2 letter country code, null returns empty
224 * @return an unmodifiable List of Locale objects, not null
225 */
226 public static List<Locale> languagesByCountry(String countryCode) {
227 if (countryCode == null) {
228 return Collections.emptyList();
229 }
230 List<Locale> langs = cLanguagesByCountry.get(countryCode);
231 if (langs == null) {
232 langs = new ArrayList<Locale>();
233 List<Locale> locales = availableLocaleList();
234 for (int i = 0; i < locales.size(); i++) {
235 Locale locale = locales.get(i);
236 if (countryCode.equals(locale.getCountry()) &&
237 locale.getVariant().length() == 0) {
238 langs.add(locale);
239 }
240 }
241 langs = Collections.unmodifiableList(langs);
242 cLanguagesByCountry.putIfAbsent(countryCode, langs);
243 langs = cLanguagesByCountry.get(countryCode);
244 }
245 return langs;
246 }
247
248 //-----------------------------------------------------------------------
249 /**
250 * <p>Obtains the list of countries supported for a given language.</p>
251 *
252 * <p>This method takes a language code and searches to find the
253 * countries available for that language. Variant locales are removed.</p>
254 *
255 * @param languageCode the 2 letter language code, null returns empty
256 * @return an unmodifiable List of Locale objects, not null
257 */
258 public static List<Locale> countriesByLanguage(String languageCode) {
259 if (languageCode == null) {
260 return Collections.emptyList();
261 }
262 List<Locale> countries = cCountriesByLanguage.get(languageCode);
263 if (countries == null) {
264 countries = new ArrayList<Locale>();
265 List<Locale> locales = availableLocaleList();
266 for (int i = 0; i < locales.size(); i++) {
267 Locale locale = locales.get(i);
268 if (languageCode.equals(locale.getLanguage()) &&
269 locale.getCountry().length() != 0 &&
270 locale.getVariant().length() == 0) {
271 countries.add(locale);
272 }
273 }
274 countries = Collections.unmodifiableList(countries);
275 cCountriesByLanguage.putIfAbsent(languageCode, countries);
276 countries = cCountriesByLanguage.get(languageCode);
277 }
278 return countries;
279 }
280
281 //-----------------------------------------------------------------------
282 // class to avoid synchronization
283 static class SyncAvoid {
284 /** Unmodifiable list of available locales. */
285 private static List<Locale> AVAILABLE_LOCALE_LIST;
286 /** Unmodifiable set of available locales. */
287 private static Set<Locale> AVAILABLE_LOCALE_SET;
288
289 static {
290 List<Locale> list = new ArrayList<Locale>(Arrays.asList(Locale.getAvailableLocales())); // extra safe
291 AVAILABLE_LOCALE_LIST = Collections.unmodifiableList(list);
292 AVAILABLE_LOCALE_SET = Collections.unmodifiableSet(new HashSet<Locale>(availableLocaleList()));
293 }
294 }
295
296 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.io.Serializable;
19 import java.lang.reflect.Array;
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.util.Collections;
23 import java.util.Comparator;
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.TreeSet;
27
28 import org.apache.commons.lang3.exception.CloneFailedException;
29 import org.apache.commons.lang3.mutable.MutableInt;
30
31 /**
32 * <p>Operations on {@code Object}.</p>
33 *
34 * <p>This class tries to handle {@code null} input gracefully.
35 * An exception will generally not be thrown for a {@code null} input.
36 * Each method documents its behaviour in more detail.</p>
37 *
38 * <p>#ThreadSafe#</p>
39 * @since 1.0
40 * @version $Id: ObjectUtils.java 1153350 2011-08-03 05:29:21Z bayard $
41 */
42 //@Immutable
43 public class ObjectUtils {
44
45 /**
46 * <p>Singleton used as a {@code null} placeholder where
47 * {@code null} has another meaning.</p>
48 *
49 * <p>For example, in a {@code HashMap} the
50 * {@link java.util.HashMap#get(java.lang.Object)} method returns
51 * {@code null} if the {@code Map} contains {@code null} or if there
52 * is no matching key. The {@code Null} placeholder can be used to
53 * distinguish between these two cases.</p>
54 *
55 * <p>Another example is {@code Hashtable}, where {@code null}
56 * cannot be stored.</p>
57 *
58 * <p>This instance is Serializable.</p>
59 */
60 public static final Null NULL = new Null();
61
62 /**
63 * <p>{@code ObjectUtils} instances should NOT be constructed in
64 * standard programming. Instead, the static methods on the class should
65 * be used, such as {@code ObjectUtils.defaultIfNull("a","b");}.</p>
66 *
67 * <p>This constructor is public to permit tools that require a JavaBean
68 * instance to operate.</p>
69 */
70 public ObjectUtils() {
71 super();
72 }
73
74 // Defaulting
75 //-----------------------------------------------------------------------
76 /**
77 * <p>Returns a default value if the object passed is {@code null}.</p>
78 *
79 * <pre>
80 * ObjectUtils.defaultIfNull(null, null) = null
81 * ObjectUtils.defaultIfNull(null, "") = ""
82 * ObjectUtils.defaultIfNull(null, "zz") = "zz"
83 * ObjectUtils.defaultIfNull("abc", *) = "abc"
84 * ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
85 * </pre>
86 *
87 * @param <T> the type of the object
88 * @param object the {@code Object} to test, may be {@code null}
89 * @param defaultValue the default value to return, may be {@code null}
90 * @return {@code object} if it is not {@code null}, defaultValue otherwise
91 */
92 public static <T> T defaultIfNull(T object, T defaultValue) {
93 return object != null ? object : defaultValue;
94 }
95
96 /**
97 * <p>Returns the first value in the array which is not {@code null}.
98 * If all the values are {@code null} or the array is {@code null}
99 * or empty then {@code null} is returned.</p>
100 *
101 * <pre>
102 * ObjectUtils.firstNonNull(null, null) = null
103 * ObjectUtils.firstNonNull(null, "") = ""
104 * ObjectUtils.firstNonNull(null, null, "") = ""
105 * ObjectUtils.firstNonNull(null, "zz") = "zz"
106 * ObjectUtils.firstNonNull("abc", *) = "abc"
107 * ObjectUtils.firstNonNull(null, "xyz", *) = "xyz"
108 * ObjectUtils.firstNonNull(Boolean.TRUE, *) = Boolean.TRUE
109 * ObjectUtils.firstNonNull() = null
110 * </pre>
111 *
112 * @param <T> the component type of the array
113 * @param values the values to test, may be {@code null} or empty
114 * @return the first value from {@code values} which is not {@code null},
115 * or {@code null} if there are no non-null values
116 * @since 3.0
117 */
118 public static <T> T firstNonNull(T... values) {
119 if (values != null) {
120 for (T val : values) {
121 if (val != null) {
122 return val;
123 }
124 }
125 }
126 return null;
127 }
128
129 // Null-safe equals/hashCode
130 //-----------------------------------------------------------------------
131 /**
132 * <p>Compares two objects for equality, where either one or both
133 * objects may be {@code null}.</p>
134 *
135 * <pre>
136 * ObjectUtils.equals(null, null) = true
137 * ObjectUtils.equals(null, "") = false
138 * ObjectUtils.equals("", null) = false
139 * ObjectUtils.equals("", "") = true
140 * ObjectUtils.equals(Boolean.TRUE, null) = false
141 * ObjectUtils.equals(Boolean.TRUE, "true") = false
142 * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE) = true
143 * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
144 * </pre>
145 *
146 * @param object1 the first object, may be {@code null}
147 * @param object2 the second object, may be {@code null}
148 * @return {@code true} if the values of both objects are the same
149 */
150 public static boolean equals(Object object1, Object object2) {
151 if (object1 == object2) {
152 return true;
153 }
154 if ((object1 == null) || (object2 == null)) {
155 return false;
156 }
157 return object1.equals(object2);
158 }
159
160 /**
161 * <p>Compares two objects for inequality, where either one or both
162 * objects may be {@code null}.</p>
163 *
164 * <pre>
165 * ObjectUtils.notEqual(null, null) = false
166 * ObjectUtils.notEqual(null, "") = true
167 * ObjectUtils.notEqual("", null) = true
168 * ObjectUtils.notEqual("", "") = false
169 * ObjectUtils.notEqual(Boolean.TRUE, null) = true
170 * ObjectUtils.notEqual(Boolean.TRUE, "true") = true
171 * ObjectUtils.notEqual(Boolean.TRUE, Boolean.TRUE) = false
172 * ObjectUtils.notEqual(Boolean.TRUE, Boolean.FALSE) = true
173 * </pre>
174 *
175 * @param object1 the first object, may be {@code null}
176 * @param object2 the second object, may be {@code null}
177 * @return {@code false} if the values of both objects are the same
178 */
179 public static boolean notEqual(Object object1, Object object2) {
180 return ObjectUtils.equals(object1, object2) == false;
181 }
182
183 /**
184 * <p>Gets the hash code of an object returning zero when the
185 * object is {@code null}.</p>
186 *
187 * <pre>
188 * ObjectUtils.hashCode(null) = 0
189 * ObjectUtils.hashCode(obj) = obj.hashCode()
190 * </pre>
191 *
192 * @param obj the object to obtain the hash code of, may be {@code null}
193 * @return the hash code of the object, or zero if null
194 * @since 2.1
195 */
196 public static int hashCode(Object obj) {
197 // hashCode(Object) retained for performance, as hash code is often critical
198 return (obj == null) ? 0 : obj.hashCode();
199 }
200
201 /**
202 * <p>Gets the hash code for multiple objects.</p>
203 *
204 * <p>This allows a hash code to be rapidly calculated for a number of objects.
205 * The hash code for a single object is the <em>not</em> same as {@link #hashCode(Object)}.
206 * The hash code for multiple objects is the same as that calculated by an
207 * {@code ArrayList} containing the specified objects.</p>
208 *
209 * <pre>
210 * ObjectUtils.hashCodeMulti() = 1
211 * ObjectUtils.hashCodeMulti((Object[]) null) = 1
212 * ObjectUtils.hashCodeMulti(a) = 31 + a.hashCode()
213 * ObjectUtils.hashCodeMulti(a,b) = (31 + a.hashCode()) * 31 + b.hashCode()
214 * ObjectUtils.hashCodeMulti(a,b,c) = ((31 + a.hashCode()) * 31 + b.hashCode()) * 31 + c.hashCode()
215 * </pre>
216 *
217 * @param objects the objects to obtain the hash code of, may be {@code null}
218 * @return the hash code of the objects, or zero if null
219 * @since 3.0
220 */
221 public static int hashCodeMulti(Object... objects) {
222 int hash = 1;
223 if (objects != null) {
224 for (Object object : objects) {
225 hash = hash * 31 + ObjectUtils.hashCode(object);
226 }
227 }
228 return hash;
229 }
230
231 // Identity ToString
232 //-----------------------------------------------------------------------
233 /**
234 * <p>Gets the toString that would be produced by {@code Object}
235 * if a class did not override toString itself. {@code null}
236 * will return {@code null}.</p>
237 *
238 * <pre>
239 * ObjectUtils.identityToString(null) = null
240 * ObjectUtils.identityToString("") = "java.lang.String@1e23"
241 * ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
242 * </pre>
243 *
244 * @param object the object to create a toString for, may be
245 * {@code null}
246 * @return the default toString text, or {@code null} if
247 * {@code null} passed in
248 */
249 public static String identityToString(Object object) {
250 if (object == null) {
251 return null;
252 }
253 StringBuffer buffer = new StringBuffer();
254 identityToString(buffer, object);
255 return buffer.toString();
256 }
257
258 /**
259 * <p>Appends the toString that would be produced by {@code Object}
260 * if a class did not override toString itself. {@code null}
261 * will throw a NullPointerException for either of the two parameters. </p>
262 *
263 * <pre>
264 * ObjectUtils.identityToString(buf, "") = buf.append("java.lang.String@1e23"
265 * ObjectUtils.identityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa"
266 * ObjectUtils.identityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa")
267 * </pre>
268 *
269 * @param buffer the buffer to append to
270 * @param object the object to create a toString for
271 * @since 2.4
272 */
273 public static void identityToString(StringBuffer buffer, Object object) {
274 if (object == null) {
275 throw new NullPointerException("Cannot get the toString of a null identity");
276 }
277 buffer.append(object.getClass().getName())
278 .append('@')
279 .append(Integer.toHexString(System.identityHashCode(object)));
280 }
281
282 // ToString
283 //-----------------------------------------------------------------------
284 /**
285 * <p>Gets the {@code toString} of an {@code Object} returning
286 * an empty string ("") if {@code null} input.</p>
287 *
288 * <pre>
289 * ObjectUtils.toString(null) = ""
290 * ObjectUtils.toString("") = ""
291 * ObjectUtils.toString("bat") = "bat"
292 * ObjectUtils.toString(Boolean.TRUE) = "true"
293 * </pre>
294 *
295 * @see StringUtils#defaultString(String)
296 * @see String#valueOf(Object)
297 * @param obj the Object to {@code toString}, may be null
298 * @return the passed in Object's toString, or nullStr if {@code null} input
299 * @since 2.0
300 */
301 public static String toString(Object obj) {
302 return obj == null ? "" : obj.toString();
303 }
304
305 /**
306 * <p>Gets the {@code toString} of an {@code Object} returning
307 * a specified text if {@code null} input.</p>
308 *
309 * <pre>
310 * ObjectUtils.toString(null, null) = null
311 * ObjectUtils.toString(null, "null") = "null"
312 * ObjectUtils.toString("", "null") = ""
313 * ObjectUtils.toString("bat", "null") = "bat"
314 * ObjectUtils.toString(Boolean.TRUE, "null") = "true"
315 * </pre>
316 *
317 * @see StringUtils#defaultString(String,String)
318 * @see String#valueOf(Object)
319 * @param obj the Object to {@code toString}, may be null
320 * @param nullStr the String to return if {@code null} input, may be null
321 * @return the passed in Object's toString, or nullStr if {@code null} input
322 * @since 2.0
323 */
324 public static String toString(Object obj, String nullStr) {
325 return obj == null ? nullStr : obj.toString();
326 }
327
328 // Comparable
329 //-----------------------------------------------------------------------
330 /**
331 * <p>Null safe comparison of Comparables.</p>
332 *
333 * @param <T> type of the values processed by this method
334 * @param values the set of comparable values, may be null
335 * @return
336 * <ul>
337 * <li>If any objects are non-null and unequal, the lesser object.
338 * <li>If all objects are non-null and equal, the first.
339 * <li>If any of the comparables are null, the lesser of the non-null objects.
340 * <li>If all the comparables are null, null is returned.
341 * </ul>
342 */
343 public static <T extends Comparable<? super T>> T min(T... values) {
344 T result = null;
345 if (values != null) {
346 for (T value : values) {
347 if (compare(value, result, true) < 0) {
348 result = value;
349 }
350 }
351 }
352 return result;
353 }
354
355 /**
356 * <p>Null safe comparison of Comparables.</p>
357 *
358 * @param <T> type of the values processed by this method
359 * @param values the set of comparable values, may be null
360 * @return
361 * <ul>
362 * <li>If any objects are non-null and unequal, the greater object.
363 * <li>If all objects are non-null and equal, the first.
364 * <li>If any of the comparables are null, the greater of the non-null objects.
365 * <li>If all the comparables are null, null is returned.
366 * </ul>
367 */
368 public static <T extends Comparable<? super T>> T max(T... values) {
369 T result = null;
370 if (values != null) {
371 for (T value : values) {
372 if (compare(value, result, false) > 0) {
373 result = value;
374 }
375 }
376 }
377 return result;
378 }
379
380 /**
381 * <p>Null safe comparison of Comparables.
382 * {@code null} is assumed to be less than a non-{@code null} value.</p>
383 *
384 * @param <T> type of the values processed by this method
385 * @param c1 the first comparable, may be null
386 * @param c2 the second comparable, may be null
387 * @return a negative value if c1 < c2, zero if c1 = c2
388 * and a positive value if c1 > c2
389 */
390 public static <T extends Comparable<? super T>> int compare(T c1, T c2) {
391 return compare(c1, c2, false);
392 }
393
394 /**
395 * <p>Null safe comparison of Comparables.</p>
396 *
397 * @param <T> type of the values processed by this method
398 * @param c1 the first comparable, may be null
399 * @param c2 the second comparable, may be null
400 * @param nullGreater if true {@code null} is considered greater
401 * than a non-{@code null} value or if false {@code null} is
402 * considered less than a Non-{@code null} value
403 * @return a negative value if c1 < c2, zero if c1 = c2
404 * and a positive value if c1 > c2
405 * @see java.util.Comparator#compare(Object, Object)
406 */
407 public static <T extends Comparable<? super T>> int compare(T c1, T c2, boolean nullGreater) {
408 if (c1 == c2) {
409 return 0;
410 } else if (c1 == null) {
411 return (nullGreater ? 1 : -1);
412 } else if (c2 == null) {
413 return (nullGreater ? -1 : 1);
414 }
415 return c1.compareTo(c2);
416 }
417
418 /**
419 * Find the "best guess" middle value among comparables. If there is an even
420 * number of total values, the lower of the two middle values will be returned.
421 * @param <T> type of values processed by this method
422 * @param items to compare
423 * @return T at middle position
424 * @throws NullPointerException if items is {@code null}
425 * @throws IllegalArgumentException if items is empty or contains {@code null} values
426 * @since 3.0.1
427 */
428 public static <T extends Comparable<? super T>> T median(T... items) {
429 Validate.notEmpty(items);
430 Validate.noNullElements(items);
431 TreeSet<T> sort = new TreeSet<T>();
432 Collections.addAll(sort, items);
433 @SuppressWarnings("unchecked") //we know all items added were T instances
434 T result = (T) sort.toArray()[(sort.size() - 1) / 2];
435 return result;
436 }
437
438 /**
439 * Find the "best guess" middle value among comparables. If there is an even
440 * number of total values, the lower of the two middle values will be returned.
441 * @param <T> type of values processed by this method
442 * @param comparator to use for comparisons
443 * @param items to compare
444 * @return T at middle position
445 * @throws NullPointerException if items or comparator is {@code null}
446 * @throws IllegalArgumentException if items is empty or contains {@code null} values
447 * @since 3.0.1
448 */
449 public static <T> T median(Comparator<T> comparator, T... items) {
450 Validate.notEmpty(items, "null/empty items");
451 Validate.noNullElements(items);
452 Validate.notNull(comparator, "null comparator");
453 TreeSet<T> sort = new TreeSet<T>(comparator);
454 Collections.addAll(sort, items);
455 @SuppressWarnings("unchecked") //we know all items added were T instances
456 T result = (T) sort.toArray()[(sort.size() - 1) / 2];
457 return result;
458 }
459
460 // Mode
461 //-----------------------------------------------------------------------
462 /**
463 * Find the most frequently occurring item.
464 *
465 * @param <T> type of values processed by this method
466 * @param items to check
467 * @return most populous T, {@code null} if non-unique or no items supplied
468 * @since 3.0.1
469 */
470 public static <T> T mode(T... items) {
471 if (ArrayUtils.isNotEmpty(items)) {
472 HashMap<T, MutableInt> occurrences = new HashMap<T, MutableInt>(items.length);
473 for (T t : items) {
474 MutableInt count = occurrences.get(t);
475 if (count == null) {
476 occurrences.put(t, new MutableInt(1));
477 } else {
478 count.increment();
479 }
480 }
481 T result = null;
482 int max = 0;
483 for (Map.Entry<T, MutableInt> e : occurrences.entrySet()) {
484 int cmp = e.getValue().intValue();
485 if (cmp == max) {
486 result = null;
487 } else if (cmp > max) {
488 max = cmp;
489 result = e.getKey();
490 }
491 }
492 return result;
493 }
494 return null;
495 }
496
497 // cloning
498 //-----------------------------------------------------------------------
499 /**
500 * <p>Clone an object.</p>
501 *
502 * @param <T> the type of the object
503 * @param obj the object to clone, null returns null
504 * @return the clone if the object implements {@link Cloneable} otherwise {@code null}
505 * @throws CloneFailedException if the object is cloneable and the clone operation fails
506 * @since 3.0
507 */
508 public static <T> T clone(final T obj) {
509 if (obj instanceof Cloneable) {
510 final Object result;
511 if (obj.getClass().isArray()) {
512 final Class<?> componentType = obj.getClass().getComponentType();
513 if (!componentType.isPrimitive()) {
514 result = ((Object[]) obj).clone();
515 } else {
516 int length = Array.getLength(obj);
517 result = Array.newInstance(componentType, length);
518 while (length-- > 0) {
519 Array.set(result, length, Array.get(obj, length));
520 }
521 }
522 } else {
523 try {
524 final Method clone = obj.getClass().getMethod("clone");
525 result = clone.invoke(obj);
526 } catch (final NoSuchMethodException e) {
527 throw new CloneFailedException("Cloneable type "
528 + obj.getClass().getName()
529 + " has no clone method", e);
530 } catch (final IllegalAccessException e) {
531 throw new CloneFailedException("Cannot clone Cloneable type "
532 + obj.getClass().getName(), e);
533 } catch (final InvocationTargetException e) {
534 throw new CloneFailedException("Exception cloning Cloneable type "
535 + obj.getClass().getName(), e.getCause());
536 }
537 }
538 @SuppressWarnings("unchecked")
539 final T checked = (T) result;
540 return checked;
541 }
542
543 return null;
544 }
545
546 /**
547 * <p>Clone an object if possible.</p>
548 *
549 * <p>This method is similar to {@link #clone(Object)}, but will return the provided
550 * instance as the return value instead of {@code null} if the instance
551 * is not cloneable. This is more convenient if the caller uses different
552 * implementations (e.g. of a service) and some of the implementations do not allow concurrent
553 * processing or have state. In such cases the implementation can simply provide a proper
554 * clone implementation and the caller's code does not have to change.</p>
555 *
556 * @param <T> the type of the object
557 * @param obj the object to clone, null returns null
558 * @return the clone if the object implements {@link Cloneable} otherwise the object itself
559 * @throws CloneFailedException if the object is cloneable and the clone operation fails
560 * @since 3.0
561 */
562 public static <T> T cloneIfPossible(final T obj) {
563 final T clone = clone(obj);
564 return clone == null ? obj : clone;
565 }
566
567 // Null
568 //-----------------------------------------------------------------------
569 /**
570 * <p>Class used as a null placeholder where {@code null}
571 * has another meaning.</p>
572 *
573 * <p>For example, in a {@code HashMap} the
574 * {@link java.util.HashMap#get(java.lang.Object)} method returns
575 * {@code null} if the {@code Map} contains {@code null} or if there is
576 * no matching key. The {@code Null} placeholder can be used to distinguish
577 * between these two cases.</p>
578 *
579 * <p>Another example is {@code Hashtable}, where {@code null}
580 * cannot be stored.</p>
581 */
582 public static class Null implements Serializable {
583 /**
584 * Required for serialization support. Declare serialization compatibility with Commons Lang 1.0
585 *
586 * @see java.io.Serializable
587 */
588 private static final long serialVersionUID = 7092611880189329093L;
589
590 /**
591 * Restricted constructor - singleton.
592 */
593 Null() {
594 super();
595 }
596
597 /**
598 * <p>Ensure singleton.</p>
599 *
600 * @return the singleton value
601 */
602 private Object readResolve() {
603 return ObjectUtils.NULL;
604 }
605 }
606
607 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.util.Random;
19
20 /**
21 * <p>Operations for random {@code String}s.</p>
22 * <p>Currently <em>private high surrogate</em> characters are ignored.
23 * These are Unicode characters that fall between the values 56192 (db80)
24 * and 56319 (dbff) as we don't know how to handle them.
25 * High and low surrogates are correctly dealt with - that is if a
26 * high surrogate is randomly chosen, 55296 (d800) to 56191 (db7f)
27 * then it is followed by a low surrogate. If a low surrogate is chosen,
28 * 56320 (dc00) to 57343 (dfff) then it is placed after a randomly
29 * chosen high surrogate. </p>
30 *
31 * <p>#ThreadSafe#</p>
32 * @since 1.0
33 * @version $Id: RandomStringUtils.java 1148520 2011-07-19 20:53:23Z ggregory $
34 */
35 public class RandomStringUtils {
36
37 /**
38 * <p>Random object used by random method. This has to be not local
39 * to the random method so as to not return the same value in the
40 * same millisecond.</p>
41 */
42 private static final Random RANDOM = new Random();
43
44 /**
45 * <p>{@code RandomStringUtils} instances should NOT be constructed in
46 * standard programming. Instead, the class should be used as
47 * {@code RandomStringUtils.random(5);}.</p>
48 *
49 * <p>This constructor is public to permit tools that require a JavaBean instance
50 * to operate.</p>
51 */
52 public RandomStringUtils() {
53 super();
54 }
55
56 // Random
57 //-----------------------------------------------------------------------
58 /**
59 * <p>Creates a random string whose length is the number of characters
60 * specified.</p>
61 *
62 * <p>Characters will be chosen from the set of all characters.</p>
63 *
64 * @param count the length of random string to create
65 * @return the random string
66 */
67 public static String random(int count) {
68 return random(count, false, false);
69 }
70
71 /**
72 * <p>Creates a random string whose length is the number of characters
73 * specified.</p>
74 *
75 * <p>Characters will be chosen from the set of characters whose
76 * ASCII value is between {@code 32} and {@code 126} (inclusive).</p>
77 *
78 * @param count the length of random string to create
79 * @return the random string
80 */
81 public static String randomAscii(int count) {
82 return random(count, 32, 127, false, false);
83 }
84
85 /**
86 * <p>Creates a random string whose length is the number of characters
87 * specified.</p>
88 *
89 * <p>Characters will be chosen from the set of alphabetic
90 * characters.</p>
91 *
92 * @param count the length of random string to create
93 * @return the random string
94 */
95 public static String randomAlphabetic(int count) {
96 return random(count, true, false);
97 }
98
99 /**
100 * <p>Creates a random string whose length is the number of characters
101 * specified.</p>
102 *
103 * <p>Characters will be chosen from the set of alpha-numeric
104 * characters.</p>
105 *
106 * @param count the length of random string to create
107 * @return the random string
108 */
109 public static String randomAlphanumeric(int count) {
110 return random(count, true, true);
111 }
112
113 /**
114 * <p>Creates a random string whose length is the number of characters
115 * specified.</p>
116 *
117 * <p>Characters will be chosen from the set of numeric
118 * characters.</p>
119 *
120 * @param count the length of random string to create
121 * @return the random string
122 */
123 public static String randomNumeric(int count) {
124 return random(count, false, true);
125 }
126
127 /**
128 * <p>Creates a random string whose length is the number of characters
129 * specified.</p>
130 *
131 * <p>Characters will be chosen from the set of alpha-numeric
132 * characters as indicated by the arguments.</p>
133 *
134 * @param count the length of random string to create
135 * @param letters if {@code true}, generated string will include
136 * alphabetic characters
137 * @param numbers if {@code true}, generated string will include
138 * numeric characters
139 * @return the random string
140 */
141 public static String random(int count, boolean letters, boolean numbers) {
142 return random(count, 0, 0, letters, numbers);
143 }
144
145 /**
146 * <p>Creates a random string whose length is the number of characters
147 * specified.</p>
148 *
149 * <p>Characters will be chosen from the set of alpha-numeric
150 * characters as indicated by the arguments.</p>
151 *
152 * @param count the length of random string to create
153 * @param start the position in set of chars to start at
154 * @param end the position in set of chars to end before
155 * @param letters if {@code true}, generated string will include
156 * alphabetic characters
157 * @param numbers if {@code true}, generated string will include
158 * numeric characters
159 * @return the random string
160 */
161 public static String random(int count, int start, int end, boolean letters, boolean numbers) {
162 return random(count, start, end, letters, numbers, null, RANDOM);
163 }
164
165 /**
166 * <p>Creates a random string based on a variety of options, using
167 * default source of randomness.</p>
168 *
169 * <p>This method has exactly the same semantics as
170 * {@link #random(int,int,int,boolean,boolean,char[],Random)}, but
171 * instead of using an externally supplied source of randomness, it uses
172 * the internal static {@link Random} instance.</p>
173 *
174 * @param count the length of random string to create
175 * @param start the position in set of chars to start at
176 * @param end the position in set of chars to end before
177 * @param letters only allow letters?
178 * @param numbers only allow numbers?
179 * @param chars the set of chars to choose randoms from.
180 * If {@code null}, then it will use the set of all chars.
181 * @return the random string
182 * @throws ArrayIndexOutOfBoundsException if there are not
183 * {@code (end - start) + 1} characters in the set array.
184 */
185 public static String random(int count, int start, int end, boolean letters, boolean numbers, char... chars) {
186 return random(count, start, end, letters, numbers, chars, RANDOM);
187 }
188
189 /**
190 * <p>Creates a random string based on a variety of options, using
191 * supplied source of randomness.</p>
192 *
193 * <p>If start and end are both {@code 0}, start and end are set
194 * to {@code ' '} and {@code 'z'}, the ASCII printable
195 * characters, will be used, unless letters and numbers are both
196 * {@code false}, in which case, start and end are set to
197 * {@code 0} and {@code Integer.MAX_VALUE}.
198 *
199 * <p>If set is not {@code null}, characters between start and
200 * end are chosen.</p>
201 *
202 * <p>This method accepts a user-supplied {@link Random}
203 * instance to use as a source of randomness. By seeding a single
204 * {@link Random} instance with a fixed seed and using it for each call,
205 * the same random sequence of strings can be generated repeatedly
206 * and predictably.</p>
207 *
208 * @param count the length of random string to create
209 * @param start the position in set of chars to start at
210 * @param end the position in set of chars to end before
211 * @param letters only allow letters?
212 * @param numbers only allow numbers?
213 * @param chars the set of chars to choose randoms from.
214 * If {@code null}, then it will use the set of all chars.
215 * @param random a source of randomness.
216 * @return the random string
217 * @throws ArrayIndexOutOfBoundsException if there are not
218 * {@code (end - start) + 1} characters in the set array.
219 * @throws IllegalArgumentException if {@code count} &lt; 0.
220 * @since 2.0
221 */
222 public static String random(int count, int start, int end, boolean letters, boolean numbers,
223 char[] chars, Random random) {
224 if (count == 0) {
225 return "";
226 } else if (count < 0) {
227 throw new IllegalArgumentException("Requested random string length " + count + " is less than 0.");
228 }
229 if ((start == 0) && (end == 0)) {
230 end = 'z' + 1;
231 start = ' ';
232 if (!letters && !numbers) {
233 start = 0;
234 end = Integer.MAX_VALUE;
235 }
236 }
237
238 char[] buffer = new char[count];
239 int gap = end - start;
240
241 while (count-- != 0) {
242 char ch;
243 if (chars == null) {
244 ch = (char) (random.nextInt(gap) + start);
245 } else {
246 ch = chars[random.nextInt(gap) + start];
247 }
248 if ((letters && Character.isLetter(ch))
249 || (numbers && Character.isDigit(ch))
250 || (!letters && !numbers)) {
251 if(ch >= 56320 && ch <= 57343) {
252 if(count == 0) {
253 count++;
254 } else {
255 // low surrogate, insert high surrogate after putting it in
256 buffer[count] = ch;
257 count--;
258 buffer[count] = (char) (55296 + random.nextInt(128));
259 }
260 } else if(ch >= 55296 && ch <= 56191) {
261 if(count == 0) {
262 count++;
263 } else {
264 // high surrogate, insert low surrogate before putting it in
265 buffer[count] = (char) (56320 + random.nextInt(128));
266 count--;
267 buffer[count] = ch;
268 }
269 } else if(ch >= 56192 && ch <= 56319) {
270 // private high surrogate, no effing clue, so skip it
271 count++;
272 } else {
273 buffer[count] = ch;
274 }
275 } else {
276 count++;
277 }
278 }
279 return new String(buffer);
280 }
281
282 /**
283 * <p>Creates a random string whose length is the number of characters
284 * specified.</p>
285 *
286 * <p>Characters will be chosen from the set of characters
287 * specified.</p>
288 *
289 * @param count the length of random string to create
290 * @param chars the String containing the set of characters to use,
291 * may be null
292 * @return the random string
293 * @throws IllegalArgumentException if {@code count} &lt; 0.
294 */
295 public static String random(int count, String chars) {
296 if (chars == null) {
297 return random(count, 0, 0, false, false, null, RANDOM);
298 }
299 return random(count, chars.toCharArray());
300 }
301
302 /**
303 * <p>Creates a random string whose length is the number of characters
304 * specified.</p>
305 *
306 * <p>Characters will be chosen from the set of characters specified.</p>
307 *
308 * @param count the length of random string to create
309 * @param chars the character array containing the set of characters to use,
310 * may be null
311 * @return the random string
312 * @throws IllegalArgumentException if {@code count} &lt; 0.
313 */
314 public static String random(int count, char... chars) {
315 if (chars == null) {
316 return random(count, 0, 0, false, false, null, RANDOM);
317 }
318 return random(count, 0, chars.length, false, false, chars, RANDOM);
319 }
320
321 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.io.Serializable;
19 import java.util.Comparator;
20
21 /**
22 * <p>An immutable range of objects from a minimum to maximum point inclusive.</p>
23 *
24 * <p>The objects need to either be implementations of {@code Comparable}
25 * or you need to supply a {@code Comparator}. </p>
26 *
27 * <p>#ThreadSafe# if the objects and comparator are thread-safe</p>
28 *
29 * @since 3.0
30 * @version $Id: Range.java 1147537 2011-07-17 06:10:37Z mbenson $
31 */
32 public final class Range<T> implements Serializable {
33
34 /**
35 * Serialization version.
36 * @see java.io.Serializable
37 */
38 private static final long serialVersionUID = 1L;
39
40 /**
41 * The ordering scheme used in this range.
42 */
43 private final Comparator<T> comparator;
44 /**
45 * The minimum value in this range (inclusive).
46 */
47 private final T minimum;
48 /**
49 * The maximum value in this range (inclusive).
50 */
51 private final T maximum;
52 /**
53 * Cached output hashCode (class is immutable).
54 */
55 private transient int hashCode;
56 /**
57 * Cached output toString (class is immutable).
58 */
59 private transient String toString;
60
61 /**
62 * <p>Obtains a range using the specified element as both the minimum
63 * and maximum in this range.</p>
64 *
65 * <p>The range uses the natural ordering of the elements to determine where
66 * values lie in the range.</p>
67 *
68 * @param <T> the type of the elements in this range
69 * @param element the value to use for this range, not null
70 * @return the range object, not null
71 * @throws IllegalArgumentException if the element is null
72 * @throws ClassCastException if the element is not {@code Comparable}
73 */
74 public static <T extends Comparable<T>> Range<T> is(T element) {
75 return between(element, element, null);
76 }
77
78 /**
79 * <p>Obtains a range using the specified element as both the minimum
80 * and maximum in this range.</p>
81 *
82 * <p>The range uses the specified {@code Comparator} to determine where
83 * values lie in the range.</p>
84 *
85 * @param <T> the type of the elements in this range
86 * @param element the value to use for this range, must not be {@code null}
87 * @param comparator the comparator to be used, null for natural ordering
88 * @return the range object, not null
89 * @throws IllegalArgumentException if the element is null
90 * @throws ClassCastException if using natural ordering and the elements are not {@code Comparable}
91 */
92 public static <T> Range<T> is(T element, Comparator<T> comparator) {
93 return between(element, element, comparator);
94 }
95
96 /**
97 * <p>Obtains a range with the specified minimum and maximum values (both inclusive).</p>
98 *
99 * <p>The range uses the natural ordering of the elements to determine where
100 * values lie in the range.</p>
101 *
102 * <p>The arguments may be passed in the order (min,max) or (max,min).
103 * The getMinimum and getMaximum methods will return the correct values.</p>
104 *
105 * @param <T> the type of the elements in this range
106 * @param fromInclusive the first value that defines the edge of the range, inclusive
107 * @param toInclusive the second value that defines the edge of the range, inclusive
108 * @return the range object, not null
109 * @throws IllegalArgumentException if either element is null
110 * @throws ClassCastException if the elements are not {@code Comparable}
111 */
112 public static <T extends Comparable<T>> Range<T> between(T fromInclusive, T toInclusive) {
113 return between(fromInclusive, toInclusive, null);
114 }
115
116 /**
117 * <p>Obtains a range with the specified minimum and maximum values (both inclusive).</p>
118 *
119 * <p>The range uses the specified {@code Comparator} to determine where
120 * values lie in the range.</p>
121 *
122 * <p>The arguments may be passed in the order (min,max) or (max,min).
123 * The getMinimum and getMaximum methods will return the correct values.</p>
124 *
125 * @param <T> the type of the elements in this range
126 * @param fromInclusive the first value that defines the edge of the range, inclusive
127 * @param toInclusive the second value that defines the edge of the range, inclusive
128 * @param comparator the comparator to be used, null for natural ordering
129 * @return the range object, not null
130 * @throws IllegalArgumentException if either element is null
131 * @throws ClassCastException if using natural ordering and the elements are not {@code Comparable}
132 */
133 public static <T> Range<T> between(T fromInclusive, T toInclusive, Comparator<T> comparator) {
134 return new Range<T>(fromInclusive, toInclusive, comparator);
135 }
136
137 /**
138 * Creates an instance.
139 *
140 * @param element1 the first element, not null
141 * @param element2 the second element, not null
142 * @param comparator the comparator to be used, null for natural ordering
143 */
144 @SuppressWarnings("unchecked")
145 private Range(T element1, T element2, Comparator<T> comparator) {
146 if (element1 == null || element2 == null) {
147 throw new IllegalArgumentException("Elements in a range must not be null: element1=" +
148 element1 + ", element2=" + element2);
149 }
150 if (comparator == null) {
151 comparator = ComparableComparator.INSTANCE;
152 }
153 if (comparator.compare(element1, element2) < 1) {
154 this.minimum = element1;
155 this.maximum = element2;
156 } else {
157 this.minimum = element2;
158 this.maximum = element1;
159 }
160 this.comparator = comparator;
161 }
162
163 // Accessors
164 //--------------------------------------------------------------------
165
166 /**
167 * <p>Gets the minimum value in this range.</p>
168 *
169 * @return the minimum value in this range, not null
170 */
171 public T getMinimum() {
172 return minimum;
173 }
174
175 /**
176 * <p>Gets the maximum value in this range.</p>
177 *
178 * @return the maximum value in this range, not null
179 */
180 public T getMaximum() {
181 return maximum;
182 }
183
184 /**
185 * <p>Gets the comparator being used to determine if objects are within the range.</p>
186 *
187 * <p>Natural ordering uses an internal comparator implementation, thus this
188 * method never returns null. See {@link #isNaturalOrdering()}.</p>
189 *
190 * @return the comparator being used, not null
191 */
192 public Comparator<T> getComparator() {
193 return comparator;
194 }
195
196 /**
197 * <p>Whether or not the Range is using the natural ordering of the elements.</p>
198 *
199 * <p>Natural ordering uses an internal comparator implementation, thus this
200 * method is the only way to check if a null comparator was specified.</p>
201 *
202 * @return true if using natural ordering
203 */
204 public boolean isNaturalOrdering() {
205 return comparator == ComparableComparator.INSTANCE;
206 }
207
208 // Element tests
209 //--------------------------------------------------------------------
210
211 /**
212 * <p>Checks whether the specified element occurs within this range.</p>
213 *
214 * @param element the element to check for, null returns false
215 * @return true if the specified element occurs within this range
216 */
217 public boolean contains(T element) {
218 if (element == null) {
219 return false;
220 }
221 return (comparator.compare(element, minimum) > -1) && (comparator.compare(element, maximum) < 1);
222 }
223
224 /**
225 * <p>Checks whether this range is after the specified element.</p>
226 *
227 * @param element the element to check for, null returns false
228 * @return true if this range is entirely after the specified element
229 */
230 public boolean isAfter(T element) {
231 if (element == null) {
232 return false;
233 }
234 return comparator.compare(element, minimum) < 0;
235 }
236
237 /**
238 * <p>Checks whether this range starts with the specified element.</p>
239 *
240 * @param element the element to check for, null returns false
241 * @return true if the specified element occurs within this range
242 */
243 public boolean isStartedBy(T element) {
244 if (element == null) {
245 return false;
246 }
247 return comparator.compare(element, minimum) == 0;
248 }
249
250 /**
251 * <p>Checks whether this range starts with the specified element.</p>
252 *
253 * @param element the element to check for, null returns false
254 * @return true if the specified element occurs within this range
255 */
256 public boolean isEndedBy(T element) {
257 if (element == null) {
258 return false;
259 }
260 return comparator.compare(element, maximum) == 0;
261 }
262
263 /**
264 * <p>Checks whether this range is before the specified element.</p>
265 *
266 * @param element the element to check for, null returns false
267 * @return true if this range is entirely before the specified element
268 */
269 public boolean isBefore(T element) {
270 if (element == null) {
271 return false;
272 }
273 return comparator.compare(element, maximum) > 0;
274 }
275
276 /**
277 * <p>Checks where the specified element occurs relative to this range.</p>
278 *
279 * <p>The API is reminiscent of the Comparable interface returning {@code -1} if
280 * the element is before the range, {@code 0} if contained within the range and
281 * {@code 1} if the element is after the range. </p>
282 *
283 * @param element the element to check for, not null
284 * @return -1, 0 or +1 depending on the element's location relative to the range
285 */
286 public int elementCompareTo(T element) {
287 if (element == null) {
288 // Comparable API says throw NPE on null
289 throw new NullPointerException("Element is null");
290 }
291 if (isAfter(element)) {
292 return -1;
293 } else if (isBefore(element)) {
294 return 1;
295 } else {
296 return 0;
297 }
298 }
299
300 // Range tests
301 //--------------------------------------------------------------------
302
303 /**
304 * <p>Checks whether this range contains all the elements of the specified range.</p>
305 *
306 * <p>This method may fail if the ranges have two different comparators or element types.</p>
307 *
308 * @param otherRange the range to check, null returns false
309 * @return true if this range contains the specified range
310 * @throws RuntimeException if ranges cannot be compared
311 */
312 public boolean containsRange(Range<T> otherRange) {
313 if (otherRange == null) {
314 return false;
315 }
316 return contains(otherRange.minimum)
317 && contains(otherRange.maximum);
318 }
319
320 /**
321 * <p>Checks whether this range is completely after the specified range.</p>
322 *
323 * <p>This method may fail if the ranges have two different comparators or element types.</p>
324 *
325 * @param otherRange the range to check, null returns false
326 * @return true if this range is completely after the specified range
327 * @throws RuntimeException if ranges cannot be compared
328 */
329 public boolean isAfterRange(Range<T> otherRange) {
330 if (otherRange == null) {
331 return false;
332 }
333 return isAfter(otherRange.maximum);
334 }
335
336 /**
337 * <p>Checks whether this range is overlapped by the specified range.</p>
338 *
339 * <p>Two ranges overlap if there is at least one element in common.</p>
340 *
341 * <p>This method may fail if the ranges have two different comparators or element types.</p>
342 *
343 * @param otherRange the range to test, null returns false
344 * @return true if the specified range overlaps with this
345 * range; otherwise, {@code false}
346 * @throws RuntimeException if ranges cannot be compared
347 */
348 public boolean isOverlappedBy(Range<T> otherRange) {
349 if (otherRange == null) {
350 return false;
351 }
352 return otherRange.contains(minimum)
353 || otherRange.contains(maximum)
354 || contains(otherRange.minimum);
355 }
356
357 /**
358 * <p>Checks whether this range is completely before the specified range.</p>
359 *
360 * <p>This method may fail if the ranges have two different comparators or element types.</p>
361 *
362 * @param otherRange the range to check, null returns false
363 * @return true if this range is completely before the specified range
364 * @throws RuntimeException if ranges cannot be compared
365 */
366 public boolean isBeforeRange(Range<T> otherRange) {
367 if (otherRange == null) {
368 return false;
369 }
370 return isBefore(otherRange.minimum);
371 }
372
373 /**
374 * Calculate the intersection of {@code this} and an overlapping Range.
375 * @param other overlapping Range
376 * @return range representing the intersection of {@code this} and {@code other} ({@code this} if equal)
377 * @throws IllegalArgumentException if {@code other} does not overlap {@code this}
378 * @since 3.0.1
379 */
380 public Range<T> intersectionWith(Range<T> other) {
381 if (!this.isOverlappedBy(other)) {
382 throw new IllegalArgumentException(String.format(
383 "Cannot calculate intersection with non-overlapping range %s", other));
384 }
385 if (this.equals(other)) {
386 return this;
387 }
388 T min = getComparator().compare(minimum, other.minimum) < 0 ? other.minimum : minimum;
389 T max = getComparator().compare(maximum, other.maximum) < 0 ? maximum : other.maximum;
390 return between(min, max, getComparator());
391 }
392
393 // Basics
394 //--------------------------------------------------------------------
395
396 /**
397 * <p>Compares this range to another object to test if they are equal.</p>.
398 *
399 * <p>To be equal, the minimum and maximum values must be equal, which
400 * ignores any differences in the comparator.</p>
401 *
402 * @param obj the reference object with which to compare
403 * @return true if this object is equal
404 */
405 @Override
406 public boolean equals(Object obj) {
407 if (obj == this) {
408 return true;
409 } else if (obj == null || obj.getClass() != getClass()) {
410 return false;
411 } else {
412 @SuppressWarnings("unchecked") // OK because we checked the class above
413 Range<T> range = (Range<T>) obj;
414 return minimum.equals(range.minimum) &&
415 maximum.equals(range.maximum);
416 }
417 }
418
419 /**
420 * <p>Gets a suitable hash code for the range.</p>
421 *
422 * @return a hash code value for this object
423 */
424 @Override
425 public int hashCode() {
426 int result = hashCode;
427 if (hashCode == 0) {
428 result = 17;
429 result = 37 * result + getClass().hashCode();
430 result = 37 * result + minimum.hashCode();
431 result = 37 * result + maximum.hashCode();
432 hashCode = result;
433 }
434 return result;
435 }
436
437 /**
438 * <p>Gets the range as a {@code String}.</p>
439 *
440 * <p>The format of the String is '[<i>min</i>..<i>max</i>]'.</p>
441 *
442 * @return the {@code String} representation of this range
443 */
444 @Override
445 public String toString() {
446 String result = toString;
447 if (result == null) {
448 StringBuilder buf = new StringBuilder(32);
449 buf.append('[');
450 buf.append(minimum);
451 buf.append("..");
452 buf.append(maximum);
453 buf.append(']');
454 result = buf.toString();
455 toString = result;
456 }
457 return result;
458 }
459
460 /**
461 * <p>Formats the receiver using the given format.</p>
462 *
463 * <p>This uses {@link java.util.Formattable} to perform the formatting. Three variables may
464 * be used to embed the minimum, maximum and comparator.
465 * Use {@code %1$s} for the minimum element, {@code %2$s} for the maximum element
466 * and {@code %3$s} for the comparator.
467 * The default format used by {@code toString()} is {@code [%1$s..%2$s]}.</p>
468 *
469 * @param format the format string, optionally containing {@code %1$s}, {@code %2$s} and {@code %3$s}, not null
470 * @return the formatted string, not null
471 */
472 public String toString(String format) {
473 return String.format(format, minimum, maximum, comparator);
474 }
475
476 //-----------------------------------------------------------------------
477 @SuppressWarnings({"rawtypes", "unchecked"})
478 private enum ComparableComparator implements Comparator {
479 INSTANCE;
480 /**
481 * Comparable based compare implementation.
482 *
483 * @param obj1 left hand side of comparison
484 * @param obj2 right hand side of comparison
485 * @return negative, 0, positive comparison value
486 */
487 public int compare(Object obj1, Object obj2) {
488 return ((Comparable) obj1).compareTo(obj2);
489 }
490 }
491
492 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 /**
19 * <p>Exception thrown when the Serialization process fails.</p>
20 *
21 * <p>The original error is wrapped within this one.</p>
22 *
23 * <p>#NotThreadSafe# because Throwable is not threadsafe</p>
24 * @since 1.0
25 * @version $Id: SerializationException.java 1088899 2011-04-05 05:31:27Z bayard $
26 */
27 public class SerializationException extends RuntimeException {
28
29 /**
30 * Required for serialization support.
31 *
32 * @see java.io.Serializable
33 */
34 private static final long serialVersionUID = 4029025366392702726L;
35
36 /**
37 * <p>Constructs a new {@code SerializationException} without specified
38 * detail message.</p>
39 */
40 public SerializationException() {
41 super();
42 }
43
44 /**
45 * <p>Constructs a new {@code SerializationException} with specified
46 * detail message.</p>
47 *
48 * @param msg The error message.
49 */
50 public SerializationException(String msg) {
51 super(msg);
52 }
53
54 /**
55 * <p>Constructs a new {@code SerializationException} with specified
56 * nested {@code Throwable}.</p>
57 *
58 * @param cause The {@code Exception} or {@code Error}
59 * that caused this exception to be thrown.
60 */
61 public SerializationException(Throwable cause) {
62 super(cause);
63 }
64
65 /**
66 * <p>Constructs a new {@code SerializationException} with specified
67 * detail message and nested {@code Throwable}.</p>
68 *
69 * @param msg The error message.
70 * @param cause The {@code Exception} or {@code Error}
71 * that caused this exception to be thrown.
72 */
73 public SerializationException(String msg, Throwable cause) {
74 super(msg, cause);
75 }
76
77 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.io.ByteArrayInputStream;
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.ObjectInputStream;
23 import java.io.ObjectOutputStream;
24 import java.io.ObjectStreamClass;
25 import java.io.OutputStream;
26 import java.io.Serializable;
27
28 /**
29 * <p>Assists with the serialization process and performs additional functionality based
30 * on serialization.</p>
31 * <p>
32 * <ul>
33 * <li>Deep clone using serialization
34 * <li>Serialize managing finally and IOException
35 * <li>Deserialize managing finally and IOException
36 * </ul>
37 *
38 * <p>This class throws exceptions for invalid {@code null} inputs.
39 * Each method documents its behaviour in more detail.</p>
40 *
41 * <p>#ThreadSafe#</p>
42 * @since 1.0
43 * @version $Id: SerializationUtils.java 1153046 2011-08-02 06:57:04Z bayard $
44 */
45 public class SerializationUtils {
46
47 /**
48 * <p>SerializationUtils instances should NOT be constructed in standard programming.
49 * Instead, the class should be used as {@code SerializationUtils.clone(object)}.</p>
50 *
51 * <p>This constructor is public to permit tools that require a JavaBean instance
52 * to operate.</p>
53 * @since 2.0
54 */
55 public SerializationUtils() {
56 super();
57 }
58
59 // Clone
60 //-----------------------------------------------------------------------
61 /**
62 * <p>Deep clone an {@code Object} using serialization.</p>
63 *
64 * <p>This is many times slower than writing clone methods by hand
65 * on all objects in your object graph. However, for complex object
66 * graphs, or for those that don't support deep cloning this can
67 * be a simple alternative implementation. Of course all the objects
68 * must be {@code Serializable}.</p>
69 *
70 * @param <T> the type of the object involved
71 * @param object the {@code Serializable} object to clone
72 * @return the cloned object
73 * @throws SerializationException (runtime) if the serialization fails
74 */
75 public static <T extends Serializable> T clone(T object) {
76 if (object == null) {
77 return null;
78 }
79 byte[] objectData = serialize(object);
80 ByteArrayInputStream bais = new ByteArrayInputStream(objectData);
81
82 ClassLoaderAwareObjectInputStream in = null;
83 try {
84 // stream closed in the finally
85 in = new ClassLoaderAwareObjectInputStream(bais, object.getClass().getClassLoader());
86 /*
87 * when we serialize and deserialize an object,
88 * it is reasonable to assume the deserialized object
89 * is of the same type as the original serialized object
90 */
91 return (T) in.readObject();
92
93 } catch (ClassNotFoundException ex) {
94 throw new SerializationException("ClassNotFoundException while reading cloned object data", ex);
95 } catch (IOException ex) {
96 throw new SerializationException("IOException while reading cloned object data", ex);
97 } finally {
98 try {
99 if (in != null) {
100 in.close();
101 }
102 } catch (IOException ex) {
103 throw new SerializationException("IOException on closing cloned object data InputStream.", ex);
104 }
105 }
106 }
107
108 // Serialize
109 //-----------------------------------------------------------------------
110 /**
111 * <p>Serializes an {@code Object} to the specified stream.</p>
112 *
113 * <p>The stream will be closed once the object is written.
114 * This avoids the need for a finally clause, and maybe also exception
115 * handling, in the application code.</p>
116 *
117 * <p>The stream passed in is not buffered internally within this method.
118 * This is the responsibility of your application if desired.</p>
119 *
120 * @param obj the object to serialize to bytes, may be null
121 * @param outputStream the stream to write to, must not be null
122 * @throws IllegalArgumentException if {@code outputStream} is {@code null}
123 * @throws SerializationException (runtime) if the serialization fails
124 */
125 public static void serialize(Serializable obj, OutputStream outputStream) {
126 if (outputStream == null) {
127 throw new IllegalArgumentException("The OutputStream must not be null");
128 }
129 ObjectOutputStream out = null;
130 try {
131 // stream closed in the finally
132 out = new ObjectOutputStream(outputStream);
133 out.writeObject(obj);
134
135 } catch (IOException ex) {
136 throw new SerializationException(ex);
137 } finally {
138 try {
139 if (out != null) {
140 out.close();
141 }
142 } catch (IOException ex) { // NOPMD
143 // ignore close exception
144 }
145 }
146 }
147
148 /**
149 * <p>Serializes an {@code Object} to a byte array for
150 * storage/serialization.</p>
151 *
152 * @param obj the object to serialize to bytes
153 * @return a byte[] with the converted Serializable
154 * @throws SerializationException (runtime) if the serialization fails
155 */
156 public static byte[] serialize(Serializable obj) {
157 ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
158 serialize(obj, baos);
159 return baos.toByteArray();
160 }
161
162 // Deserialize
163 //-----------------------------------------------------------------------
164 /**
165 * <p>Deserializes an {@code Object} from the specified stream.</p>
166 *
167 * <p>The stream will be closed once the object is written. This
168 * avoids the need for a finally clause, and maybe also exception
169 * handling, in the application code.</p>
170 *
171 * <p>The stream passed in is not buffered internally within this method.
172 * This is the responsibility of your application if desired.</p>
173 *
174 * @param inputStream the serialized object input stream, must not be null
175 * @return the deserialized object
176 * @throws IllegalArgumentException if {@code inputStream} is {@code null}
177 * @throws SerializationException (runtime) if the serialization fails
178 */
179 public static Object deserialize(InputStream inputStream) {
180 if (inputStream == null) {
181 throw new IllegalArgumentException("The InputStream must not be null");
182 }
183 ObjectInputStream in = null;
184 try {
185 // stream closed in the finally
186 in = new ObjectInputStream(inputStream);
187 return in.readObject();
188
189 } catch (ClassNotFoundException ex) {
190 throw new SerializationException(ex);
191 } catch (IOException ex) {
192 throw new SerializationException(ex);
193 } finally {
194 try {
195 if (in != null) {
196 in.close();
197 }
198 } catch (IOException ex) { // NOPMD
199 // ignore close exception
200 }
201 }
202 }
203
204 /**
205 * <p>Deserializes a single {@code Object} from an array of bytes.</p>
206 *
207 * @param objectData the serialized object, must not be null
208 * @return the deserialized object
209 * @throws IllegalArgumentException if {@code objectData} is {@code null}
210 * @throws SerializationException (runtime) if the serialization fails
211 */
212 public static Object deserialize(byte[] objectData) {
213 if (objectData == null) {
214 throw new IllegalArgumentException("The byte[] must not be null");
215 }
216 ByteArrayInputStream bais = new ByteArrayInputStream(objectData);
217 return deserialize(bais);
218 }
219
220 /**
221 * <p>Custom specialization of the standard JDK {@link java.io.ObjectInputStream}
222 * that uses a custom <code>ClassLoader</code> to resolve a class.
223 * If the specified <code>ClassLoader</code> is not able to resolve the class,
224 * the context classloader of the current thread will be used.
225 * This way, the standard deserialization work also in web-application
226 * containers and application servers, no matter in which of the
227 * <code>ClassLoader</code> the particular class that encapsulates
228 * serialization/deserialization lives. </p>
229 *
230 * <p>For more in-depth information about the problem for which this
231 * class here is a workaround, see the JIRA issue LANG-626. </p>
232 */
233 static class ClassLoaderAwareObjectInputStream extends ObjectInputStream {
234 private ClassLoader classLoader;
235
236 /**
237 * Constructor.
238 * @param in The <code>InputStream</code>.
239 * @param classLoader classloader to use
240 * @throws IOException if an I/O error occurs while reading stream header.
241 * @see java.io.ObjectInputStream
242 */
243 public ClassLoaderAwareObjectInputStream(InputStream in, ClassLoader classLoader) throws IOException {
244 super(in);
245 this.classLoader = classLoader;
246 }
247
248 /**
249 * Overriden version that uses the parametrized <code>ClassLoader</code> or the <code>ClassLoader</code>
250 * of the current <code>Thread</code> to resolve the class.
251 * @param desc An instance of class <code>ObjectStreamClass</code>.
252 * @return A <code>Class</code> object corresponding to <code>desc</code>.
253 * @throws IOException Any of the usual Input/Output exceptions.
254 * @throws ClassNotFoundException If class of a serialized object cannot be found.
255 */
256 @Override
257 protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
258 String name = desc.getName();
259 try {
260 return Class.forName(name, false, classLoader);
261 } catch (ClassNotFoundException ex) {
262 return Class.forName(name, false, Thread.currentThread().getContextClassLoader());
263 }
264 }
265
266 }
267
268 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.io.IOException;
19 import java.io.Writer;
20
21 import org.apache.commons.lang3.text.translate.AggregateTranslator;
22 import org.apache.commons.lang3.text.translate.CharSequenceTranslator;
23 import org.apache.commons.lang3.text.translate.EntityArrays;
24 import org.apache.commons.lang3.text.translate.LookupTranslator;
25 import org.apache.commons.lang3.text.translate.NumericEntityUnescaper;
26 import org.apache.commons.lang3.text.translate.OctalUnescaper;
27 import org.apache.commons.lang3.text.translate.UnicodeEscaper;
28 import org.apache.commons.lang3.text.translate.UnicodeUnescaper;
29
30 /**
31 * <p>Escapes and unescapes {@code String}s for
32 * Java, Java Script, HTML and XML.</p>
33 *
34 * <p>#ThreadSafe#</p>
35 * @since 2.0
36 * @version $Id: StringEscapeUtils.java 1148520 2011-07-19 20:53:23Z ggregory $
37 */
38 public class StringEscapeUtils {
39
40 /* ESCAPE TRANSLATORS */
41
42 /**
43 * Translator object for escaping Java.
44 *
45 * While {@link #escapeJava(String)} is the expected method of use, this
46 * object allows the Java escaping functionality to be used
47 * as the foundation for a custom translator.
48 *
49 * @since 3.0
50 */
51 public static final CharSequenceTranslator ESCAPE_JAVA =
52 new LookupTranslator(
53 new String[][] {
54 {"\"", "\\\""},
55 {"\\", "\\\\"},
56 }).with(
57 new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE())
58 ).with(
59 UnicodeEscaper.outsideOf(32, 0x7f)
60 );
61
62 /**
63 * Translator object for escaping EcmaScript/JavaScript.
64 *
65 * While {@link #escapeEcmaScript(String)} is the expected method of use, this
66 * object allows the EcmaScript escaping functionality to be used
67 * as the foundation for a custom translator.
68 *
69 * @since 3.0
70 */
71 public static final CharSequenceTranslator ESCAPE_ECMASCRIPT =
72 new AggregateTranslator(
73 new LookupTranslator(
74 new String[][] {
75 {"'", "\\'"},
76 {"\"", "\\\""},
77 {"\\", "\\\\"},
78 {"/", "\\/"}
79 }),
80 new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE()),
81 UnicodeEscaper.outsideOf(32, 0x7f)
82 );
83
84 /**
85 * Translator object for escaping XML.
86 *
87 * While {@link #escapeXml(String)} is the expected method of use, this
88 * object allows the XML escaping functionality to be used
89 * as the foundation for a custom translator.
90 *
91 * @since 3.0
92 */
93 public static final CharSequenceTranslator ESCAPE_XML =
94 new AggregateTranslator(
95 new LookupTranslator(EntityArrays.BASIC_ESCAPE()),
96 new LookupTranslator(EntityArrays.APOS_ESCAPE())
97 );
98
99 /**
100 * Translator object for escaping HTML version 3.0.
101 *
102 * While {@link #escapeHtml3(String)} is the expected method of use, this
103 * object allows the HTML escaping functionality to be used
104 * as the foundation for a custom translator.
105 *
106 * @since 3.0
107 */
108 public static final CharSequenceTranslator ESCAPE_HTML3 =
109 new AggregateTranslator(
110 new LookupTranslator(EntityArrays.BASIC_ESCAPE()),
111 new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE())
112 );
113
114 /**
115 * Translator object for escaping HTML version 4.0.
116 *
117 * While {@link #escapeHtml4(String)} is the expected method of use, this
118 * object allows the HTML escaping functionality to be used
119 * as the foundation for a custom translator.
120 *
121 * @since 3.0
122 */
123 public static final CharSequenceTranslator ESCAPE_HTML4 =
124 new AggregateTranslator(
125 new LookupTranslator(EntityArrays.BASIC_ESCAPE()),
126 new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE()),
127 new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE())
128 );
129
130 /**
131 * Translator object for escaping individual Comma Separated Values.
132 *
133 * While {@link #escapeCsv(String)} is the expected method of use, this
134 * object allows the CSV escaping functionality to be used
135 * as the foundation for a custom translator.
136 *
137 * @since 3.0
138 */
139 public static final CharSequenceTranslator ESCAPE_CSV = new CsvEscaper();
140
141 // TODO: Create a parent class - 'SinglePassTranslator' ?
142 // It would handle the index checking + length returning,
143 // and could also have an optimization check method.
144 static class CsvEscaper extends CharSequenceTranslator {
145
146 private static final char CSV_DELIMITER = ',';
147 private static final char CSV_QUOTE = '"';
148 private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE);
149 private static final char[] CSV_SEARCH_CHARS =
150 new char[] {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF};
151
152 @Override
153 public int translate(CharSequence input, int index, Writer out) throws IOException {
154
155 if(index != 0) {
156 throw new IllegalStateException("CsvEscaper should never reach the [1] index");
157 }
158
159 if (StringUtils.containsNone(input.toString(), CSV_SEARCH_CHARS)) {
160 out.write(input.toString());
161 } else {
162 out.write(CSV_QUOTE);
163 out.write(StringUtils.replace(input.toString(), CSV_QUOTE_STR, CSV_QUOTE_STR + CSV_QUOTE_STR));
164 out.write(CSV_QUOTE);
165 }
166 return input.length();
167 }
168 }
169
170 /* UNESCAPE TRANSLATORS */
171
172 /**
173 * Translator object for unescaping escaped Java.
174 *
175 * While {@link #unescapeJava(String)} is the expected method of use, this
176 * object allows the Java unescaping functionality to be used
177 * as the foundation for a custom translator.
178 *
179 * @since 3.0
180 */
181 // TODO: throw "illegal character: \92" as an Exception if a \ on the end of the Java (as per the compiler)?
182 public static final CharSequenceTranslator UNESCAPE_JAVA =
183 new AggregateTranslator(
184 new OctalUnescaper(), // .between('\1', '\377'),
185 new UnicodeUnescaper(),
186 new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_UNESCAPE()),
187 new LookupTranslator(
188 new String[][] {
189 {"\\\\", "\\"},
190 {"\\\"", "\""},
191 {"\\'", "'"},
192 {"\\", ""}
193 })
194 );
195
196 /**
197 * Translator object for unescaping escaped EcmaScript.
198 *
199 * While {@link #unescapeEcmaScript(String)} is the expected method of use, this
200 * object allows the EcmaScript unescaping functionality to be used
201 * as the foundation for a custom translator.
202 *
203 * @since 3.0
204 */
205 public static final CharSequenceTranslator UNESCAPE_ECMASCRIPT = UNESCAPE_JAVA;
206
207 /**
208 * Translator object for unescaping escaped HTML 3.0.
209 *
210 * While {@link #unescapeHtml3(String)} is the expected method of use, this
211 * object allows the HTML unescaping functionality to be used
212 * as the foundation for a custom translator.
213 *
214 * @since 3.0
215 */
216 public static final CharSequenceTranslator UNESCAPE_HTML3 =
217 new AggregateTranslator(
218 new LookupTranslator(EntityArrays.BASIC_UNESCAPE()),
219 new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE()),
220 new NumericEntityUnescaper()
221 );
222
223 /**
224 * Translator object for unescaping escaped HTML 4.0.
225 *
226 * While {@link #unescapeHtml4(String)} is the expected method of use, this
227 * object allows the HTML unescaping functionality to be used
228 * as the foundation for a custom translator.
229 *
230 * @since 3.0
231 */
232 public static final CharSequenceTranslator UNESCAPE_HTML4 =
233 new AggregateTranslator(
234 new LookupTranslator(EntityArrays.BASIC_UNESCAPE()),
235 new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE()),
236 new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE()),
237 new NumericEntityUnescaper()
238 );
239
240 /**
241 * Translator object for unescaping escaped XML.
242 *
243 * While {@link #unescapeXml(String)} is the expected method of use, this
244 * object allows the XML unescaping functionality to be used
245 * as the foundation for a custom translator.
246 *
247 * @since 3.0
248 */
249 public static final CharSequenceTranslator UNESCAPE_XML =
250 new AggregateTranslator(
251 new LookupTranslator(EntityArrays.BASIC_UNESCAPE()),
252 new LookupTranslator(EntityArrays.APOS_UNESCAPE()),
253 new NumericEntityUnescaper()
254 );
255
256 /**
257 * Translator object for unescaping escaped Comma Separated Value entries.
258 *
259 * While {@link #unescapeCsv(String)} is the expected method of use, this
260 * object allows the CSV unescaping functionality to be used
261 * as the foundation for a custom translator.
262 *
263 * @since 3.0
264 */
265 public static final CharSequenceTranslator UNESCAPE_CSV = new CsvUnescaper();
266
267 static class CsvUnescaper extends CharSequenceTranslator {
268
269 private static final char CSV_DELIMITER = ',';
270 private static final char CSV_QUOTE = '"';
271 private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE);
272 private static final char[] CSV_SEARCH_CHARS =
273 new char[] {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF};
274
275 @Override
276 public int translate(CharSequence input, int index, Writer out) throws IOException {
277
278 if(index != 0) {
279 throw new IllegalStateException("CsvUnescaper should never reach the [1] index");
280 }
281
282 if ( input.charAt(0) != CSV_QUOTE || input.charAt(input.length() - 1) != CSV_QUOTE ) {
283 out.write(input.toString());
284 return input.length();
285 }
286
287 // strip quotes
288 String quoteless = input.subSequence(1, input.length() - 1).toString();
289
290 if ( StringUtils.containsAny(quoteless, CSV_SEARCH_CHARS) ) {
291 // deal with escaped quotes; ie) ""
292 out.write(StringUtils.replace(quoteless, CSV_QUOTE_STR + CSV_QUOTE_STR, CSV_QUOTE_STR));
293 } else {
294 out.write(input.toString());
295 }
296 return input.length();
297 }
298 }
299
300 /* Helper functions */
301
302 /**
303 * <p>{@code StringEscapeUtils} instances should NOT be constructed in
304 * standard programming.</p>
305 *
306 * <p>Instead, the class should be used as:
307 * <pre>StringEscapeUtils.escapeJava("foo");</pre></p>
308 *
309 * <p>This constructor is public to permit tools that require a JavaBean
310 * instance to operate.</p>
311 */
312 public StringEscapeUtils() {
313 super();
314 }
315
316 // Java and JavaScript
317 //--------------------------------------------------------------------------
318 /**
319 * <p>Escapes the characters in a {@code String} using Java String rules.</p>
320 *
321 * <p>Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
322 *
323 * <p>So a tab becomes the characters {@code '\\'} and
324 * {@code 't'}.</p>
325 *
326 * <p>The only difference between Java strings and JavaScript strings
327 * is that in JavaScript, a single quote and forward-slash (/) are escaped.</p>
328 *
329 * <p>Example:
330 * <pre>
331 * input string: He didn't say, "Stop!"
332 * output string: He didn't say, \"Stop!\"
333 * </pre>
334 * </p>
335 *
336 * @param input String to escape values in, may be null
337 * @return String with escaped values, {@code null} if null string input
338 */
339 public static final String escapeJava(String input) {
340 return ESCAPE_JAVA.translate(input);
341 }
342
343 /**
344 * <p>Escapes the characters in a {@code String} using EcmaScript String rules.</p>
345 * <p>Escapes any values it finds into their EcmaScript String form.
346 * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
347 *
348 * <p>So a tab becomes the characters {@code '\\'} and
349 * {@code 't'}.</p>
350 *
351 * <p>The only difference between Java strings and EcmaScript strings
352 * is that in EcmaScript, a single quote and forward-slash (/) are escaped.</p>
353 *
354 * <p>Note that EcmaScript is best known by the JavaScript and ActionScript dialects. </p>
355 *
356 * <p>Example:
357 * <pre>
358 * input string: He didn't say, "Stop!"
359 * output string: He didn\'t say, \"Stop!\"
360 * </pre>
361 * </p>
362 *
363 * @param input String to escape values in, may be null
364 * @return String with escaped values, {@code null} if null string input
365 *
366 * @since 3.0
367 */
368 public static final String escapeEcmaScript(String input) {
369 return ESCAPE_ECMASCRIPT.translate(input);
370 }
371
372 /**
373 * <p>Unescapes any Java literals found in the {@code String}.
374 * For example, it will turn a sequence of {@code '\'} and
375 * {@code 'n'} into a newline character, unless the {@code '\'}
376 * is preceded by another {@code '\'}.</p>
377 *
378 * @param input the {@code String} to unescape, may be null
379 * @return a new unescaped {@code String}, {@code null} if null string input
380 */
381 public static final String unescapeJava(String input) {
382 return UNESCAPE_JAVA.translate(input);
383 }
384
385 /**
386 * <p>Unescapes any EcmaScript literals found in the {@code String}.</p>
387 *
388 * <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
389 * into a newline character, unless the {@code '\'} is preceded by another
390 * {@code '\'}.</p>
391 *
392 * @see #unescapeJava(String)
393 * @param input the {@code String} to unescape, may be null
394 * @return A new unescaped {@code String}, {@code null} if null string input
395 *
396 * @since 3.0
397 */
398 public static final String unescapeEcmaScript(String input) {
399 return UNESCAPE_ECMASCRIPT.translate(input);
400 }
401
402 // HTML and XML
403 //--------------------------------------------------------------------------
404 /**
405 * <p>Escapes the characters in a {@code String} using HTML entities.</p>
406 *
407 * <p>
408 * For example:
409 * </p>
410 * <p><code>"bread" & "butter"</code></p>
411 * becomes:
412 * <p>
413 * <code>&amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;</code>.
414 * </p>
415 *
416 * <p>Supports all known HTML 4.0 entities, including funky accents.
417 * Note that the commonly used apostrophe escape character (&amp;apos;)
418 * is not a legal entity and so is not supported). </p>
419 *
420 * @param input the {@code String} to escape, may be null
421 * @return a new escaped {@code String}, {@code null} if null string input
422 *
423 * @see <a href="http://hotwired.lycos.com/webmonkey/reference/special_characters/">ISO Entities</a>
424 * @see <a href="http://www.w3.org/TR/REC-html32#latin1">HTML 3.2 Character Entities for ISO Latin-1</a>
425 * @see <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">HTML 4.0 Character entity references</a>
426 * @see <a href="http://www.w3.org/TR/html401/charset.html#h-5.3">HTML 4.01 Character References</a>
427 * @see <a href="http://www.w3.org/TR/html401/charset.html#code-position">HTML 4.01 Code positions</a>
428 *
429 * @since 3.0
430 */
431 public static final String escapeHtml4(String input) {
432 return ESCAPE_HTML4.translate(input);
433 }
434
435 /**
436 * <p>Escapes the characters in a {@code String} using HTML entities.</p>
437 * <p>Supports only the HTML 3.0 entities. </p>
438 *
439 * @param input the {@code String} to escape, may be null
440 * @return a new escaped {@code String}, {@code null} if null string input
441 *
442 * @since 3.0
443 */
444 public static final String escapeHtml3(String input) {
445 return ESCAPE_HTML3.translate(input);
446 }
447
448 //-----------------------------------------------------------------------
449 /**
450 * <p>Unescapes a string containing entity escapes to a string
451 * containing the actual Unicode characters corresponding to the
452 * escapes. Supports HTML 4.0 entities.</p>
453 *
454 * <p>For example, the string "&amp;lt;Fran&amp;ccedil;ais&amp;gt;"
455 * will become "&lt;Fran&ccedil;ais&gt;"</p>
456 *
457 * <p>If an entity is unrecognized, it is left alone, and inserted
458 * verbatim into the result string. e.g. "&amp;gt;&amp;zzzz;x" will
459 * become "&gt;&amp;zzzz;x".</p>
460 *
461 * @param input the {@code String} to unescape, may be null
462 * @return a new unescaped {@code String}, {@code null} if null string input
463 *
464 * @since 3.0
465 */
466 public static final String unescapeHtml4(String input) {
467 return UNESCAPE_HTML4.translate(input);
468 }
469
470 /**
471 * <p>Unescapes a string containing entity escapes to a string
472 * containing the actual Unicode characters corresponding to the
473 * escapes. Supports only HTML 3.0 entities.</p>
474 *
475 * @param input the {@code String} to unescape, may be null
476 * @return a new unescaped {@code String}, {@code null} if null string input
477 *
478 * @since 3.0
479 */
480 public static final String unescapeHtml3(String input) {
481 return UNESCAPE_HTML3.translate(input);
482 }
483
484 //-----------------------------------------------------------------------
485 /**
486 * <p>Escapes the characters in a {@code String} using XML entities.</p>
487 *
488 * <p>For example: <tt>"bread" & "butter"</tt> =>
489 * <tt>&amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;</tt>.
490 * </p>
491 *
492 * <p>Supports only the five basic XML entities (gt, lt, quot, amp, apos).
493 * Does not support DTDs or external entities.</p>
494 *
495 * <p>Note that Unicode characters greater than 0x7f are as of 3.0, no longer
496 * escaped. If you still wish this functionality, you can achieve it
497 * via the following:
498 * {@code StringEscapeUtils.ESCAPE_XML.with( NumericEntityEscaper.between(0x7f, Integer.MAX_VALUE) );}</p>
499 *
500 * @param input the {@code String} to escape, may be null
501 * @return a new escaped {@code String}, {@code null} if null string input
502 * @see #unescapeXml(java.lang.String)
503 */
504 public static final String escapeXml(String input) {
505 return ESCAPE_XML.translate(input);
506 }
507
508
509 //-----------------------------------------------------------------------
510 /**
511 * <p>Unescapes a string containing XML entity escapes to a string
512 * containing the actual Unicode characters corresponding to the
513 * escapes.</p>
514 *
515 * <p>Supports only the five basic XML entities (gt, lt, quot, amp, apos).
516 * Does not support DTDs or external entities.</p>
517 *
518 * <p>Note that numerical \\u Unicode codes are unescaped to their respective
519 * Unicode characters. This may change in future releases. </p>
520 *
521 * @param input the {@code String} to unescape, may be null
522 * @return a new unescaped {@code String}, {@code null} if null string input
523 * @see #escapeXml(String)
524 */
525 public static final String unescapeXml(String input) {
526 return UNESCAPE_XML.translate(input);
527 }
528
529
530 //-----------------------------------------------------------------------
531
532 /**
533 * <p>Returns a {@code String} value for a CSV column enclosed in double quotes,
534 * if required.</p>
535 *
536 * <p>If the value contains a comma, newline or double quote, then the
537 * String value is returned enclosed in double quotes.</p>
538 * </p>
539 *
540 * <p>Any double quote characters in the value are escaped with another double quote.</p>
541 *
542 * <p>If the value does not contain a comma, newline or double quote, then the
543 * String value is returned unchanged.</p>
544 * </p>
545 *
546 * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and
547 * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
548 *
549 * @param input the input CSV column String, may be null
550 * @return the input String, enclosed in double quotes if the value contains a comma,
551 * newline or double quote, {@code null} if null string input
552 * @since 2.4
553 */
554 public static final String escapeCsv(String input) {
555 return ESCAPE_CSV.translate(input);
556 }
557
558 /**
559 * <p>Returns a {@code String} value for an unescaped CSV column. </p>
560 *
561 * <p>If the value is enclosed in double quotes, and contains a comma, newline
562 * or double quote, then quotes are removed.
563 * </p>
564 *
565 * <p>Any double quote escaped characters (a pair of double quotes) are unescaped
566 * to just one double quote. </p>
567 *
568 * <p>If the value is not enclosed in double quotes, or is and does not contain a
569 * comma, newline or double quote, then the String value is returned unchanged.</p>
570 * </p>
571 *
572 * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and
573 * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
574 *
575 * @param input the input CSV column String, may be null
576 * @return the input String, with enclosing double quotes removed and embedded double
577 * quotes unescaped, {@code null} if null string input
578 * @since 2.4
579 */
580 public static final String unescapeCsv(String input) {
581 return UNESCAPE_CSV.translate(input);
582 }
583
584 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.lang.reflect.InvocationTargetException;
19 import java.lang.reflect.Method;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.regex.Pattern;
26
27 /**
28 * <p>Operations on {@link java.lang.String} that are
29 * {@code null} safe.</p>
30 *
31 * <ul>
32 * <li><b>IsEmpty/IsBlank</b>
33 * - checks if a String contains text</li>
34 * <li><b>Trim/Strip</b>
35 * - removes leading and trailing whitespace</li>
36 * <li><b>Equals</b>
37 * - compares two strings null-safe</li>
38 * <li><b>startsWith</b>
39 * - check if a String starts with a prefix null-safe</li>
40 * <li><b>endsWith</b>
41 * - check if a String ends with a suffix null-safe</li>
42 * <li><b>IndexOf/LastIndexOf/Contains</b>
43 * - null-safe index-of checks
44 * <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
45 * - index-of any of a set of Strings</li>
46 * <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
47 * - does String contains only/none/any of these characters</li>
48 * <li><b>Substring/Left/Right/Mid</b>
49 * - null-safe substring extractions</li>
50 * <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
51 * - substring extraction relative to other strings</li>
52 * <li><b>Split/Join</b>
53 * - splits a String into an array of substrings and vice versa</li>
54 * <li><b>Remove/Delete</b>
55 * - removes part of a String</li>
56 * <li><b>Replace/Overlay</b>
57 * - Searches a String and replaces one String with another</li>
58 * <li><b>Chomp/Chop</b>
59 * - removes the last part of a String</li>
60 * <li><b>LeftPad/RightPad/Center/Repeat</b>
61 * - pads a String</li>
62 * <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
63 * - changes the case of a String</li>
64 * <li><b>CountMatches</b>
65 * - counts the number of occurrences of one String in another</li>
66 * <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
67 * - checks the characters in a String</li>
68 * <li><b>DefaultString</b>
69 * - protects against a null input String</li>
70 * <li><b>Reverse/ReverseDelimited</b>
71 * - reverses a String</li>
72 * <li><b>Abbreviate</b>
73 * - abbreviates a string using ellipsis</li>
74 * <li><b>Difference</b>
75 * - compares Strings and reports on their differences</li>
76 * <li><b>LevenshteinDistance</b>
77 * - the number of changes needed to change one String into another</li>
78 * </ul>
79 *
80 * <p>The {@code StringUtils} class defines certain words related to
81 * String handling.</p>
82 *
83 * <ul>
84 * <li>null - {@code null}</li>
85 * <li>empty - a zero-length string ({@code ""})</li>
86 * <li>space - the space character ({@code ' '}, char 32)</li>
87 * <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
88 * <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
89 * </ul>
90 *
91 * <p>{@code StringUtils} handles {@code null} input Strings quietly.
92 * That is to say that a {@code null} input will return {@code null}.
93 * Where a {@code boolean} or {@code int} is being returned
94 * details vary by method.</p>
95 *
96 * <p>A side effect of the {@code null} handling is that a
97 * {@code NullPointerException} should be considered a bug in
98 * {@code StringUtils}.</p>
99 *
100 * <p>Methods in this class give sample code to explain their operation.
101 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
102 *
103 * <p>#ThreadSafe#</p>
104 * @see java.lang.String
105 * @since 1.0
106 * @version $Id: StringUtils.java 1153241 2011-08-02 18:49:52Z ggregory $
107 */
108 //@Immutable
109 public class StringUtils {
110 // Performance testing notes (JDK 1.4, Jul03, scolebourne)
111 // Whitespace:
112 // Character.isWhitespace() is faster than WHITESPACE.indexOf()
113 // where WHITESPACE is a string of all whitespace characters
114 //
115 // Character access:
116 // String.charAt(n) versus toCharArray(), then array[n]
117 // String.charAt(n) is about 15% worse for a 10K string
118 // They are about equal for a length 50 string
119 // String.charAt(n) is about 4 times better for a length 3 string
120 // String.charAt(n) is best bet overall
121 //
122 // Append:
123 // String.concat about twice as fast as StringBuffer.append
124 // (not sure who tested this)
125
126 /**
127 * The empty String {@code ""}.
128 * @since 2.0
129 */
130 public static final String EMPTY = "";
131
132 /**
133 * Represents a failed index search.
134 * @since 2.1
135 */
136 public static final int INDEX_NOT_FOUND = -1;
137
138 /**
139 * <p>The maximum size to which the padding constant(s) can expand.</p>
140 */
141 private static final int PAD_LIMIT = 8192;
142
143 /**
144 * A regex pattern for recognizing blocks of whitespace characters.
145 */
146 private static final Pattern WHITESPACE_BLOCK = Pattern.compile("\\s+");
147
148 /**
149 * <p>{@code StringUtils} instances should NOT be constructed in
150 * standard programming. Instead, the class should be used as
151 * {@code StringUtils.trim(" foo ");}.</p>
152 *
153 * <p>This constructor is public to permit tools that require a JavaBean
154 * instance to operate.</p>
155 */
156 public StringUtils() {
157 super();
158 }
159
160 // Empty checks
161 //-----------------------------------------------------------------------
162 /**
163 * <p>Checks if a CharSequence is empty ("") or null.</p>
164 *
165 * <pre>
166 * StringUtils.isEmpty(null) = true
167 * StringUtils.isEmpty("") = true
168 * StringUtils.isEmpty(" ") = false
169 * StringUtils.isEmpty("bob") = false
170 * StringUtils.isEmpty(" bob ") = false
171 * </pre>
172 *
173 * <p>NOTE: This method changed in Lang version 2.0.
174 * It no longer trims the CharSequence.
175 * That functionality is available in isBlank().</p>
176 *
177 * @param cs the CharSequence to check, may be null
178 * @return {@code true} if the CharSequence is empty or null
179 * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
180 */
181 public static boolean isEmpty(CharSequence cs) {
182 return cs == null || cs.length() == 0;
183 }
184
185 /**
186 * <p>Checks if a CharSequence is not empty ("") and not null.</p>
187 *
188 * <pre>
189 * StringUtils.isNotEmpty(null) = false
190 * StringUtils.isNotEmpty("") = false
191 * StringUtils.isNotEmpty(" ") = true
192 * StringUtils.isNotEmpty("bob") = true
193 * StringUtils.isNotEmpty(" bob ") = true
194 * </pre>
195 *
196 * @param cs the CharSequence to check, may be null
197 * @return {@code true} if the CharSequence is not empty and not null
198 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
199 */
200 public static boolean isNotEmpty(CharSequence cs) {
201 return !StringUtils.isEmpty(cs);
202 }
203
204 /**
205 * <p>Checks if a CharSequence is whitespace, empty ("") or null.</p>
206 *
207 * <pre>
208 * StringUtils.isBlank(null) = true
209 * StringUtils.isBlank("") = true
210 * StringUtils.isBlank(" ") = true
211 * StringUtils.isBlank("bob") = false
212 * StringUtils.isBlank(" bob ") = false
213 * </pre>
214 *
215 * @param cs the CharSequence to check, may be null
216 * @return {@code true} if the CharSequence is null, empty or whitespace
217 * @since 2.0
218 * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
219 */
220 public static boolean isBlank(CharSequence cs) {
221 int strLen;
222 if (cs == null || (strLen = cs.length()) == 0) {
223 return true;
224 }
225 for (int i = 0; i < strLen; i++) {
226 if ((Character.isWhitespace(cs.charAt(i)) == false)) {
227 return false;
228 }
229 }
230 return true;
231 }
232
233 /**
234 * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
235 *
236 * <pre>
237 * StringUtils.isNotBlank(null) = false
238 * StringUtils.isNotBlank("") = false
239 * StringUtils.isNotBlank(" ") = false
240 * StringUtils.isNotBlank("bob") = true
241 * StringUtils.isNotBlank(" bob ") = true
242 * </pre>
243 *
244 * @param cs the CharSequence to check, may be null
245 * @return {@code true} if the CharSequence is
246 * not empty and not null and not whitespace
247 * @since 2.0
248 * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
249 */
250 public static boolean isNotBlank(CharSequence cs) {
251 return !StringUtils.isBlank(cs);
252 }
253
254 // Trim
255 //-----------------------------------------------------------------------
256 /**
257 * <p>Removes control characters (char &lt;= 32) from both
258 * ends of this String, handling {@code null} by returning
259 * {@code null}.</p>
260 *
261 * <p>The String is trimmed using {@link String#trim()}.
262 * Trim removes start and end characters &lt;= 32.
263 * To strip whitespace use {@link #strip(String)}.</p>
264 *
265 * <p>To trim your choice of characters, use the
266 * {@link #strip(String, String)} methods.</p>
267 *
268 * <pre>
269 * StringUtils.trim(null) = null
270 * StringUtils.trim("") = ""
271 * StringUtils.trim(" ") = ""
272 * StringUtils.trim("abc") = "abc"
273 * StringUtils.trim(" abc ") = "abc"
274 * </pre>
275 *
276 * @param str the String to be trimmed, may be null
277 * @return the trimmed string, {@code null} if null String input
278 */
279 public static String trim(String str) {
280 return str == null ? null : str.trim();
281 }
282
283 /**
284 * <p>Removes control characters (char &lt;= 32) from both
285 * ends of this String returning {@code null} if the String is
286 * empty ("") after the trim or if it is {@code null}.
287 *
288 * <p>The String is trimmed using {@link String#trim()}.
289 * Trim removes start and end characters &lt;= 32.
290 * To strip whitespace use {@link #stripToNull(String)}.</p>
291 *
292 * <pre>
293 * StringUtils.trimToNull(null) = null
294 * StringUtils.trimToNull("") = null
295 * StringUtils.trimToNull(" ") = null
296 * StringUtils.trimToNull("abc") = "abc"
297 * StringUtils.trimToNull(" abc ") = "abc"
298 * </pre>
299 *
300 * @param str the String to be trimmed, may be null
301 * @return the trimmed String,
302 * {@code null} if only chars &lt;= 32, empty or null String input
303 * @since 2.0
304 */
305 public static String trimToNull(String str) {
306 String ts = trim(str);
307 return isEmpty(ts) ? null : ts;
308 }
309
310 /**
311 * <p>Removes control characters (char &lt;= 32) from both
312 * ends of this String returning an empty String ("") if the String
313 * is empty ("") after the trim or if it is {@code null}.
314 *
315 * <p>The String is trimmed using {@link String#trim()}.
316 * Trim removes start and end characters &lt;= 32.
317 * To strip whitespace use {@link #stripToEmpty(String)}.</p>
318 *
319 * <pre>
320 * StringUtils.trimToEmpty(null) = ""
321 * StringUtils.trimToEmpty("") = ""
322 * StringUtils.trimToEmpty(" ") = ""
323 * StringUtils.trimToEmpty("abc") = "abc"
324 * StringUtils.trimToEmpty(" abc ") = "abc"
325 * </pre>
326 *
327 * @param str the String to be trimmed, may be null
328 * @return the trimmed String, or an empty String if {@code null} input
329 * @since 2.0
330 */
331 public static String trimToEmpty(String str) {
332 return str == null ? EMPTY : str.trim();
333 }
334
335 // Stripping
336 //-----------------------------------------------------------------------
337 /**
338 * <p>Strips whitespace from the start and end of a String.</p>
339 *
340 * <p>This is similar to {@link #trim(String)} but removes whitespace.
341 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
342 *
343 * <p>A {@code null} input String returns {@code null}.</p>
344 *
345 * <pre>
346 * StringUtils.strip(null) = null
347 * StringUtils.strip("") = ""
348 * StringUtils.strip(" ") = ""
349 * StringUtils.strip("abc") = "abc"
350 * StringUtils.strip(" abc") = "abc"
351 * StringUtils.strip("abc ") = "abc"
352 * StringUtils.strip(" abc ") = "abc"
353 * StringUtils.strip(" ab c ") = "ab c"
354 * </pre>
355 *
356 * @param str the String to remove whitespace from, may be null
357 * @return the stripped String, {@code null} if null String input
358 */
359 public static String strip(String str) {
360 return strip(str, null);
361 }
362
363 /**
364 * <p>Strips whitespace from the start and end of a String returning
365 * {@code null} if the String is empty ("") after the strip.</p>
366 *
367 * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
368 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
369 *
370 * <pre>
371 * StringUtils.stripToNull(null) = null
372 * StringUtils.stripToNull("") = null
373 * StringUtils.stripToNull(" ") = null
374 * StringUtils.stripToNull("abc") = "abc"
375 * StringUtils.stripToNull(" abc") = "abc"
376 * StringUtils.stripToNull("abc ") = "abc"
377 * StringUtils.stripToNull(" abc ") = "abc"
378 * StringUtils.stripToNull(" ab c ") = "ab c"
379 * </pre>
380 *
381 * @param str the String to be stripped, may be null
382 * @return the stripped String,
383 * {@code null} if whitespace, empty or null String input
384 * @since 2.0
385 */
386 public static String stripToNull(String str) {
387 if (str == null) {
388 return null;
389 }
390 str = strip(str, null);
391 return str.length() == 0 ? null : str;
392 }
393
394 /**
395 * <p>Strips whitespace from the start and end of a String returning
396 * an empty String if {@code null} input.</p>
397 *
398 * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
399 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
400 *
401 * <pre>
402 * StringUtils.stripToEmpty(null) = ""
403 * StringUtils.stripToEmpty("") = ""
404 * StringUtils.stripToEmpty(" ") = ""
405 * StringUtils.stripToEmpty("abc") = "abc"
406 * StringUtils.stripToEmpty(" abc") = "abc"
407 * StringUtils.stripToEmpty("abc ") = "abc"
408 * StringUtils.stripToEmpty(" abc ") = "abc"
409 * StringUtils.stripToEmpty(" ab c ") = "ab c"
410 * </pre>
411 *
412 * @param str the String to be stripped, may be null
413 * @return the trimmed String, or an empty String if {@code null} input
414 * @since 2.0
415 */
416 public static String stripToEmpty(String str) {
417 return str == null ? EMPTY : strip(str, null);
418 }
419
420 /**
421 * <p>Strips any of a set of characters from the start and end of a String.
422 * This is similar to {@link String#trim()} but allows the characters
423 * to be stripped to be controlled.</p>
424 *
425 * <p>A {@code null} input String returns {@code null}.
426 * An empty string ("") input returns the empty string.</p>
427 *
428 * <p>If the stripChars String is {@code null}, whitespace is
429 * stripped as defined by {@link Character#isWhitespace(char)}.
430 * Alternatively use {@link #strip(String)}.</p>
431 *
432 * <pre>
433 * StringUtils.strip(null, *) = null
434 * StringUtils.strip("", *) = ""
435 * StringUtils.strip("abc", null) = "abc"
436 * StringUtils.strip(" abc", null) = "abc"
437 * StringUtils.strip("abc ", null) = "abc"
438 * StringUtils.strip(" abc ", null) = "abc"
439 * StringUtils.strip(" abcyx", "xyz") = " abc"
440 * </pre>
441 *
442 * @param str the String to remove characters from, may be null
443 * @param stripChars the characters to remove, null treated as whitespace
444 * @return the stripped String, {@code null} if null String input
445 */
446 public static String strip(String str, String stripChars) {
447 if (isEmpty(str)) {
448 return str;
449 }
450 str = stripStart(str, stripChars);
451 return stripEnd(str, stripChars);
452 }
453
454 /**
455 * <p>Strips any of a set of characters from the start of a String.</p>
456 *
457 * <p>A {@code null} input String returns {@code null}.
458 * An empty string ("") input returns the empty string.</p>
459 *
460 * <p>If the stripChars String is {@code null}, whitespace is
461 * stripped as defined by {@link Character#isWhitespace(char)}.</p>
462 *
463 * <pre>
464 * StringUtils.stripStart(null, *) = null
465 * StringUtils.stripStart("", *) = ""
466 * StringUtils.stripStart("abc", "") = "abc"
467 * StringUtils.stripStart("abc", null) = "abc"
468 * StringUtils.stripStart(" abc", null) = "abc"
469 * StringUtils.stripStart("abc ", null) = "abc "
470 * StringUtils.stripStart(" abc ", null) = "abc "
471 * StringUtils.stripStart("yxabc ", "xyz") = "abc "
472 * </pre>
473 *
474 * @param str the String to remove characters from, may be null
475 * @param stripChars the characters to remove, null treated as whitespace
476 * @return the stripped String, {@code null} if null String input
477 */
478 public static String stripStart(String str, String stripChars) {
479 int strLen;
480 if (str == null || (strLen = str.length()) == 0) {
481 return str;
482 }
483 int start = 0;
484 if (stripChars == null) {
485 while ((start != strLen) && Character.isWhitespace(str.charAt(start))) {
486 start++;
487 }
488 } else if (stripChars.length() == 0) {
489 return str;
490 } else {
491 while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND)) {
492 start++;
493 }
494 }
495 return str.substring(start);
496 }
497
498 /**
499 * <p>Strips any of a set of characters from the end of a String.</p>
500 *
501 * <p>A {@code null} input String returns {@code null}.
502 * An empty string ("") input returns the empty string.</p>
503 *
504 * <p>If the stripChars String is {@code null}, whitespace is
505 * stripped as defined by {@link Character#isWhitespace(char)}.</p>
506 *
507 * <pre>
508 * StringUtils.stripEnd(null, *) = null
509 * StringUtils.stripEnd("", *) = ""
510 * StringUtils.stripEnd("abc", "") = "abc"
511 * StringUtils.stripEnd("abc", null) = "abc"
512 * StringUtils.stripEnd(" abc", null) = " abc"
513 * StringUtils.stripEnd("abc ", null) = "abc"
514 * StringUtils.stripEnd(" abc ", null) = " abc"
515 * StringUtils.stripEnd(" abcyx", "xyz") = " abc"
516 * StringUtils.stripEnd("120.00", ".0") = "12"
517 * </pre>
518 *
519 * @param str the String to remove characters from, may be null
520 * @param stripChars the set of characters to remove, null treated as whitespace
521 * @return the stripped String, {@code null} if null String input
522 */
523 public static String stripEnd(String str, String stripChars) {
524 int end;
525 if (str == null || (end = str.length()) == 0) {
526 return str;
527 }
528
529 if (stripChars == null) {
530 while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) {
531 end--;
532 }
533 } else if (stripChars.length() == 0) {
534 return str;
535 } else {
536 while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND)) {
537 end--;
538 }
539 }
540 return str.substring(0, end);
541 }
542
543 // StripAll
544 //-----------------------------------------------------------------------
545 /**
546 * <p>Strips whitespace from the start and end of every String in an array.
547 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
548 *
549 * <p>A new array is returned each time, except for length zero.
550 * A {@code null} array will return {@code null}.
551 * An empty array will return itself.
552 * A {@code null} array entry will be ignored.</p>
553 *
554 * <pre>
555 * StringUtils.stripAll(null) = null
556 * StringUtils.stripAll([]) = []
557 * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"]
558 * StringUtils.stripAll(["abc ", null]) = ["abc", null]
559 * </pre>
560 *
561 * @param strs the array to remove whitespace from, may be null
562 * @return the stripped Strings, {@code null} if null array input
563 */
564 public static String[] stripAll(String... strs) {
565 return stripAll(strs, null);
566 }
567
568 /**
569 * <p>Strips any of a set of characters from the start and end of every
570 * String in an array.</p>
571 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
572 *
573 * <p>A new array is returned each time, except for length zero.
574 * A {@code null} array will return {@code null}.
575 * An empty array will return itself.
576 * A {@code null} array entry will be ignored.
577 * A {@code null} stripChars will strip whitespace as defined by
578 * {@link Character#isWhitespace(char)}.</p>
579 *
580 * <pre>
581 * StringUtils.stripAll(null, *) = null
582 * StringUtils.stripAll([], *) = []
583 * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"]
584 * StringUtils.stripAll(["abc ", null], null) = ["abc", null]
585 * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null]
586 * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null]
587 * </pre>
588 *
589 * @param strs the array to remove characters from, may be null
590 * @param stripChars the characters to remove, null treated as whitespace
591 * @return the stripped Strings, {@code null} if null array input
592 */
593 public static String[] stripAll(String[] strs, String stripChars) {
594 int strsLen;
595 if (strs == null || (strsLen = strs.length) == 0) {
596 return strs;
597 }
598 String[] newArr = new String[strsLen];
599 for (int i = 0; i < strsLen; i++) {
600 newArr[i] = strip(strs[i], stripChars);
601 }
602 return newArr;
603 }
604
605 /**
606 * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p>
607 * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
608 * <p>Note that ligatures will be left as is.</p>
609 *
610 * <p>This method will use the first available implementation of:
611 * Java 6's {@link java.text.Normalizer}, Java 1.3&ndash;1.5's {@code sun.text.Normalizer}</p>
612 *
613 * <pre>
614 * StringUtils.stripAccents(null) = null
615 * StringUtils.stripAccents("") = ""
616 * StringUtils.stripAccents("control") = "control"
617 * StringUtils.stripAccents("&eacute;clair") = "eclair"
618 * </pre>
619 *
620 * @param input String to be stripped
621 * @return input text with diacritics removed
622 *
623 * @since 3.0
624 */
625 // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
626 public static String stripAccents(String input) {
627 if(input == null) {
628 return null;
629 }
630 try {
631 String result = null;
632 if (java6Available) {
633 result = removeAccentsJava6(input);
634 } else if (sunAvailable) {
635 result = removeAccentsSUN(input);
636 } else {
637 throw new UnsupportedOperationException(
638 "The stripAccents(CharSequence) method requires at least Java 1.6 or a Sun JVM");
639 }
640 // Note that none of the above methods correctly remove ligatures...
641 return result;
642 } catch(IllegalArgumentException iae) {
643 throw new RuntimeException("IllegalArgumentException occurred", iae);
644 } catch(IllegalAccessException iae) {
645 throw new RuntimeException("IllegalAccessException occurred", iae);
646 } catch(InvocationTargetException ite) {
647 throw new RuntimeException("InvocationTargetException occurred", ite);
648 } catch(SecurityException se) {
649 throw new RuntimeException("SecurityException occurred", se);
650 }
651 }
652
653 /**
654 * Use {@code java.text.Normalizer#normalize(CharSequence, Normalizer.Form)}
655 * (but be careful, this class exists in Java 1.3, with an entirely different meaning!)
656 *
657 * @param text the text to be processed
658 * @return the processed string
659 * @throws IllegalAccessException may be thrown by a reflection call
660 * @throws InvocationTargetException if a reflection call throws an exception
661 * @throws IllegalStateException if the {@code Normalizer} class is not available
662 */
663 private static String removeAccentsJava6(CharSequence text)
664 throws IllegalAccessException, InvocationTargetException {
665 /*
666 String decomposed = java.text.Normalizer.normalize(CharSequence, Normalizer.Form.NFD);
667 return java6Pattern.matcher(decomposed).replaceAll("");//$NON-NLS-1$
668 */
669 if (!java6Available || java6NormalizerFormNFD == null) {
670 throw new IllegalStateException("java.text.Normalizer is not available");
671 }
672 String result;
673 result = (String) java6NormalizeMethod.invoke(null, new Object[] {text, java6NormalizerFormNFD});
674 result = java6Pattern.matcher(result).replaceAll("");//$NON-NLS-1$
675 return result;
676 }
677
678 /**
679 * Use {@code sun.text.Normalizer#decompose(String, boolean, int)}
680 *
681 * @param text the text to be processed
682 * @return the processed string
683 * @throws IllegalAccessException may be thrown by a reflection call
684 * @throws InvocationTargetException if a reflection call throws an exception
685 * @throws IllegalStateException if the {@code Normalizer} class is not available
686 */
687 private static String removeAccentsSUN(CharSequence text)
688 throws IllegalAccessException, InvocationTargetException {
689 /*
690 String decomposed = sun.text.Normalizer.decompose(text, false, 0);
691 return sunPattern.matcher(decomposed).replaceAll("");//$NON-NLS-1$
692 */
693 if (! sunAvailable) {
694 throw new IllegalStateException("sun.text.Normalizer is not available");
695 }
696 String result;
697 result = (String) sunDecomposeMethod.invoke(null, new Object[] {text, Boolean.FALSE, Integer.valueOf(0)});
698 result = sunPattern.matcher(result).replaceAll("");//$NON-NLS-1$
699 return result;
700 }
701
702 // SUN internal, Java 1.3 -> Java 5
703 private static boolean sunAvailable = false;
704 private static Method sunDecomposeMethod = null;
705 private static final Pattern sunPattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$
706 // Java 6+
707 private static boolean java6Available = false;
708 private static Method java6NormalizeMethod = null;
709 private static Object java6NormalizerFormNFD = null;
710 private static final Pattern java6Pattern = sunPattern;
711
712 static {
713 try {
714 // java.text.Normalizer.normalize(CharSequence, Normalizer.Form.NFD);
715 // Be careful not to get Java 1.3 java.text.Normalizer!
716 Class<?> normalizerFormClass = Thread.currentThread().getContextClassLoader()
717 .loadClass("java.text.Normalizer$Form");//$NON-NLS-1$
718 java6NormalizerFormNFD = normalizerFormClass.getField("NFD").get(null);//$NON-NLS-1$
719 Class<?> normalizerClass = Thread.currentThread().getContextClassLoader()
720 .loadClass("java.text.Normalizer");//$NON-NLS-1$
721 java6NormalizeMethod = normalizerClass.getMethod("normalize",
722 new Class[] {CharSequence.class, normalizerFormClass});//$NON-NLS-1$
723 java6Available = true;
724 } catch (ClassNotFoundException e) {
725 java6Available = false;
726 } catch (NoSuchFieldException e) {
727 java6Available = false;
728 } catch (IllegalAccessException e) {
729 java6Available = false;
730 } catch (NoSuchMethodException e) {
731 java6Available = false;
732 }
733
734 try {
735 // sun.text.Normalizer.decompose(text, false, 0);
736 Class<?> normalizerClass = Thread.currentThread().getContextClassLoader()
737 .loadClass("sun.text.Normalizer");//$NON-NLS-1$
738 sunDecomposeMethod = normalizerClass.getMethod("decompose",
739 new Class[] {String.class, Boolean.TYPE, Integer.TYPE});//$NON-NLS-1$
740 sunAvailable = true;
741 } catch (ClassNotFoundException e) {
742 sunAvailable = false;
743 } catch (NoSuchMethodException e) {
744 sunAvailable = false;
745 }
746 }
747
748 // Equals
749 //-----------------------------------------------------------------------
750 /**
751 * <p>Compares two CharSequences, returning {@code true} if they are equal.</p>
752 *
753 * <p>{@code null}s are handled without exceptions. Two {@code null}
754 * references are considered to be equal. The comparison is case sensitive.</p>
755 *
756 * <pre>
757 * StringUtils.equals(null, null) = true
758 * StringUtils.equals(null, "abc") = false
759 * StringUtils.equals("abc", null) = false
760 * StringUtils.equals("abc", "abc") = true
761 * StringUtils.equals("abc", "ABC") = false
762 * </pre>
763 *
764 * @see java.lang.String#equals(Object)
765 * @param cs1 the first CharSequence, may be null
766 * @param cs2 the second CharSequence, may be null
767 * @return {@code true} if the CharSequences are equal, case sensitive, or
768 * both {@code null}
769 * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
770 */
771 public static boolean equals(CharSequence cs1, CharSequence cs2) {
772 return cs1 == null ? cs2 == null : cs1.equals(cs2);
773 }
774
775 /**
776 * <p>Compares two CharSequences, returning {@code true} if they are equal ignoring
777 * the case.</p>
778 *
779 * <p>{@code null}s are handled without exceptions. Two {@code null}
780 * references are considered equal. Comparison is case insensitive.</p>
781 *
782 * <pre>
783 * StringUtils.equalsIgnoreCase(null, null) = true
784 * StringUtils.equalsIgnoreCase(null, "abc") = false
785 * StringUtils.equalsIgnoreCase("abc", null) = false
786 * StringUtils.equalsIgnoreCase("abc", "abc") = true
787 * StringUtils.equalsIgnoreCase("abc", "ABC") = true
788 * </pre>
789 *
790 * @param str1 the first CharSequence, may be null
791 * @param str2 the second CharSequence, may be null
792 * @return {@code true} if the CharSequence are equal, case insensitive, or
793 * both {@code null}
794 * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
795 */
796 public static boolean equalsIgnoreCase(CharSequence str1, CharSequence str2) {
797 if (str1 == null || str2 == null) {
798 return str1 == str2;
799 } else {
800 return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, Math.max(str1.length(), str2.length()));
801 }
802 }
803
804 // IndexOf
805 //-----------------------------------------------------------------------
806 /**
807 * <p>Finds the first index within a CharSequence, handling {@code null}.
808 * This method uses {@link String#indexOf(int, int)} if possible.</p>
809 *
810 * <p>A {@code null} or empty ("") CharSequence will return {@code INDEX_NOT_FOUND (-1)}.</p>
811 *
812 * <pre>
813 * StringUtils.indexOf(null, *) = -1
814 * StringUtils.indexOf("", *) = -1
815 * StringUtils.indexOf("aabaabaa", 'a') = 0
816 * StringUtils.indexOf("aabaabaa", 'b') = 2
817 * </pre>
818 *
819 * @param seq the CharSequence to check, may be null
820 * @param searchChar the character to find
821 * @return the first index of the search character,
822 * -1 if no match or {@code null} string input
823 * @since 2.0
824 * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
825 */
826 public static int indexOf(CharSequence seq, int searchChar) {
827 if (isEmpty(seq)) {
828 return INDEX_NOT_FOUND;
829 }
830 return CharSequenceUtils.indexOf(seq, searchChar, 0);
831 }
832
833 /**
834 * <p>Finds the first index within a CharSequence from a start position,
835 * handling {@code null}.
836 * This method uses {@link String#indexOf(int, int)} if possible.</p>
837 *
838 * <p>A {@code null} or empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}.
839 * A negative start position is treated as zero.
840 * A start position greater than the string length returns {@code -1}.</p>
841 *
842 * <pre>
843 * StringUtils.indexOf(null, *, *) = -1
844 * StringUtils.indexOf("", *, *) = -1
845 * StringUtils.indexOf("aabaabaa", 'b', 0) = 2
846 * StringUtils.indexOf("aabaabaa", 'b', 3) = 5
847 * StringUtils.indexOf("aabaabaa", 'b', 9) = -1
848 * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
849 * </pre>
850 *
851 * @param seq the CharSequence to check, may be null
852 * @param searchChar the character to find
853 * @param startPos the start position, negative treated as zero
854 * @return the first index of the search character,
855 * -1 if no match or {@code null} string input
856 * @since 2.0
857 * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
858 */
859 public static int indexOf(CharSequence seq, int searchChar, int startPos) {
860 if (isEmpty(seq)) {
861 return INDEX_NOT_FOUND;
862 }
863 return CharSequenceUtils.indexOf(seq, searchChar, startPos);
864 }
865
866 /**
867 * <p>Finds the first index within a CharSequence, handling {@code null}.
868 * This method uses {@link String#indexOf(String, int)} if possible.</p>
869 *
870 * <p>A {@code null} CharSequence will return {@code -1}.</p>
871 *
872 * <pre>
873 * StringUtils.indexOf(null, *) = -1
874 * StringUtils.indexOf(*, null) = -1
875 * StringUtils.indexOf("", "") = 0
876 * StringUtils.indexOf("", *) = -1 (except when * = "")
877 * StringUtils.indexOf("aabaabaa", "a") = 0
878 * StringUtils.indexOf("aabaabaa", "b") = 2
879 * StringUtils.indexOf("aabaabaa", "ab") = 1
880 * StringUtils.indexOf("aabaabaa", "") = 0
881 * </pre>
882 *
883 * @param seq the CharSequence to check, may be null
884 * @param searchSeq the CharSequence to find, may be null
885 * @return the first index of the search CharSequence,
886 * -1 if no match or {@code null} string input
887 * @since 2.0
888 * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
889 */
890 public static int indexOf(CharSequence seq, CharSequence searchSeq) {
891 if (seq == null || searchSeq == null) {
892 return INDEX_NOT_FOUND;
893 }
894 return CharSequenceUtils.indexOf(seq, searchSeq, 0);
895 }
896
897 /**
898 * <p>Finds the first index within a CharSequence, handling {@code null}.
899 * This method uses {@link String#indexOf(String, int)} if possible.</p>
900 *
901 * <p>A {@code null} CharSequence will return {@code -1}.
902 * A negative start position is treated as zero.
903 * An empty ("") search CharSequence always matches.
904 * A start position greater than the string length only matches
905 * an empty search CharSequence.</p>
906 *
907 * <pre>
908 * StringUtils.indexOf(null, *, *) = -1
909 * StringUtils.indexOf(*, null, *) = -1
910 * StringUtils.indexOf("", "", 0) = 0
911 * StringUtils.indexOf("", *, 0) = -1 (except when * = "")
912 * StringUtils.indexOf("aabaabaa", "a", 0) = 0
913 * StringUtils.indexOf("aabaabaa", "b", 0) = 2
914 * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
915 * StringUtils.indexOf("aabaabaa", "b", 3) = 5
916 * StringUtils.indexOf("aabaabaa", "b", 9) = -1
917 * StringUtils.indexOf("aabaabaa", "b", -1) = 2
918 * StringUtils.indexOf("aabaabaa", "", 2) = 2
919 * StringUtils.indexOf("abc", "", 9) = 3
920 * </pre>
921 *
922 * @param seq the CharSequence to check, may be null
923 * @param searchSeq the CharSequence to find, may be null
924 * @param startPos the start position, negative treated as zero
925 * @return the first index of the search CharSequence,
926 * -1 if no match or {@code null} string input
927 * @since 2.0
928 * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
929 */
930 public static int indexOf(CharSequence seq, CharSequence searchSeq, int startPos) {
931 if (seq == null || searchSeq == null) {
932 return INDEX_NOT_FOUND;
933 }
934 return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
935 }
936
937 /**
938 * <p>Finds the n-th index within a CharSequence, handling {@code null}.
939 * This method uses {@link String#indexOf(String)} if possible.</p>
940 *
941 * <p>A {@code null} CharSequence will return {@code -1}.</p>
942 *
943 * <pre>
944 * StringUtils.ordinalIndexOf(null, *, *) = -1
945 * StringUtils.ordinalIndexOf(*, null, *) = -1
946 * StringUtils.ordinalIndexOf("", "", *) = 0
947 * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0
948 * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1
949 * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2
950 * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5
951 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
952 * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
953 * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0
954 * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0
955 * </pre>
956 *
957 * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
958 *
959 * <pre>
960 * str.substring(0, lastOrdinalIndexOf(str, "\n", n))
961 * </pre>
962 *
963 * @param str the CharSequence to check, may be null
964 * @param searchStr the CharSequence to find, may be null
965 * @param ordinal the n-th {@code searchStr} to find
966 * @return the n-th index of the search CharSequence,
967 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
968 * @since 2.1
969 * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
970 */
971 public static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) {
972 return ordinalIndexOf(str, searchStr, ordinal, false);
973 }
974
975 /**
976 * <p>Finds the n-th index within a String, handling {@code null}.
977 * This method uses {@link String#indexOf(String)} if possible.</p>
978 *
979 * <p>A {@code null} CharSequence will return {@code -1}.</p>
980 *
981 * @param str the CharSequence to check, may be null
982 * @param searchStr the CharSequence to find, may be null
983 * @param ordinal the n-th {@code searchStr} to find
984 * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
985 * @return the n-th index of the search CharSequence,
986 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
987 */
988 // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int)
989 private static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal, boolean lastIndex) {
990 if (str == null || searchStr == null || ordinal <= 0) {
991 return INDEX_NOT_FOUND;
992 }
993 if (searchStr.length() == 0) {
994 return lastIndex ? str.length() : 0;
995 }
996 int found = 0;
997 int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
998 do {
999 if (lastIndex) {
1000 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1);
1001 } else {
1002 index = CharSequenceUtils.indexOf(str, searchStr, index + 1);
1003 }
1004 if (index < 0) {
1005 return index;
1006 }
1007 found++;
1008 } while (found < ordinal);
1009 return index;
1010 }
1011
1012 /**
1013 * <p>Case in-sensitive find of the first index within a CharSequence.</p>
1014 *
1015 * <p>A {@code null} CharSequence will return {@code -1}.
1016 * A negative start position is treated as zero.
1017 * An empty ("") search CharSequence always matches.
1018 * A start position greater than the string length only matches
1019 * an empty search CharSequence.</p>
1020 *
1021 * <pre>
1022 * StringUtils.indexOfIgnoreCase(null, *) = -1
1023 * StringUtils.indexOfIgnoreCase(*, null) = -1
1024 * StringUtils.indexOfIgnoreCase("", "") = 0
1025 * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0
1026 * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2
1027 * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
1028 * </pre>
1029 *
1030 * @param str the CharSequence to check, may be null
1031 * @param searchStr the CharSequence to find, may be null
1032 * @return the first index of the search CharSequence,
1033 * -1 if no match or {@code null} string input
1034 * @since 2.5
1035 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
1036 */
1037 public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr) {
1038 return indexOfIgnoreCase(str, searchStr, 0);
1039 }
1040
1041 /**
1042 * <p>Case in-sensitive find of the first index within a CharSequence
1043 * from the specified position.</p>
1044 *
1045 * <p>A {@code null} CharSequence will return {@code -1}.
1046 * A negative start position is treated as zero.
1047 * An empty ("") search CharSequence always matches.
1048 * A start position greater than the string length only matches
1049 * an empty search CharSequence.</p>
1050 *
1051 * <pre>
1052 * StringUtils.indexOfIgnoreCase(null, *, *) = -1
1053 * StringUtils.indexOfIgnoreCase(*, null, *) = -1
1054 * StringUtils.indexOfIgnoreCase("", "", 0) = 0
1055 * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0
1056 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2
1057 * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
1058 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5
1059 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1
1060 * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
1061 * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2
1062 * StringUtils.indexOfIgnoreCase("abc", "", 9) = 3
1063 * </pre>
1064 *
1065 * @param str the CharSequence to check, may be null
1066 * @param searchStr the CharSequence to find, may be null
1067 * @param startPos the start position, negative treated as zero
1068 * @return the first index of the search CharSequence,
1069 * -1 if no match or {@code null} string input
1070 * @since 2.5
1071 * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
1072 */
1073 public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) {
1074 if (str == null || searchStr == null) {
1075 return INDEX_NOT_FOUND;
1076 }
1077 if (startPos < 0) {
1078 startPos = 0;
1079 }
1080 int endLimit = (str.length() - searchStr.length()) + 1;
1081 if (startPos > endLimit) {
1082 return INDEX_NOT_FOUND;
1083 }
1084 if (searchStr.length() == 0) {
1085 return startPos;
1086 }
1087 for (int i = startPos; i < endLimit; i++) {
1088 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1089 return i;
1090 }
1091 }
1092 return INDEX_NOT_FOUND;
1093 }
1094
1095 // LastIndexOf
1096 //-----------------------------------------------------------------------
1097 /**
1098 * <p>Finds the last index within a CharSequence, handling {@code null}.
1099 * This method uses {@link String#lastIndexOf(int)} if possible.</p>
1100 *
1101 * <p>A {@code null} or empty ("") CharSequence will return {@code -1}.</p>
1102 *
1103 * <pre>
1104 * StringUtils.lastIndexOf(null, *) = -1
1105 * StringUtils.lastIndexOf("", *) = -1
1106 * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
1107 * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
1108 * </pre>
1109 *
1110 * @param seq the CharSequence to check, may be null
1111 * @param searchChar the character to find
1112 * @return the last index of the search character,
1113 * -1 if no match or {@code null} string input
1114 * @since 2.0
1115 * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
1116 */
1117 public static int lastIndexOf(CharSequence seq, int searchChar) {
1118 if (isEmpty(seq)) {
1119 return INDEX_NOT_FOUND;
1120 }
1121 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
1122 }
1123
1124 /**
1125 * <p>Finds the last index within a CharSequence from a start position,
1126 * handling {@code null}.
1127 * This method uses {@link String#lastIndexOf(int, int)} if possible.</p>
1128 *
1129 * <p>A {@code null} or empty ("") CharSequence will return {@code -1}.
1130 * A negative start position returns {@code -1}.
1131 * A start position greater than the string length searches the whole string.</p>
1132 *
1133 * <pre>
1134 * StringUtils.lastIndexOf(null, *, *) = -1
1135 * StringUtils.lastIndexOf("", *, *) = -1
1136 * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5
1137 * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2
1138 * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1
1139 * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5
1140 * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
1141 * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0
1142 * </pre>
1143 *
1144 * @param seq the CharSequence to check, may be null
1145 * @param searchChar the character to find
1146 * @param startPos the start position
1147 * @return the last index of the search character,
1148 * -1 if no match or {@code null} string input
1149 * @since 2.0
1150 * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
1151 */
1152 public static int lastIndexOf(CharSequence seq, int searchChar, int startPos) {
1153 if (isEmpty(seq)) {
1154 return INDEX_NOT_FOUND;
1155 }
1156 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
1157 }
1158
1159 /**
1160 * <p>Finds the last index within a CharSequence, handling {@code null}.
1161 * This method uses {@link String#lastIndexOf(String)} if possible.</p>
1162 *
1163 * <p>A {@code null} CharSequence will return {@code -1}.</p>
1164 *
1165 * <pre>
1166 * StringUtils.lastIndexOf(null, *) = -1
1167 * StringUtils.lastIndexOf(*, null) = -1
1168 * StringUtils.lastIndexOf("", "") = 0
1169 * StringUtils.lastIndexOf("aabaabaa", "a") = 7
1170 * StringUtils.lastIndexOf("aabaabaa", "b") = 5
1171 * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
1172 * StringUtils.lastIndexOf("aabaabaa", "") = 8
1173 * </pre>
1174 *
1175 * @param seq the CharSequence to check, may be null
1176 * @param searchSeq the CharSequence to find, may be null
1177 * @return the last index of the search String,
1178 * -1 if no match or {@code null} string input
1179 * @since 2.0
1180 * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
1181 */
1182 public static int lastIndexOf(CharSequence seq, CharSequence searchSeq) {
1183 if (seq == null || searchSeq == null) {
1184 return INDEX_NOT_FOUND;
1185 }
1186 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
1187 }
1188
1189 /**
1190 * <p>Finds the n-th last index within a String, handling {@code null}.
1191 * This method uses {@link String#lastIndexOf(String)}.</p>
1192 *
1193 * <p>A {@code null} String will return {@code -1}.</p>
1194 *
1195 * <pre>
1196 * StringUtils.lastOrdinalIndexOf(null, *, *) = -1
1197 * StringUtils.lastOrdinalIndexOf(*, null, *) = -1
1198 * StringUtils.lastOrdinalIndexOf("", "", *) = 0
1199 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7
1200 * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6
1201 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5
1202 * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2
1203 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
1204 * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
1205 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8
1206 * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8
1207 * </pre>
1208 *
1209 * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
1210 *
1211 * <pre>
1212 * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
1213 * </pre>
1214 *
1215 * @param str the CharSequence to check, may be null
1216 * @param searchStr the CharSequence to find, may be null
1217 * @param ordinal the n-th last {@code searchStr} to find
1218 * @return the n-th last index of the search CharSequence,
1219 * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1220 * @since 2.5
1221 * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
1222 */
1223 public static int lastOrdinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) {
1224 return ordinalIndexOf(str, searchStr, ordinal, true);
1225 }
1226
1227 /**
1228 * <p>Finds the first index within a CharSequence, handling {@code null}.
1229 * This method uses {@link String#lastIndexOf(String, int)} if possible.</p>
1230 *
1231 * <p>A {@code null} CharSequence will return {@code -1}.
1232 * A negative start position returns {@code -1}.
1233 * An empty ("") search CharSequence always matches unless the start position is negative.
1234 * A start position greater than the string length searches the whole string.</p>
1235 *
1236 * <pre>
1237 * StringUtils.lastIndexOf(null, *, *) = -1
1238 * StringUtils.lastIndexOf(*, null, *) = -1
1239 * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7
1240 * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5
1241 * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
1242 * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5
1243 * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
1244 * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0
1245 * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1
1246 * </pre>
1247 *
1248 * @param seq the CharSequence to check, may be null
1249 * @param searchSeq the CharSequence to find, may be null
1250 * @param startPos the start position, negative treated as zero
1251 * @return the first index of the search CharSequence,
1252 * -1 if no match or {@code null} string input
1253 * @since 2.0
1254 * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
1255 */
1256 public static int lastIndexOf(CharSequence seq, CharSequence searchSeq, int startPos) {
1257 if (seq == null || searchSeq == null) {
1258 return INDEX_NOT_FOUND;
1259 }
1260 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
1261 }
1262
1263 /**
1264 * <p>Case in-sensitive find of the last index within a CharSequence.</p>
1265 *
1266 * <p>A {@code null} CharSequence will return {@code -1}.
1267 * A negative start position returns {@code -1}.
1268 * An empty ("") search CharSequence always matches unless the start position is negative.
1269 * A start position greater than the string length searches the whole string.</p>
1270 *
1271 * <pre>
1272 * StringUtils.lastIndexOfIgnoreCase(null, *) = -1
1273 * StringUtils.lastIndexOfIgnoreCase(*, null) = -1
1274 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7
1275 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5
1276 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
1277 * </pre>
1278 *
1279 * @param str the CharSequence to check, may be null
1280 * @param searchStr the CharSequence to find, may be null
1281 * @return the first index of the search CharSequence,
1282 * -1 if no match or {@code null} string input
1283 * @since 2.5
1284 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
1285 */
1286 public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr) {
1287 if (str == null || searchStr == null) {
1288 return INDEX_NOT_FOUND;
1289 }
1290 return lastIndexOfIgnoreCase(str, searchStr, str.length());
1291 }
1292
1293 /**
1294 * <p>Case in-sensitive find of the last index within a CharSequence
1295 * from the specified position.</p>
1296 *
1297 * <p>A {@code null} CharSequence will return {@code -1}.
1298 * A negative start position returns {@code -1}.
1299 * An empty ("") search CharSequence always matches unless the start position is negative.
1300 * A start position greater than the string length searches the whole string.</p>
1301 *
1302 * <pre>
1303 * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1
1304 * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1
1305 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7
1306 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5
1307 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
1308 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5
1309 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
1310 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0
1311 * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1
1312 * </pre>
1313 *
1314 * @param str the CharSequence to check, may be null
1315 * @param searchStr the CharSequence to find, may be null
1316 * @param startPos the start position
1317 * @return the first index of the search CharSequence,
1318 * -1 if no match or {@code null} input
1319 * @since 2.5
1320 * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
1321 */
1322 public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) {
1323 if (str == null || searchStr == null) {
1324 return INDEX_NOT_FOUND;
1325 }
1326 if (startPos > (str.length() - searchStr.length())) {
1327 startPos = str.length() - searchStr.length();
1328 }
1329 if (startPos < 0) {
1330 return INDEX_NOT_FOUND;
1331 }
1332 if (searchStr.length() == 0) {
1333 return startPos;
1334 }
1335
1336 for (int i = startPos; i >= 0; i--) {
1337 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1338 return i;
1339 }
1340 }
1341 return INDEX_NOT_FOUND;
1342 }
1343
1344 // Contains
1345 //-----------------------------------------------------------------------
1346 /**
1347 * <p>Checks if CharSequence contains a search character, handling {@code null}.
1348 * This method uses {@link String#indexOf(int)} if possible.</p>
1349 *
1350 * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
1351 *
1352 * <pre>
1353 * StringUtils.contains(null, *) = false
1354 * StringUtils.contains("", *) = false
1355 * StringUtils.contains("abc", 'a') = true
1356 * StringUtils.contains("abc", 'z') = false
1357 * </pre>
1358 *
1359 * @param seq the CharSequence to check, may be null
1360 * @param searchChar the character to find
1361 * @return true if the CharSequence contains the search character,
1362 * false if not or {@code null} string input
1363 * @since 2.0
1364 * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1365 */
1366 public static boolean contains(CharSequence seq, int searchChar) {
1367 if (isEmpty(seq)) {
1368 return false;
1369 }
1370 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1371 }
1372
1373 /**
1374 * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}.
1375 * This method uses {@link String#indexOf(String)} if possible.</p>
1376 *
1377 * <p>A {@code null} CharSequence will return {@code false}.</p>
1378 *
1379 * <pre>
1380 * StringUtils.contains(null, *) = false
1381 * StringUtils.contains(*, null) = false
1382 * StringUtils.contains("", "") = true
1383 * StringUtils.contains("abc", "") = true
1384 * StringUtils.contains("abc", "a") = true
1385 * StringUtils.contains("abc", "z") = false
1386 * </pre>
1387 *
1388 * @param seq the CharSequence to check, may be null
1389 * @param searchSeq the CharSequence to find, may be null
1390 * @return true if the CharSequence contains the search CharSequence,
1391 * false if not or {@code null} string input
1392 * @since 2.0
1393 * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
1394 */
1395 public static boolean contains(CharSequence seq, CharSequence searchSeq) {
1396 if (seq == null || searchSeq == null) {
1397 return false;
1398 }
1399 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
1400 }
1401
1402 /**
1403 * <p>Checks if CharSequence contains a search CharSequence irrespective of case,
1404 * handling {@code null}. Case-insensitivity is defined as by
1405 * {@link String#equalsIgnoreCase(String)}.
1406 *
1407 * <p>A {@code null} CharSequence will return {@code false}.</p>
1408 *
1409 * <pre>
1410 * StringUtils.contains(null, *) = false
1411 * StringUtils.contains(*, null) = false
1412 * StringUtils.contains("", "") = true
1413 * StringUtils.contains("abc", "") = true
1414 * StringUtils.contains("abc", "a") = true
1415 * StringUtils.contains("abc", "z") = false
1416 * StringUtils.contains("abc", "A") = true
1417 * StringUtils.contains("abc", "Z") = false
1418 * </pre>
1419 *
1420 * @param str the CharSequence to check, may be null
1421 * @param searchStr the CharSequence to find, may be null
1422 * @return true if the CharSequence contains the search CharSequence irrespective of
1423 * case or false if not or {@code null} string input
1424 * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
1425 */
1426 public static boolean containsIgnoreCase(CharSequence str, CharSequence searchStr) {
1427 if (str == null || searchStr == null) {
1428 return false;
1429 }
1430 int len = searchStr.length();
1431 int max = str.length() - len;
1432 for (int i = 0; i <= max; i++) {
1433 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
1434 return true;
1435 }
1436 }
1437 return false;
1438 }
1439
1440 /**
1441 * Check whether the given CharSequence contains any whitespace characters.
1442 * @param seq the CharSequence to check (may be {@code null})
1443 * @return {@code true} if the CharSequence is not empty and
1444 * contains at least 1 whitespace character
1445 * @see java.lang.Character#isWhitespace
1446 * @since 3.0
1447 */
1448 // From org.springframework.util.StringUtils, under Apache License 2.0
1449 public static boolean containsWhitespace(CharSequence seq) {
1450 if (isEmpty(seq)) {
1451 return false;
1452 }
1453 int strLen = seq.length();
1454 for (int i = 0; i < strLen; i++) {
1455 if (Character.isWhitespace(seq.charAt(i))) {
1456 return true;
1457 }
1458 }
1459 return false;
1460 }
1461
1462 // IndexOfAny chars
1463 //-----------------------------------------------------------------------
1464 /**
1465 * <p>Search a CharSequence to find the first index of any
1466 * character in the given set of characters.</p>
1467 *
1468 * <p>A {@code null} String will return {@code -1}.
1469 * A {@code null} or zero length search array will return {@code -1}.</p>
1470 *
1471 * <pre>
1472 * StringUtils.indexOfAny(null, *) = -1
1473 * StringUtils.indexOfAny("", *) = -1
1474 * StringUtils.indexOfAny(*, null) = -1
1475 * StringUtils.indexOfAny(*, []) = -1
1476 * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
1477 * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
1478 * StringUtils.indexOfAny("aba", ['z']) = -1
1479 * </pre>
1480 *
1481 * @param cs the CharSequence to check, may be null
1482 * @param searchChars the chars to search for, may be null
1483 * @return the index of any of the chars, -1 if no match or null input
1484 * @since 2.0
1485 * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
1486 */
1487 public static int indexOfAny(CharSequence cs, char... searchChars) {
1488 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1489 return INDEX_NOT_FOUND;
1490 }
1491 int csLen = cs.length();
1492 int csLast = csLen - 1;
1493 int searchLen = searchChars.length;
1494 int searchLast = searchLen - 1;
1495 for (int i = 0; i < csLen; i++) {
1496 char ch = cs.charAt(i);
1497 for (int j = 0; j < searchLen; j++) {
1498 if (searchChars[j] == ch) {
1499 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
1500 // ch is a supplementary character
1501 if (searchChars[j + 1] == cs.charAt(i + 1)) {
1502 return i;
1503 }
1504 } else {
1505 return i;
1506 }
1507 }
1508 }
1509 }
1510 return INDEX_NOT_FOUND;
1511 }
1512
1513 /**
1514 * <p>Search a CharSequence to find the first index of any
1515 * character in the given set of characters.</p>
1516 *
1517 * <p>A {@code null} String will return {@code -1}.
1518 * A {@code null} search string will return {@code -1}.</p>
1519 *
1520 * <pre>
1521 * StringUtils.indexOfAny(null, *) = -1
1522 * StringUtils.indexOfAny("", *) = -1
1523 * StringUtils.indexOfAny(*, null) = -1
1524 * StringUtils.indexOfAny(*, "") = -1
1525 * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
1526 * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
1527 * StringUtils.indexOfAny("aba","z") = -1
1528 * </pre>
1529 *
1530 * @param cs the CharSequence to check, may be null
1531 * @param searchChars the chars to search for, may be null
1532 * @return the index of any of the chars, -1 if no match or null input
1533 * @since 2.0
1534 * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
1535 */
1536 public static int indexOfAny(CharSequence cs, String searchChars) {
1537 if (isEmpty(cs) || isEmpty(searchChars)) {
1538 return INDEX_NOT_FOUND;
1539 }
1540 return indexOfAny(cs, searchChars.toCharArray());
1541 }
1542
1543 // ContainsAny
1544 //-----------------------------------------------------------------------
1545 /**
1546 * <p>Checks if the CharSequence contains any character in the given
1547 * set of characters.</p>
1548 *
1549 * <p>A {@code null} CharSequence will return {@code false}.
1550 * A {@code null} or zero length search array will return {@code false}.</p>
1551 *
1552 * <pre>
1553 * StringUtils.containsAny(null, *) = false
1554 * StringUtils.containsAny("", *) = false
1555 * StringUtils.containsAny(*, null) = false
1556 * StringUtils.containsAny(*, []) = false
1557 * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
1558 * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
1559 * StringUtils.containsAny("aba", ['z']) = false
1560 * </pre>
1561 *
1562 * @param cs the CharSequence to check, may be null
1563 * @param searchChars the chars to search for, may be null
1564 * @return the {@code true} if any of the chars are found,
1565 * {@code false} if no match or null input
1566 * @since 2.4
1567 * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
1568 */
1569 public static boolean containsAny(CharSequence cs, char... searchChars) {
1570 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1571 return false;
1572 }
1573 int csLength = cs.length();
1574 int searchLength = searchChars.length;
1575 int csLast = csLength - 1;
1576 int searchLast = searchLength - 1;
1577 for (int i = 0; i < csLength; i++) {
1578 char ch = cs.charAt(i);
1579 for (int j = 0; j < searchLength; j++) {
1580 if (searchChars[j] == ch) {
1581 if (Character.isHighSurrogate(ch)) {
1582 if (j == searchLast) {
1583 // missing low surrogate, fine, like String.indexOf(String)
1584 return true;
1585 }
1586 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1587 return true;
1588 }
1589 } else {
1590 // ch is in the Basic Multilingual Plane
1591 return true;
1592 }
1593 }
1594 }
1595 }
1596 return false;
1597 }
1598
1599 /**
1600 * <p>
1601 * Checks if the CharSequence contains any character in the given set of characters.
1602 * </p>
1603 *
1604 * <p>
1605 * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
1606 * {@code false}.
1607 * </p>
1608 *
1609 * <pre>
1610 * StringUtils.containsAny(null, *) = false
1611 * StringUtils.containsAny("", *) = false
1612 * StringUtils.containsAny(*, null) = false
1613 * StringUtils.containsAny(*, "") = false
1614 * StringUtils.containsAny("zzabyycdxx", "za") = true
1615 * StringUtils.containsAny("zzabyycdxx", "by") = true
1616 * StringUtils.containsAny("aba","z") = false
1617 * </pre>
1618 *
1619 * @param cs
1620 * the CharSequence to check, may be null
1621 * @param searchChars
1622 * the chars to search for, may be null
1623 * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
1624 * @since 2.4
1625 * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1626 */
1627 public static boolean containsAny(CharSequence cs, CharSequence searchChars) {
1628 if (searchChars == null) {
1629 return false;
1630 }
1631 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1632 }
1633
1634 // IndexOfAnyBut chars
1635 //-----------------------------------------------------------------------
1636 /**
1637 * <p>Searches a CharSequence to find the first index of any
1638 * character not in the given set of characters.</p>
1639 *
1640 * <p>A {@code null} CharSequence will return {@code -1}.
1641 * A {@code null} or zero length search array will return {@code -1}.</p>
1642 *
1643 * <pre>
1644 * StringUtils.indexOfAnyBut(null, *) = -1
1645 * StringUtils.indexOfAnyBut("", *) = -1
1646 * StringUtils.indexOfAnyBut(*, null) = -1
1647 * StringUtils.indexOfAnyBut(*, []) = -1
1648 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
1649 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0
1650 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1
1651
1652 * </pre>
1653 *
1654 * @param cs the CharSequence to check, may be null
1655 * @param searchChars the chars to search for, may be null
1656 * @return the index of any of the chars, -1 if no match or null input
1657 * @since 2.0
1658 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
1659 */
1660 public static int indexOfAnyBut(CharSequence cs, char... searchChars) {
1661 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1662 return INDEX_NOT_FOUND;
1663 }
1664 int csLen = cs.length();
1665 int csLast = csLen - 1;
1666 int searchLen = searchChars.length;
1667 int searchLast = searchLen - 1;
1668 outer:
1669 for (int i = 0; i < csLen; i++) {
1670 char ch = cs.charAt(i);
1671 for (int j = 0; j < searchLen; j++) {
1672 if (searchChars[j] == ch) {
1673 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
1674 if (searchChars[j + 1] == cs.charAt(i + 1)) {
1675 continue outer;
1676 }
1677 } else {
1678 continue outer;
1679 }
1680 }
1681 }
1682 return i;
1683 }
1684 return INDEX_NOT_FOUND;
1685 }
1686
1687 /**
1688 * <p>Search a CharSequence to find the first index of any
1689 * character not in the given set of characters.</p>
1690 *
1691 * <p>A {@code null} CharSequence will return {@code -1}.
1692 * A {@code null} or empty search string will return {@code -1}.</p>
1693 *
1694 * <pre>
1695 * StringUtils.indexOfAnyBut(null, *) = -1
1696 * StringUtils.indexOfAnyBut("", *) = -1
1697 * StringUtils.indexOfAnyBut(*, null) = -1
1698 * StringUtils.indexOfAnyBut(*, "") = -1
1699 * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
1700 * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1
1701 * StringUtils.indexOfAnyBut("aba","ab") = -1
1702 * </pre>
1703 *
1704 * @param seq the CharSequence to check, may be null
1705 * @param searchChars the chars to search for, may be null
1706 * @return the index of any of the chars, -1 if no match or null input
1707 * @since 2.0
1708 * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
1709 */
1710 public static int indexOfAnyBut(CharSequence seq, CharSequence searchChars) {
1711 if (isEmpty(seq) || isEmpty(searchChars)) {
1712 return INDEX_NOT_FOUND;
1713 }
1714 int strLen = seq.length();
1715 for (int i = 0; i < strLen; i++) {
1716 char ch = seq.charAt(i);
1717 boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
1718 if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
1719 char ch2 = seq.charAt(i + 1);
1720 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
1721 return i;
1722 }
1723 } else {
1724 if (!chFound) {
1725 return i;
1726 }
1727 }
1728 }
1729 return INDEX_NOT_FOUND;
1730 }
1731
1732 // ContainsOnly
1733 //-----------------------------------------------------------------------
1734 /**
1735 * <p>Checks if the CharSequence contains only certain characters.</p>
1736 *
1737 * <p>A {@code null} CharSequence will return {@code false}.
1738 * A {@code null} valid character array will return {@code false}.
1739 * An empty CharSequence (length()=0) always returns {@code true}.</p>
1740 *
1741 * <pre>
1742 * StringUtils.containsOnly(null, *) = false
1743 * StringUtils.containsOnly(*, null) = false
1744 * StringUtils.containsOnly("", *) = true
1745 * StringUtils.containsOnly("ab", '') = false
1746 * StringUtils.containsOnly("abab", 'abc') = true
1747 * StringUtils.containsOnly("ab1", 'abc') = false
1748 * StringUtils.containsOnly("abz", 'abc') = false
1749 * </pre>
1750 *
1751 * @param cs the String to check, may be null
1752 * @param valid an array of valid chars, may be null
1753 * @return true if it only contains valid chars and is non-null
1754 * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1755 */
1756 public static boolean containsOnly(CharSequence cs, char... valid) {
1757 // All these pre-checks are to maintain API with an older version
1758 if (valid == null || cs == null) {
1759 return false;
1760 }
1761 if (cs.length() == 0) {
1762 return true;
1763 }
1764 if (valid.length == 0) {
1765 return false;
1766 }
1767 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1768 }
1769
1770 /**
1771 * <p>Checks if the CharSequence contains only certain characters.</p>
1772 *
1773 * <p>A {@code null} CharSequence will return {@code false}.
1774 * A {@code null} valid character String will return {@code false}.
1775 * An empty String (length()=0) always returns {@code true}.</p>
1776 *
1777 * <pre>
1778 * StringUtils.containsOnly(null, *) = false
1779 * StringUtils.containsOnly(*, null) = false
1780 * StringUtils.containsOnly("", *) = true
1781 * StringUtils.containsOnly("ab", "") = false
1782 * StringUtils.containsOnly("abab", "abc") = true
1783 * StringUtils.containsOnly("ab1", "abc") = false
1784 * StringUtils.containsOnly("abz", "abc") = false
1785 * </pre>
1786 *
1787 * @param cs the CharSequence to check, may be null
1788 * @param validChars a String of valid chars, may be null
1789 * @return true if it only contains valid chars and is non-null
1790 * @since 2.0
1791 * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1792 */
1793 public static boolean containsOnly(CharSequence cs, String validChars) {
1794 if (cs == null || validChars == null) {
1795 return false;
1796 }
1797 return containsOnly(cs, validChars.toCharArray());
1798 }
1799
1800 // ContainsNone
1801 //-----------------------------------------------------------------------
1802 /**
1803 * <p>Checks that the CharSequence does not contain certain characters.</p>
1804 *
1805 * <p>A {@code null} CharSequence will return {@code true}.
1806 * A {@code null} invalid character array will return {@code true}.
1807 * An empty CharSequence (length()=0) always returns true.</p>
1808 *
1809 * <pre>
1810 * StringUtils.containsNone(null, *) = true
1811 * StringUtils.containsNone(*, null) = true
1812 * StringUtils.containsNone("", *) = true
1813 * StringUtils.containsNone("ab", '') = true
1814 * StringUtils.containsNone("abab", 'xyz') = true
1815 * StringUtils.containsNone("ab1", 'xyz') = true
1816 * StringUtils.containsNone("abz", 'xyz') = false
1817 * </pre>
1818 *
1819 * @param cs the CharSequence to check, may be null
1820 * @param searchChars an array of invalid chars, may be null
1821 * @return true if it contains none of the invalid chars, or is null
1822 * @since 2.0
1823 * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1824 */
1825 public static boolean containsNone(CharSequence cs, char... searchChars) {
1826 if (cs == null || searchChars == null) {
1827 return true;
1828 }
1829 int csLen = cs.length();
1830 int csLast = csLen - 1;
1831 int searchLen = searchChars.length;
1832 int searchLast = searchLen - 1;
1833 for (int i = 0; i < csLen; i++) {
1834 char ch = cs.charAt(i);
1835 for (int j = 0; j < searchLen; j++) {
1836 if (searchChars[j] == ch) {
1837 if (Character.isHighSurrogate(ch)) {
1838 if (j == searchLast) {
1839 // missing low surrogate, fine, like String.indexOf(String)
1840 return false;
1841 }
1842 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1843 return false;
1844 }
1845 } else {
1846 // ch is in the Basic Multilingual Plane
1847 return false;
1848 }
1849 }
1850 }
1851 }
1852 return true;
1853 }
1854
1855 /**
1856 * <p>Checks that the CharSequence does not contain certain characters.</p>
1857 *
1858 * <p>A {@code null} CharSequence will return {@code true}.
1859 * A {@code null} invalid character array will return {@code true}.
1860 * An empty String ("") always returns true.</p>
1861 *
1862 * <pre>
1863 * StringUtils.containsNone(null, *) = true
1864 * StringUtils.containsNone(*, null) = true
1865 * StringUtils.containsNone("", *) = true
1866 * StringUtils.containsNone("ab", "") = true
1867 * StringUtils.containsNone("abab", "xyz") = true
1868 * StringUtils.containsNone("ab1", "xyz") = true
1869 * StringUtils.containsNone("abz", "xyz") = false
1870 * </pre>
1871 *
1872 * @param cs the CharSequence to check, may be null
1873 * @param invalidChars a String of invalid chars, may be null
1874 * @return true if it contains none of the invalid chars, or is null
1875 * @since 2.0
1876 * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1877 */
1878 public static boolean containsNone(CharSequence cs, String invalidChars) {
1879 if (cs == null || invalidChars == null) {
1880 return true;
1881 }
1882 return containsNone(cs, invalidChars.toCharArray());
1883 }
1884
1885 // IndexOfAny strings
1886 //-----------------------------------------------------------------------
1887 /**
1888 * <p>Find the first index of any of a set of potential substrings.</p>
1889 *
1890 * <p>A {@code null} CharSequence will return {@code -1}.
1891 * A {@code null} or zero length search array will return {@code -1}.
1892 * A {@code null} search array entry will be ignored, but a search
1893 * array containing "" will return {@code 0} if {@code str} is not
1894 * null. This method uses {@link String#indexOf(String)} if possible.</p>
1895 *
1896 * <pre>
1897 * StringUtils.indexOfAny(null, *) = -1
1898 * StringUtils.indexOfAny(*, null) = -1
1899 * StringUtils.indexOfAny(*, []) = -1
1900 * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"]) = 2
1901 * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"]) = 2
1902 * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"]) = -1
1903 * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
1904 * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0
1905 * StringUtils.indexOfAny("", [""]) = 0
1906 * StringUtils.indexOfAny("", ["a"]) = -1
1907 * </pre>
1908 *
1909 * @param str the CharSequence to check, may be null
1910 * @param searchStrs the CharSequences to search for, may be null
1911 * @return the first index of any of the searchStrs in str, -1 if no match
1912 * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
1913 */
1914 public static int indexOfAny(CharSequence str, CharSequence... searchStrs) {
1915 if (str == null || searchStrs == null) {
1916 return INDEX_NOT_FOUND;
1917 }
1918 int sz = searchStrs.length;
1919
1920 // String's can't have a MAX_VALUEth index.
1921 int ret = Integer.MAX_VALUE;
1922
1923 int tmp = 0;
1924 for (int i = 0; i < sz; i++) {
1925 CharSequence search = searchStrs[i];
1926 if (search == null) {
1927 continue;
1928 }
1929 tmp = CharSequenceUtils.indexOf(str, search, 0);
1930 if (tmp == INDEX_NOT_FOUND) {
1931 continue;
1932 }
1933
1934 if (tmp < ret) {
1935 ret = tmp;
1936 }
1937 }
1938
1939 return (ret == Integer.MAX_VALUE) ? INDEX_NOT_FOUND : ret;
1940 }
1941
1942 /**
1943 * <p>Find the latest index of any of a set of potential substrings.</p>
1944 *
1945 * <p>A {@code null} CharSequence will return {@code -1}.
1946 * A {@code null} search array will return {@code -1}.
1947 * A {@code null} or zero length search array entry will be ignored,
1948 * but a search array containing "" will return the length of {@code str}
1949 * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
1950 *
1951 * <pre>
1952 * StringUtils.lastIndexOfAny(null, *) = -1
1953 * StringUtils.lastIndexOfAny(*, null) = -1
1954 * StringUtils.lastIndexOfAny(*, []) = -1
1955 * StringUtils.lastIndexOfAny(*, [null]) = -1
1956 * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
1957 * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
1958 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
1959 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
1960 * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""]) = 10
1961 * </pre>
1962 *
1963 * @param str the CharSequence to check, may be null
1964 * @param searchStrs the CharSequences to search for, may be null
1965 * @return the last index of any of the CharSequences, -1 if no match
1966 * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
1967 */
1968 public static int lastIndexOfAny(CharSequence str, CharSequence... searchStrs) {
1969 if (str == null || searchStrs == null) {
1970 return INDEX_NOT_FOUND;
1971 }
1972 int sz = searchStrs.length;
1973 int ret = INDEX_NOT_FOUND;
1974 int tmp = 0;
1975 for (int i = 0; i < sz; i++) {
1976 CharSequence search = searchStrs[i];
1977 if (search == null) {
1978 continue;
1979 }
1980 tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
1981 if (tmp > ret) {
1982 ret = tmp;
1983 }
1984 }
1985 return ret;
1986 }
1987
1988 // Substring
1989 //-----------------------------------------------------------------------
1990 /**
1991 * <p>Gets a substring from the specified String avoiding exceptions.</p>
1992 *
1993 * <p>A negative start position can be used to start {@code n}
1994 * characters from the end of the String.</p>
1995 *
1996 * <p>A {@code null} String will return {@code null}.
1997 * An empty ("") String will return "".</p>
1998 *
1999 * <pre>
2000 * StringUtils.substring(null, *) = null
2001 * StringUtils.substring("", *) = ""
2002 * StringUtils.substring("abc", 0) = "abc"
2003 * StringUtils.substring("abc", 2) = "c"
2004 * StringUtils.substring("abc", 4) = ""
2005 * StringUtils.substring("abc", -2) = "bc"
2006 * StringUtils.substring("abc", -4) = "abc"
2007 * </pre>
2008 *
2009 * @param str the String to get the substring from, may be null
2010 * @param start the position to start from, negative means
2011 * count back from the end of the String by this many characters
2012 * @return substring from start position, {@code null} if null String input
2013 */
2014 public static String substring(String str, int start) {
2015 if (str == null) {
2016 return null;
2017 }
2018
2019 // handle negatives, which means last n characters
2020 if (start < 0) {
2021 start = str.length() + start; // remember start is negative
2022 }
2023
2024 if (start < 0) {
2025 start = 0;
2026 }
2027 if (start > str.length()) {
2028 return EMPTY;
2029 }
2030
2031 return str.substring(start);
2032 }
2033
2034 /**
2035 * <p>Gets a substring from the specified String avoiding exceptions.</p>
2036 *
2037 * <p>A negative start position can be used to start/end {@code n}
2038 * characters from the end of the String.</p>
2039 *
2040 * <p>The returned substring starts with the character in the {@code start}
2041 * position and ends before the {@code end} position. All position counting is
2042 * zero-based -- i.e., to start at the beginning of the string use
2043 * {@code start = 0}. Negative start and end positions can be used to
2044 * specify offsets relative to the end of the String.</p>
2045 *
2046 * <p>If {@code start} is not strictly to the left of {@code end}, ""
2047 * is returned.</p>
2048 *
2049 * <pre>
2050 * StringUtils.substring(null, *, *) = null
2051 * StringUtils.substring("", * , *) = "";
2052 * StringUtils.substring("abc", 0, 2) = "ab"
2053 * StringUtils.substring("abc", 2, 0) = ""
2054 * StringUtils.substring("abc", 2, 4) = "c"
2055 * StringUtils.substring("abc", 4, 6) = ""
2056 * StringUtils.substring("abc", 2, 2) = ""
2057 * StringUtils.substring("abc", -2, -1) = "b"
2058 * StringUtils.substring("abc", -4, 2) = "ab"
2059 * </pre>
2060 *
2061 * @param str the String to get the substring from, may be null
2062 * @param start the position to start from, negative means
2063 * count back from the end of the String by this many characters
2064 * @param end the position to end at (exclusive), negative means
2065 * count back from the end of the String by this many characters
2066 * @return substring from start position to end position,
2067 * {@code null} if null String input
2068 */
2069 public static String substring(String str, int start, int end) {
2070 if (str == null) {
2071 return null;
2072 }
2073
2074 // handle negatives
2075 if (end < 0) {
2076 end = str.length() + end; // remember end is negative
2077 }
2078 if (start < 0) {
2079 start = str.length() + start; // remember start is negative
2080 }
2081
2082 // check length next
2083 if (end > str.length()) {
2084 end = str.length();
2085 }
2086
2087 // if start is greater than end, return ""
2088 if (start > end) {
2089 return EMPTY;
2090 }
2091
2092 if (start < 0) {
2093 start = 0;
2094 }
2095 if (end < 0) {
2096 end = 0;
2097 }
2098
2099 return str.substring(start, end);
2100 }
2101
2102 // Left/Right/Mid
2103 //-----------------------------------------------------------------------
2104 /**
2105 * <p>Gets the leftmost {@code len} characters of a String.</p>
2106 *
2107 * <p>If {@code len} characters are not available, or the
2108 * String is {@code null}, the String will be returned without
2109 * an exception. An empty String is returned if len is negative.</p>
2110 *
2111 * <pre>
2112 * StringUtils.left(null, *) = null
2113 * StringUtils.left(*, -ve) = ""
2114 * StringUtils.left("", *) = ""
2115 * StringUtils.left("abc", 0) = ""
2116 * StringUtils.left("abc", 2) = "ab"
2117 * StringUtils.left("abc", 4) = "abc"
2118 * </pre>
2119 *
2120 * @param str the String to get the leftmost characters from, may be null
2121 * @param len the length of the required String
2122 * @return the leftmost characters, {@code null} if null String input
2123 */
2124 public static String left(String str, int len) {
2125 if (str == null) {
2126 return null;
2127 }
2128 if (len < 0) {
2129 return EMPTY;
2130 }
2131 if (str.length() <= len) {
2132 return str;
2133 }
2134 return str.substring(0, len);
2135 }
2136
2137 /**
2138 * <p>Gets the rightmost {@code len} characters of a String.</p>
2139 *
2140 * <p>If {@code len} characters are not available, or the String
2141 * is {@code null}, the String will be returned without an
2142 * an exception. An empty String is returned if len is negative.</p>
2143 *
2144 * <pre>
2145 * StringUtils.right(null, *) = null
2146 * StringUtils.right(*, -ve) = ""
2147 * StringUtils.right("", *) = ""
2148 * StringUtils.right("abc", 0) = ""
2149 * StringUtils.right("abc", 2) = "bc"
2150 * StringUtils.right("abc", 4) = "abc"
2151 * </pre>
2152 *
2153 * @param str the String to get the rightmost characters from, may be null
2154 * @param len the length of the required String
2155 * @return the rightmost characters, {@code null} if null String input
2156 */
2157 public static String right(String str, int len) {
2158 if (str == null) {
2159 return null;
2160 }
2161 if (len < 0) {
2162 return EMPTY;
2163 }
2164 if (str.length() <= len) {
2165 return str;
2166 }
2167 return str.substring(str.length() - len);
2168 }
2169
2170 /**
2171 * <p>Gets {@code len} characters from the middle of a String.</p>
2172 *
2173 * <p>If {@code len} characters are not available, the remainder
2174 * of the String will be returned without an exception. If the
2175 * String is {@code null}, {@code null} will be returned.
2176 * An empty String is returned if len is negative or exceeds the
2177 * length of {@code str}.</p>
2178 *
2179 * <pre>
2180 * StringUtils.mid(null, *, *) = null
2181 * StringUtils.mid(*, *, -ve) = ""
2182 * StringUtils.mid("", 0, *) = ""
2183 * StringUtils.mid("abc", 0, 2) = "ab"
2184 * StringUtils.mid("abc", 0, 4) = "abc"
2185 * StringUtils.mid("abc", 2, 4) = "c"
2186 * StringUtils.mid("abc", 4, 2) = ""
2187 * StringUtils.mid("abc", -2, 2) = "ab"
2188 * </pre>
2189 *
2190 * @param str the String to get the characters from, may be null
2191 * @param pos the position to start from, negative treated as zero
2192 * @param len the length of the required String
2193 * @return the middle characters, {@code null} if null String input
2194 */
2195 public static String mid(String str, int pos, int len) {
2196 if (str == null) {
2197 return null;
2198 }
2199 if (len < 0 || pos > str.length()) {
2200 return EMPTY;
2201 }
2202 if (pos < 0) {
2203 pos = 0;
2204 }
2205 if (str.length() <= (pos + len)) {
2206 return str.substring(pos);
2207 }
2208 return str.substring(pos, pos + len);
2209 }
2210
2211 // SubStringAfter/SubStringBefore
2212 //-----------------------------------------------------------------------
2213 /**
2214 * <p>Gets the substring before the first occurrence of a separator.
2215 * The separator is not returned.</p>
2216 *
2217 * <p>A {@code null} string input will return {@code null}.
2218 * An empty ("") string input will return the empty string.
2219 * A {@code null} separator will return the input string.</p>
2220 *
2221 * <p>If nothing is found, the string input is returned.</p>
2222 *
2223 * <pre>
2224 * StringUtils.substringBefore(null, *) = null
2225 * StringUtils.substringBefore("", *) = ""
2226 * StringUtils.substringBefore("abc", "a") = ""
2227 * StringUtils.substringBefore("abcba", "b") = "a"
2228 * StringUtils.substringBefore("abc", "c") = "ab"
2229 * StringUtils.substringBefore("abc", "d") = "abc"
2230 * StringUtils.substringBefore("abc", "") = ""
2231 * StringUtils.substringBefore("abc", null) = "abc"
2232 * </pre>
2233 *
2234 * @param str the String to get a substring from, may be null
2235 * @param separator the String to search for, may be null
2236 * @return the substring before the first occurrence of the separator,
2237 * {@code null} if null String input
2238 * @since 2.0
2239 */
2240 public static String substringBefore(String str, String separator) {
2241 if (isEmpty(str) || separator == null) {
2242 return str;
2243 }
2244 if (separator.length() == 0) {
2245 return EMPTY;
2246 }
2247 int pos = str.indexOf(separator);
2248 if (pos == INDEX_NOT_FOUND) {
2249 return str;
2250 }
2251 return str.substring(0, pos);
2252 }
2253
2254 /**
2255 * <p>Gets the substring after the first occurrence of a separator.
2256 * The separator is not returned.</p>
2257 *
2258 * <p>A {@code null} string input will return {@code null}.
2259 * An empty ("") string input will return the empty string.
2260 * A {@code null} separator will return the empty string if the
2261 * input string is not {@code null}.</p>
2262 *
2263 * <p>If nothing is found, the empty string is returned.</p>
2264 *
2265 * <pre>
2266 * StringUtils.substringAfter(null, *) = null
2267 * StringUtils.substringAfter("", *) = ""
2268 * StringUtils.substringAfter(*, null) = ""
2269 * StringUtils.substringAfter("abc", "a") = "bc"
2270 * StringUtils.substringAfter("abcba", "b") = "cba"
2271 * StringUtils.substringAfter("abc", "c") = ""
2272 * StringUtils.substringAfter("abc", "d") = ""
2273 * StringUtils.substringAfter("abc", "") = "abc"
2274 * </pre>
2275 *
2276 * @param str the String to get a substring from, may be null
2277 * @param separator the String to search for, may be null
2278 * @return the substring after the first occurrence of the separator,
2279 * {@code null} if null String input
2280 * @since 2.0
2281 */
2282 public static String substringAfter(String str, String separator) {
2283 if (isEmpty(str)) {
2284 return str;
2285 }
2286 if (separator == null) {
2287 return EMPTY;
2288 }
2289 int pos = str.indexOf(separator);
2290 if (pos == INDEX_NOT_FOUND) {
2291 return EMPTY;
2292 }
2293 return str.substring(pos + separator.length());
2294 }
2295
2296 /**
2297 * <p>Gets the substring before the last occurrence of a separator.
2298 * The separator is not returned.</p>
2299 *
2300 * <p>A {@code null} string input will return {@code null}.
2301 * An empty ("") string input will return the empty string.
2302 * An empty or {@code null} separator will return the input string.</p>
2303 *
2304 * <p>If nothing is found, the string input is returned.</p>
2305 *
2306 * <pre>
2307 * StringUtils.substringBeforeLast(null, *) = null
2308 * StringUtils.substringBeforeLast("", *) = ""
2309 * StringUtils.substringBeforeLast("abcba", "b") = "abc"
2310 * StringUtils.substringBeforeLast("abc", "c") = "ab"
2311 * StringUtils.substringBeforeLast("a", "a") = ""
2312 * StringUtils.substringBeforeLast("a", "z") = "a"
2313 * StringUtils.substringBeforeLast("a", null) = "a"
2314 * StringUtils.substringBeforeLast("a", "") = "a"
2315 * </pre>
2316 *
2317 * @param str the String to get a substring from, may be null
2318 * @param separator the String to search for, may be null
2319 * @return the substring before the last occurrence of the separator,
2320 * {@code null} if null String input
2321 * @since 2.0
2322 */
2323 public static String substringBeforeLast(String str, String separator) {
2324 if (isEmpty(str) || isEmpty(separator)) {
2325 return str;
2326 }
2327 int pos = str.lastIndexOf(separator);
2328 if (pos == INDEX_NOT_FOUND) {
2329 return str;
2330 }
2331 return str.substring(0, pos);
2332 }
2333
2334 /**
2335 * <p>Gets the substring after the last occurrence of a separator.
2336 * The separator is not returned.</p>
2337 *
2338 * <p>A {@code null} string input will return {@code null}.
2339 * An empty ("") string input will return the empty string.
2340 * An empty or {@code null} separator will return the empty string if
2341 * the input string is not {@code null}.</p>
2342 *
2343 * <p>If nothing is found, the empty string is returned.</p>
2344 *
2345 * <pre>
2346 * StringUtils.substringAfterLast(null, *) = null
2347 * StringUtils.substringAfterLast("", *) = ""
2348 * StringUtils.substringAfterLast(*, "") = ""
2349 * StringUtils.substringAfterLast(*, null) = ""
2350 * StringUtils.substringAfterLast("abc", "a") = "bc"
2351 * StringUtils.substringAfterLast("abcba", "b") = "a"
2352 * StringUtils.substringAfterLast("abc", "c") = ""
2353 * StringUtils.substringAfterLast("a", "a") = ""
2354 * StringUtils.substringAfterLast("a", "z") = ""
2355 * </pre>
2356 *
2357 * @param str the String to get a substring from, may be null
2358 * @param separator the String to search for, may be null
2359 * @return the substring after the last occurrence of the separator,
2360 * {@code null} if null String input
2361 * @since 2.0
2362 */
2363 public static String substringAfterLast(String str, String separator) {
2364 if (isEmpty(str)) {
2365 return str;
2366 }
2367 if (isEmpty(separator)) {
2368 return EMPTY;
2369 }
2370 int pos = str.lastIndexOf(separator);
2371 if (pos == INDEX_NOT_FOUND || pos == (str.length() - separator.length())) {
2372 return EMPTY;
2373 }
2374 return str.substring(pos + separator.length());
2375 }
2376
2377 // Substring between
2378 //-----------------------------------------------------------------------
2379 /**
2380 * <p>Gets the String that is nested in between two instances of the
2381 * same String.</p>
2382 *
2383 * <p>A {@code null} input String returns {@code null}.
2384 * A {@code null} tag returns {@code null}.</p>
2385 *
2386 * <pre>
2387 * StringUtils.substringBetween(null, *) = null
2388 * StringUtils.substringBetween("", "") = ""
2389 * StringUtils.substringBetween("", "tag") = null
2390 * StringUtils.substringBetween("tagabctag", null) = null
2391 * StringUtils.substringBetween("tagabctag", "") = ""
2392 * StringUtils.substringBetween("tagabctag", "tag") = "abc"
2393 * </pre>
2394 *
2395 * @param str the String containing the substring, may be null
2396 * @param tag the String before and after the substring, may be null
2397 * @return the substring, {@code null} if no match
2398 * @since 2.0
2399 */
2400 public static String substringBetween(String str, String tag) {
2401 return substringBetween(str, tag, tag);
2402 }
2403
2404 /**
2405 * <p>Gets the String that is nested in between two Strings.
2406 * Only the first match is returned.</p>
2407 *
2408 * <p>A {@code null} input String returns {@code null}.
2409 * A {@code null} open/close returns {@code null} (no match).
2410 * An empty ("") open and close returns an empty string.</p>
2411 *
2412 * <pre>
2413 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
2414 * StringUtils.substringBetween(null, *, *) = null
2415 * StringUtils.substringBetween(*, null, *) = null
2416 * StringUtils.substringBetween(*, *, null) = null
2417 * StringUtils.substringBetween("", "", "") = ""
2418 * StringUtils.substringBetween("", "", "]") = null
2419 * StringUtils.substringBetween("", "[", "]") = null
2420 * StringUtils.substringBetween("yabcz", "", "") = ""
2421 * StringUtils.substringBetween("yabcz", "y", "z") = "abc"
2422 * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc"
2423 * </pre>
2424 *
2425 * @param str the String containing the substring, may be null
2426 * @param open the String before the substring, may be null
2427 * @param close the String after the substring, may be null
2428 * @return the substring, {@code null} if no match
2429 * @since 2.0
2430 */
2431 public static String substringBetween(String str, String open, String close) {
2432 if (str == null || open == null || close == null) {
2433 return null;
2434 }
2435 int start = str.indexOf(open);
2436 if (start != INDEX_NOT_FOUND) {
2437 int end = str.indexOf(close, start + open.length());
2438 if (end != INDEX_NOT_FOUND) {
2439 return str.substring(start + open.length(), end);
2440 }
2441 }
2442 return null;
2443 }
2444
2445 /**
2446 * <p>Searches a String for substrings delimited by a start and end tag,
2447 * returning all matching substrings in an array.</p>
2448 *
2449 * <p>A {@code null} input String returns {@code null}.
2450 * A {@code null} open/close returns {@code null} (no match).
2451 * An empty ("") open/close returns {@code null} (no match).</p>
2452 *
2453 * <pre>
2454 * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
2455 * StringUtils.substringsBetween(null, *, *) = null
2456 * StringUtils.substringsBetween(*, null, *) = null
2457 * StringUtils.substringsBetween(*, *, null) = null
2458 * StringUtils.substringsBetween("", "[", "]") = []
2459 * </pre>
2460 *
2461 * @param str the String containing the substrings, null returns null, empty returns empty
2462 * @param open the String identifying the start of the substring, empty returns null
2463 * @param close the String identifying the end of the substring, empty returns null
2464 * @return a String Array of substrings, or {@code null} if no match
2465 * @since 2.3
2466 */
2467 public static String[] substringsBetween(String str, String open, String close) {
2468 if (str == null || isEmpty(open) || isEmpty(close)) {
2469 return null;
2470 }
2471 int strLen = str.length();
2472 if (strLen == 0) {
2473 return ArrayUtils.EMPTY_STRING_ARRAY;
2474 }
2475 int closeLen = close.length();
2476 int openLen = open.length();
2477 List<String> list = new ArrayList<String>();
2478 int pos = 0;
2479 while (pos < (strLen - closeLen)) {
2480 int start = str.indexOf(open, pos);
2481 if (start < 0) {
2482 break;
2483 }
2484 start += openLen;
2485 int end = str.indexOf(close, start);
2486 if (end < 0) {
2487 break;
2488 }
2489 list.add(str.substring(start, end));
2490 pos = end + closeLen;
2491 }
2492 if (list.isEmpty()) {
2493 return null;
2494 }
2495 return list.toArray(new String [list.size()]);
2496 }
2497
2498 // Nested extraction
2499 //-----------------------------------------------------------------------
2500
2501 // Splitting
2502 //-----------------------------------------------------------------------
2503 /**
2504 * <p>Splits the provided text into an array, using whitespace as the
2505 * separator.
2506 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2507 *
2508 * <p>The separator is not included in the returned String array.
2509 * Adjacent separators are treated as one separator.
2510 * For more control over the split use the StrTokenizer class.</p>
2511 *
2512 * <p>A {@code null} input String returns {@code null}.</p>
2513 *
2514 * <pre>
2515 * StringUtils.split(null) = null
2516 * StringUtils.split("") = []
2517 * StringUtils.split("abc def") = ["abc", "def"]
2518 * StringUtils.split("abc def") = ["abc", "def"]
2519 * StringUtils.split(" abc ") = ["abc"]
2520 * </pre>
2521 *
2522 * @param str the String to parse, may be null
2523 * @return an array of parsed Strings, {@code null} if null String input
2524 */
2525 public static String[] split(String str) {
2526 return split(str, null, -1);
2527 }
2528
2529 /**
2530 * <p>Splits the provided text into an array, separator specified.
2531 * This is an alternative to using StringTokenizer.</p>
2532 *
2533 * <p>The separator is not included in the returned String array.
2534 * Adjacent separators are treated as one separator.
2535 * For more control over the split use the StrTokenizer class.</p>
2536 *
2537 * <p>A {@code null} input String returns {@code null}.</p>
2538 *
2539 * <pre>
2540 * StringUtils.split(null, *) = null
2541 * StringUtils.split("", *) = []
2542 * StringUtils.split("a.b.c", '.') = ["a", "b", "c"]
2543 * StringUtils.split("a..b.c", '.') = ["a", "b", "c"]
2544 * StringUtils.split("a:b:c", '.') = ["a:b:c"]
2545 * StringUtils.split("a b c", ' ') = ["a", "b", "c"]
2546 * </pre>
2547 *
2548 * @param str the String to parse, may be null
2549 * @param separatorChar the character used as the delimiter
2550 * @return an array of parsed Strings, {@code null} if null String input
2551 * @since 2.0
2552 */
2553 public static String[] split(String str, char separatorChar) {
2554 return splitWorker(str, separatorChar, false);
2555 }
2556
2557 /**
2558 * <p>Splits the provided text into an array, separators specified.
2559 * This is an alternative to using StringTokenizer.</p>
2560 *
2561 * <p>The separator is not included in the returned String array.
2562 * Adjacent separators are treated as one separator.
2563 * For more control over the split use the StrTokenizer class.</p>
2564 *
2565 * <p>A {@code null} input String returns {@code null}.
2566 * A {@code null} separatorChars splits on whitespace.</p>
2567 *
2568 * <pre>
2569 * StringUtils.split(null, *) = null
2570 * StringUtils.split("", *) = []
2571 * StringUtils.split("abc def", null) = ["abc", "def"]
2572 * StringUtils.split("abc def", " ") = ["abc", "def"]
2573 * StringUtils.split("abc def", " ") = ["abc", "def"]
2574 * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
2575 * </pre>
2576 *
2577 * @param str the String to parse, may be null
2578 * @param separatorChars the characters used as the delimiters,
2579 * {@code null} splits on whitespace
2580 * @return an array of parsed Strings, {@code null} if null String input
2581 */
2582 public static String[] split(String str, String separatorChars) {
2583 return splitWorker(str, separatorChars, -1, false);
2584 }
2585
2586 /**
2587 * <p>Splits the provided text into an array with a maximum length,
2588 * separators specified.</p>
2589 *
2590 * <p>The separator is not included in the returned String array.
2591 * Adjacent separators are treated as one separator.</p>
2592 *
2593 * <p>A {@code null} input String returns {@code null}.
2594 * A {@code null} separatorChars splits on whitespace.</p>
2595 *
2596 * <p>If more than {@code max} delimited substrings are found, the last
2597 * returned string includes all characters after the first {@code max - 1}
2598 * returned strings (including separator characters).</p>
2599 *
2600 * <pre>
2601 * StringUtils.split(null, *, *) = null
2602 * StringUtils.split("", *, *) = []
2603 * StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
2604 * StringUtils.split("ab de fg", null, 0) = ["ab", "cd", "ef"]
2605 * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
2606 * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
2607 * </pre>
2608 *
2609 * @param str the String to parse, may be null
2610 * @param separatorChars the characters used as the delimiters,
2611 * {@code null} splits on whitespace
2612 * @param max the maximum number of elements to include in the
2613 * array. A zero or negative value implies no limit
2614 * @return an array of parsed Strings, {@code null} if null String input
2615 */
2616 public static String[] split(String str, String separatorChars, int max) {
2617 return splitWorker(str, separatorChars, max, false);
2618 }
2619
2620 /**
2621 * <p>Splits the provided text into an array, separator string specified.</p>
2622 *
2623 * <p>The separator(s) will not be included in the returned String array.
2624 * Adjacent separators are treated as one separator.</p>
2625 *
2626 * <p>A {@code null} input String returns {@code null}.
2627 * A {@code null} separator splits on whitespace.</p>
2628 *
2629 * <pre>
2630 * StringUtils.splitByWholeSeparator(null, *) = null
2631 * StringUtils.splitByWholeSeparator("", *) = []
2632 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"]
2633 * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"]
2634 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"]
2635 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
2636 * </pre>
2637 *
2638 * @param str the String to parse, may be null
2639 * @param separator String containing the String to be used as a delimiter,
2640 * {@code null} splits on whitespace
2641 * @return an array of parsed Strings, {@code null} if null String was input
2642 */
2643 public static String[] splitByWholeSeparator(String str, String separator) {
2644 return splitByWholeSeparatorWorker( str, separator, -1, false ) ;
2645 }
2646
2647 /**
2648 * <p>Splits the provided text into an array, separator string specified.
2649 * Returns a maximum of {@code max} substrings.</p>
2650 *
2651 * <p>The separator(s) will not be included in the returned String array.
2652 * Adjacent separators are treated as one separator.</p>
2653 *
2654 * <p>A {@code null} input String returns {@code null}.
2655 * A {@code null} separator splits on whitespace.</p>
2656 *
2657 * <pre>
2658 * StringUtils.splitByWholeSeparator(null, *, *) = null
2659 * StringUtils.splitByWholeSeparator("", *, *) = []
2660 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
2661 * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
2662 * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
2663 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
2664 * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
2665 * </pre>
2666 *
2667 * @param str the String to parse, may be null
2668 * @param separator String containing the String to be used as a delimiter,
2669 * {@code null} splits on whitespace
2670 * @param max the maximum number of elements to include in the returned
2671 * array. A zero or negative value implies no limit.
2672 * @return an array of parsed Strings, {@code null} if null String was input
2673 */
2674 public static String[] splitByWholeSeparator( String str, String separator, int max ) {
2675 return splitByWholeSeparatorWorker(str, separator, max, false);
2676 }
2677
2678 /**
2679 * <p>Splits the provided text into an array, separator string specified. </p>
2680 *
2681 * <p>The separator is not included in the returned String array.
2682 * Adjacent separators are treated as separators for empty tokens.
2683 * For more control over the split use the StrTokenizer class.</p>
2684 *
2685 * <p>A {@code null} input String returns {@code null}.
2686 * A {@code null} separator splits on whitespace.</p>
2687 *
2688 * <pre>
2689 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null
2690 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = []
2691 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"]
2692 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"]
2693 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
2694 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
2695 * </pre>
2696 *
2697 * @param str the String to parse, may be null
2698 * @param separator String containing the String to be used as a delimiter,
2699 * {@code null} splits on whitespace
2700 * @return an array of parsed Strings, {@code null} if null String was input
2701 * @since 2.4
2702 */
2703 public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator) {
2704 return splitByWholeSeparatorWorker(str, separator, -1, true);
2705 }
2706
2707 /**
2708 * <p>Splits the provided text into an array, separator string specified.
2709 * Returns a maximum of {@code max} substrings.</p>
2710 *
2711 * <p>The separator is not included in the returned String array.
2712 * Adjacent separators are treated as separators for empty tokens.
2713 * For more control over the split use the StrTokenizer class.</p>
2714 *
2715 * <p>A {@code null} input String returns {@code null}.
2716 * A {@code null} separator splits on whitespace.</p>
2717 *
2718 * <pre>
2719 * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null
2720 * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = []
2721 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"]
2722 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"]
2723 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
2724 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
2725 * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
2726 * </pre>
2727 *
2728 * @param str the String to parse, may be null
2729 * @param separator String containing the String to be used as a delimiter,
2730 * {@code null} splits on whitespace
2731 * @param max the maximum number of elements to include in the returned
2732 * array. A zero or negative value implies no limit.
2733 * @return an array of parsed Strings, {@code null} if null String was input
2734 * @since 2.4
2735 */
2736 public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator, int max) {
2737 return splitByWholeSeparatorWorker(str, separator, max, true);
2738 }
2739
2740 /**
2741 * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
2742 *
2743 * @param str the String to parse, may be {@code null}
2744 * @param separator String containing the String to be used as a delimiter,
2745 * {@code null} splits on whitespace
2746 * @param max the maximum number of elements to include in the returned
2747 * array. A zero or negative value implies no limit.
2748 * @param preserveAllTokens if {@code true}, adjacent separators are
2749 * treated as empty token separators; if {@code false}, adjacent
2750 * separators are treated as one separator.
2751 * @return an array of parsed Strings, {@code null} if null String input
2752 * @since 2.4
2753 */
2754 private static String[] splitByWholeSeparatorWorker(
2755 String str, String separator, int max, boolean preserveAllTokens) {
2756 if (str == null) {
2757 return null;
2758 }
2759
2760 int len = str.length();
2761
2762 if (len == 0) {
2763 return ArrayUtils.EMPTY_STRING_ARRAY;
2764 }
2765
2766 if ((separator == null) || (EMPTY.equals(separator))) {
2767 // Split on whitespace.
2768 return splitWorker(str, null, max, preserveAllTokens);
2769 }
2770
2771 int separatorLength = separator.length();
2772
2773 ArrayList<String> substrings = new ArrayList<String>();
2774 int numberOfSubstrings = 0;
2775 int beg = 0;
2776 int end = 0;
2777 while (end < len) {
2778 end = str.indexOf(separator, beg);
2779
2780 if (end > -1) {
2781 if (end > beg) {
2782 numberOfSubstrings += 1;
2783
2784 if (numberOfSubstrings == max) {
2785 end = len;
2786 substrings.add(str.substring(beg));
2787 } else {
2788 // The following is OK, because String.substring( beg, end ) excludes
2789 // the character at the position 'end'.
2790 substrings.add(str.substring(beg, end));
2791
2792 // Set the starting point for the next search.
2793 // The following is equivalent to beg = end + (separatorLength - 1) + 1,
2794 // which is the right calculation:
2795 beg = end + separatorLength;
2796 }
2797 } else {
2798 // We found a consecutive occurrence of the separator, so skip it.
2799 if (preserveAllTokens) {
2800 numberOfSubstrings += 1;
2801 if (numberOfSubstrings == max) {
2802 end = len;
2803 substrings.add(str.substring(beg));
2804 } else {
2805 substrings.add(EMPTY);
2806 }
2807 }
2808 beg = end + separatorLength;
2809 }
2810 } else {
2811 // String.substring( beg ) goes from 'beg' to the end of the String.
2812 substrings.add(str.substring(beg));
2813 end = len;
2814 }
2815 }
2816
2817 return substrings.toArray(new String[substrings.size()]);
2818 }
2819
2820 // -----------------------------------------------------------------------
2821 /**
2822 * <p>Splits the provided text into an array, using whitespace as the
2823 * separator, preserving all tokens, including empty tokens created by
2824 * adjacent separators. This is an alternative to using StringTokenizer.
2825 * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2826 *
2827 * <p>The separator is not included in the returned String array.
2828 * Adjacent separators are treated as separators for empty tokens.
2829 * For more control over the split use the StrTokenizer class.</p>
2830 *
2831 * <p>A {@code null} input String returns {@code null}.</p>
2832 *
2833 * <pre>
2834 * StringUtils.splitPreserveAllTokens(null) = null
2835 * StringUtils.splitPreserveAllTokens("") = []
2836 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"]
2837 * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"]
2838 * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""]
2839 * </pre>
2840 *
2841 * @param str the String to parse, may be {@code null}
2842 * @return an array of parsed Strings, {@code null} if null String input
2843 * @since 2.1
2844 */
2845 public static String[] splitPreserveAllTokens(String str) {
2846 return splitWorker(str, null, -1, true);
2847 }
2848
2849 /**
2850 * <p>Splits the provided text into an array, separator specified,
2851 * preserving all tokens, including empty tokens created by adjacent
2852 * separators. This is an alternative to using StringTokenizer.</p>
2853 *
2854 * <p>The separator is not included in the returned String array.
2855 * Adjacent separators are treated as separators for empty tokens.
2856 * For more control over the split use the StrTokenizer class.</p>
2857 *
2858 * <p>A {@code null} input String returns {@code null}.</p>
2859 *
2860 * <pre>
2861 * StringUtils.splitPreserveAllTokens(null, *) = null
2862 * StringUtils.splitPreserveAllTokens("", *) = []
2863 * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"]
2864 * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"]
2865 * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"]
2866 * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
2867 * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"]
2868 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""]
2869 * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""]
2870 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"]
2871 * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"]
2872 * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""]
2873 * </pre>
2874 *
2875 * @param str the String to parse, may be {@code null}
2876 * @param separatorChar the character used as the delimiter,
2877 * {@code null} splits on whitespace
2878 * @return an array of parsed Strings, {@code null} if null String input
2879 * @since 2.1
2880 */
2881 public static String[] splitPreserveAllTokens(String str, char separatorChar) {
2882 return splitWorker(str, separatorChar, true);
2883 }
2884
2885 /**
2886 * Performs the logic for the {@code split} and
2887 * {@code splitPreserveAllTokens} methods that do not return a
2888 * maximum array length.
2889 *
2890 * @param str the String to parse, may be {@code null}
2891 * @param separatorChar the separate character
2892 * @param preserveAllTokens if {@code true}, adjacent separators are
2893 * treated as empty token separators; if {@code false}, adjacent
2894 * separators are treated as one separator.
2895 * @return an array of parsed Strings, {@code null} if null String input
2896 */
2897 private static String[] splitWorker(String str, char separatorChar, boolean preserveAllTokens) {
2898 // Performance tuned for 2.0 (JDK1.4)
2899
2900 if (str == null) {
2901 return null;
2902 }
2903 int len = str.length();
2904 if (len == 0) {
2905 return ArrayUtils.EMPTY_STRING_ARRAY;
2906 }
2907 List<String> list = new ArrayList<String>();
2908 int i = 0, start = 0;
2909 boolean match = false;
2910 boolean lastMatch = false;
2911 while (i < len) {
2912 if (str.charAt(i) == separatorChar) {
2913 if (match || preserveAllTokens) {
2914 list.add(str.substring(start, i));
2915 match = false;
2916 lastMatch = true;
2917 }
2918 start = ++i;
2919 continue;
2920 }
2921 lastMatch = false;
2922 match = true;
2923 i++;
2924 }
2925 if (match || (preserveAllTokens && lastMatch)) {
2926 list.add(str.substring(start, i));
2927 }
2928 return list.toArray(new String[list.size()]);
2929 }
2930
2931 /**
2932 * <p>Splits the provided text into an array, separators specified,
2933 * preserving all tokens, including empty tokens created by adjacent
2934 * separators. This is an alternative to using StringTokenizer.</p>
2935 *
2936 * <p>The separator is not included in the returned String array.
2937 * Adjacent separators are treated as separators for empty tokens.
2938 * For more control over the split use the StrTokenizer class.</p>
2939 *
2940 * <p>A {@code null} input String returns {@code null}.
2941 * A {@code null} separatorChars splits on whitespace.</p>
2942 *
2943 * <pre>
2944 * StringUtils.splitPreserveAllTokens(null, *) = null
2945 * StringUtils.splitPreserveAllTokens("", *) = []
2946 * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"]
2947 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"]
2948 * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"]
2949 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
2950 * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""]
2951 * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
2952 * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"]
2953 * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"]
2954 * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"]
2955 * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""]
2956 * </pre>
2957 *
2958 * @param str the String to parse, may be {@code null}
2959 * @param separatorChars the characters used as the delimiters,
2960 * {@code null} splits on whitespace
2961 * @return an array of parsed Strings, {@code null} if null String input
2962 * @since 2.1
2963 */
2964 public static String[] splitPreserveAllTokens(String str, String separatorChars) {
2965 return splitWorker(str, separatorChars, -1, true);
2966 }
2967
2968 /**
2969 * <p>Splits the provided text into an array with a maximum length,
2970 * separators specified, preserving all tokens, including empty tokens
2971 * created by adjacent separators.</p>
2972 *
2973 * <p>The separator is not included in the returned String array.
2974 * Adjacent separators are treated as separators for empty tokens.
2975 * Adjacent separators are treated as one separator.</p>
2976 *
2977 * <p>A {@code null} input String returns {@code null}.
2978 * A {@code null} separatorChars splits on whitespace.</p>
2979 *
2980 * <p>If more than {@code max} delimited substrings are found, the last
2981 * returned string includes all characters after the first {@code max - 1}
2982 * returned strings (including separator characters).</p>
2983 *
2984 * <pre>
2985 * StringUtils.splitPreserveAllTokens(null, *, *) = null
2986 * StringUtils.splitPreserveAllTokens("", *, *) = []
2987 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
2988 * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
2989 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
2990 * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
2991 * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"]
2992 * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"]
2993 * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"]
2994 * </pre>
2995 *
2996 * @param str the String to parse, may be {@code null}
2997 * @param separatorChars the characters used as the delimiters,
2998 * {@code null} splits on whitespace
2999 * @param max the maximum number of elements to include in the
3000 * array. A zero or negative value implies no limit
3001 * @return an array of parsed Strings, {@code null} if null String input
3002 * @since 2.1
3003 */
3004 public static String[] splitPreserveAllTokens(String str, String separatorChars, int max) {
3005 return splitWorker(str, separatorChars, max, true);
3006 }
3007
3008 /**
3009 * Performs the logic for the {@code split} and
3010 * {@code splitPreserveAllTokens} methods that return a maximum array
3011 * length.
3012 *
3013 * @param str the String to parse, may be {@code null}
3014 * @param separatorChars the separate character
3015 * @param max the maximum number of elements to include in the
3016 * array. A zero or negative value implies no limit.
3017 * @param preserveAllTokens if {@code true}, adjacent separators are
3018 * treated as empty token separators; if {@code false}, adjacent
3019 * separators are treated as one separator.
3020 * @return an array of parsed Strings, {@code null} if null String input
3021 */
3022 private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens) {
3023 // Performance tuned for 2.0 (JDK1.4)
3024 // Direct code is quicker than StringTokenizer.
3025 // Also, StringTokenizer uses isSpace() not isWhitespace()
3026
3027 if (str == null) {
3028 return null;
3029 }
3030 int len = str.length();
3031 if (len == 0) {
3032 return ArrayUtils.EMPTY_STRING_ARRAY;
3033 }
3034 List<String> list = new ArrayList<String>();
3035 int sizePlus1 = 1;
3036 int i = 0, start = 0;
3037 boolean match = false;
3038 boolean lastMatch = false;
3039 if (separatorChars == null) {
3040 // Null separator means use whitespace
3041 while (i < len) {
3042 if (Character.isWhitespace(str.charAt(i))) {
3043 if (match || preserveAllTokens) {
3044 lastMatch = true;
3045 if (sizePlus1++ == max) {
3046 i = len;
3047 lastMatch = false;
3048 }
3049 list.add(str.substring(start, i));
3050 match = false;
3051 }
3052 start = ++i;
3053 continue;
3054 }
3055 lastMatch = false;
3056 match = true;
3057 i++;
3058 }
3059 } else if (separatorChars.length() == 1) {
3060 // Optimise 1 character case
3061 char sep = separatorChars.charAt(0);
3062 while (i < len) {
3063 if (str.charAt(i) == sep) {
3064 if (match || preserveAllTokens) {
3065 lastMatch = true;
3066 if (sizePlus1++ == max) {
3067 i = len;
3068 lastMatch = false;
3069 }
3070 list.add(str.substring(start, i));
3071 match = false;
3072 }
3073 start = ++i;
3074 continue;
3075 }
3076 lastMatch = false;
3077 match = true;
3078 i++;
3079 }
3080 } else {
3081 // standard case
3082 while (i < len) {
3083 if (separatorChars.indexOf(str.charAt(i)) >= 0) {
3084 if (match || preserveAllTokens) {
3085 lastMatch = true;
3086 if (sizePlus1++ == max) {
3087 i = len;
3088 lastMatch = false;
3089 }
3090 list.add(str.substring(start, i));
3091 match = false;
3092 }
3093 start = ++i;
3094 continue;
3095 }
3096 lastMatch = false;
3097 match = true;
3098 i++;
3099 }
3100 }
3101 if (match || (preserveAllTokens && lastMatch)) {
3102 list.add(str.substring(start, i));
3103 }
3104 return list.toArray(new String[list.size()]);
3105 }
3106
3107 /**
3108 * <p>Splits a String by Character type as returned by
3109 * {@code java.lang.Character.getType(char)}. Groups of contiguous
3110 * characters of the same type are returned as complete tokens.
3111 * <pre>
3112 * StringUtils.splitByCharacterType(null) = null
3113 * StringUtils.splitByCharacterType("") = []
3114 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"]
3115 * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"]
3116 * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"]
3117 * StringUtils.splitByCharacterType("number5") = ["number", "5"]
3118 * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"]
3119 * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"]
3120 * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"]
3121 * </pre>
3122 * @param str the String to split, may be {@code null}
3123 * @return an array of parsed Strings, {@code null} if null String input
3124 * @since 2.4
3125 */
3126 public static String[] splitByCharacterType(String str) {
3127 return splitByCharacterType(str, false);
3128 }
3129
3130 /**
3131 * <p>Splits a String by Character type as returned by
3132 * {@code java.lang.Character.getType(char)}. Groups of contiguous
3133 * characters of the same type are returned as complete tokens, with the
3134 * following exception: the character of type
3135 * {@code Character.UPPERCASE_LETTER}, if any, immediately
3136 * preceding a token of type {@code Character.LOWERCASE_LETTER}
3137 * will belong to the following token rather than to the preceding, if any,
3138 * {@code Character.UPPERCASE_LETTER} token.
3139 * <pre>
3140 * StringUtils.splitByCharacterTypeCamelCase(null) = null
3141 * StringUtils.splitByCharacterTypeCamelCase("") = []
3142 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
3143 * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
3144 * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"]
3145 * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"]
3146 * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"]
3147 * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"]
3148 * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"]
3149 * </pre>
3150 * @param str the String to split, may be {@code null}
3151 * @return an array of parsed Strings, {@code null} if null String input
3152 * @since 2.4
3153 */
3154 public static String[] splitByCharacterTypeCamelCase(String str) {
3155 return splitByCharacterType(str, true);
3156 }
3157
3158 /**
3159 * <p>Splits a String by Character type as returned by
3160 * {@code java.lang.Character.getType(char)}. Groups of contiguous
3161 * characters of the same type are returned as complete tokens, with the
3162 * following exception: if {@code camelCase} is {@code true},
3163 * the character of type {@code Character.UPPERCASE_LETTER}, if any,
3164 * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
3165 * will belong to the following token rather than to the preceding, if any,
3166 * {@code Character.UPPERCASE_LETTER} token.
3167 * @param str the String to split, may be {@code null}
3168 * @param camelCase whether to use so-called "camel-case" for letter types
3169 * @return an array of parsed Strings, {@code null} if null String input
3170 * @since 2.4
3171 */
3172 private static String[] splitByCharacterType(String str, boolean camelCase) {
3173 if (str == null) {
3174 return null;
3175 }
3176 if (str.length() == 0) {
3177 return ArrayUtils.EMPTY_STRING_ARRAY;
3178 }
3179 char[] c = str.toCharArray();
3180 List<String> list = new ArrayList<String>();
3181 int tokenStart = 0;
3182 int currentType = Character.getType(c[tokenStart]);
3183 for (int pos = tokenStart + 1; pos < c.length; pos++) {
3184 int type = Character.getType(c[pos]);
3185 if (type == currentType) {
3186 continue;
3187 }
3188 if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
3189 int newTokenStart = pos - 1;
3190 if (newTokenStart != tokenStart) {
3191 list.add(new String(c, tokenStart, newTokenStart - tokenStart));
3192 tokenStart = newTokenStart;
3193 }
3194 } else {
3195 list.add(new String(c, tokenStart, pos - tokenStart));
3196 tokenStart = pos;
3197 }
3198 currentType = type;
3199 }
3200 list.add(new String(c, tokenStart, c.length - tokenStart));
3201 return list.toArray(new String[list.size()]);
3202 }
3203
3204 // Joining
3205 //-----------------------------------------------------------------------
3206 /**
3207 * <p>Joins the elements of the provided array into a single String
3208 * containing the provided list of elements.</p>
3209 *
3210 * <p>No separator is added to the joined String.
3211 * Null objects or empty strings within the array are represented by
3212 * empty strings.</p>
3213 *
3214 * <pre>
3215 * StringUtils.join(null) = null
3216 * StringUtils.join([]) = ""
3217 * StringUtils.join([null]) = ""
3218 * StringUtils.join(["a", "b", "c"]) = "abc"
3219 * StringUtils.join([null, "", "a"]) = "a"
3220 * </pre>
3221 *
3222 * @param <T> the specific type of values to join together
3223 * @param elements the values to join together, may be null
3224 * @return the joined String, {@code null} if null array input
3225 * @since 2.0
3226 * @since 3.0 Changed signature to use varargs
3227 */
3228 public static <T> String join(T... elements) {
3229 return join(elements, null);
3230 }
3231
3232 /**
3233 * <p>Joins the elements of the provided array into a single String
3234 * containing the provided list of elements.</p>
3235 *
3236 * <p>No delimiter is added before or after the list.
3237 * Null objects or empty strings within the array are represented by
3238 * empty strings.</p>
3239 *
3240 * <pre>
3241 * StringUtils.join(null, *) = null
3242 * StringUtils.join([], *) = ""
3243 * StringUtils.join([null], *) = ""
3244 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
3245 * StringUtils.join(["a", "b", "c"], null) = "abc"
3246 * StringUtils.join([null, "", "a"], ';') = ";;a"
3247 * </pre>
3248 *
3249 * @param array the array of values to join together, may be null
3250 * @param separator the separator character to use
3251 * @return the joined String, {@code null} if null array input
3252 * @since 2.0
3253 */
3254 public static String join(Object[] array, char separator) {
3255 if (array == null) {
3256 return null;
3257 }
3258
3259 return join(array, separator, 0, array.length);
3260 }
3261
3262 /**
3263 * <p>Joins the elements of the provided array into a single String
3264 * containing the provided list of elements.</p>
3265 *
3266 * <p>No delimiter is added before or after the list.
3267 * Null objects or empty strings within the array are represented by
3268 * empty strings.</p>
3269 *
3270 * <pre>
3271 * StringUtils.join(null, *) = null
3272 * StringUtils.join([], *) = ""
3273 * StringUtils.join([null], *) = ""
3274 * StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
3275 * StringUtils.join(["a", "b", "c"], null) = "abc"
3276 * StringUtils.join([null, "", "a"], ';') = ";;a"
3277 * </pre>
3278 *
3279 * @param array the array of values to join together, may be null
3280 * @param separator the separator character to use
3281 * @param startIndex the first index to start joining from. It is
3282 * an error to pass in an end index past the end of the array
3283 * @param endIndex the index to stop joining from (exclusive). It is
3284 * an error to pass in an end index past the end of the array
3285 * @return the joined String, {@code null} if null array input
3286 * @since 2.0
3287 */
3288 public static String join(Object[] array, char separator, int startIndex, int endIndex) {
3289 if (array == null) {
3290 return null;
3291 }
3292 int noOfItems = (endIndex - startIndex);
3293 if (noOfItems <= 0) {
3294 return EMPTY;
3295 }
3296
3297 StringBuilder buf = new StringBuilder(noOfItems * 16);
3298
3299 for (int i = startIndex; i < endIndex; i++) {
3300 if (i > startIndex) {
3301 buf.append(separator);
3302 }
3303 if (array[i] != null) {
3304 buf.append(array[i]);
3305 }
3306 }
3307 return buf.toString();
3308 }
3309
3310 /**
3311 * <p>Joins the elements of the provided array into a single String
3312 * containing the provided list of elements.</p>
3313 *
3314 * <p>No delimiter is added before or after the list.
3315 * A {@code null} separator is the same as an empty String ("").
3316 * Null objects or empty strings within the array are represented by
3317 * empty strings.</p>
3318 *
3319 * <pre>
3320 * StringUtils.join(null, *) = null
3321 * StringUtils.join([], *) = ""
3322 * StringUtils.join([null], *) = ""
3323 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
3324 * StringUtils.join(["a", "b", "c"], null) = "abc"
3325 * StringUtils.join(["a", "b", "c"], "") = "abc"
3326 * StringUtils.join([null, "", "a"], ',') = ",,a"
3327 * </pre>
3328 *
3329 * @param array the array of values to join together, may be null
3330 * @param separator the separator character to use, null treated as ""
3331 * @return the joined String, {@code null} if null array input
3332 */
3333 public static String join(Object[] array, String separator) {
3334 if (array == null) {
3335 return null;
3336 }
3337 return join(array, separator, 0, array.length);
3338 }
3339
3340 /**
3341 * <p>Joins the elements of the provided array into a single String
3342 * containing the provided list of elements.</p>
3343 *
3344 * <p>No delimiter is added before or after the list.
3345 * A {@code null} separator is the same as an empty String ("").
3346 * Null objects or empty strings within the array are represented by
3347 * empty strings.</p>
3348 *
3349 * <pre>
3350 * StringUtils.join(null, *) = null
3351 * StringUtils.join([], *) = ""
3352 * StringUtils.join([null], *) = ""
3353 * StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
3354 * StringUtils.join(["a", "b", "c"], null) = "abc"
3355 * StringUtils.join(["a", "b", "c"], "") = "abc"
3356 * StringUtils.join([null, "", "a"], ',') = ",,a"
3357 * </pre>
3358 *
3359 * @param array the array of values to join together, may be null
3360 * @param separator the separator character to use, null treated as ""
3361 * @param startIndex the first index to start joining from. It is
3362 * an error to pass in an end index past the end of the array
3363 * @param endIndex the index to stop joining from (exclusive). It is
3364 * an error to pass in an end index past the end of the array
3365 * @return the joined String, {@code null} if null array input
3366 */
3367 public static String join(Object[] array, String separator, int startIndex, int endIndex) {
3368 if (array == null) {
3369 return null;
3370 }
3371 if (separator == null) {
3372 separator = EMPTY;
3373 }
3374
3375 // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator))
3376 // (Assuming that all Strings are roughly equally long)
3377 int noOfItems = (endIndex - startIndex);
3378 if (noOfItems <= 0) {
3379 return EMPTY;
3380 }
3381
3382 StringBuilder buf = new StringBuilder(noOfItems * 16);
3383
3384 for (int i = startIndex; i < endIndex; i++) {
3385 if (i > startIndex) {
3386 buf.append(separator);
3387 }
3388 if (array[i] != null) {
3389 buf.append(array[i]);
3390 }
3391 }
3392 return buf.toString();
3393 }
3394
3395 /**
3396 * <p>Joins the elements of the provided {@code Iterator} into
3397 * a single String containing the provided elements.</p>
3398 *
3399 * <p>No delimiter is added before or after the list. Null objects or empty
3400 * strings within the iteration are represented by empty strings.</p>
3401 *
3402 * <p>See the examples here: {@link #join(Object[],char)}. </p>
3403 *
3404 * @param iterator the {@code Iterator} of values to join together, may be null
3405 * @param separator the separator character to use
3406 * @return the joined String, {@code null} if null iterator input
3407 * @since 2.0
3408 */
3409 public static String join(Iterator<?> iterator, char separator) {
3410
3411 // handle null, zero and one elements before building a buffer
3412 if (iterator == null) {
3413 return null;
3414 }
3415 if (!iterator.hasNext()) {
3416 return EMPTY;
3417 }
3418 Object first = iterator.next();
3419 if (!iterator.hasNext()) {
3420 return ObjectUtils.toString(first);
3421 }
3422
3423 // two or more elements
3424 StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
3425 if (first != null) {
3426 buf.append(first);
3427 }
3428
3429 while (iterator.hasNext()) {
3430 buf.append(separator);
3431 Object obj = iterator.next();
3432 if (obj != null) {
3433 buf.append(obj);
3434 }
3435 }
3436
3437 return buf.toString();
3438 }
3439
3440 /**
3441 * <p>Joins the elements of the provided {@code Iterator} into
3442 * a single String containing the provided elements.</p>
3443 *
3444 * <p>No delimiter is added before or after the list.
3445 * A {@code null} separator is the same as an empty String ("").</p>
3446 *
3447 * <p>See the examples here: {@link #join(Object[],String)}. </p>
3448 *
3449 * @param iterator the {@code Iterator} of values to join together, may be null
3450 * @param separator the separator character to use, null treated as ""
3451 * @return the joined String, {@code null} if null iterator input
3452 */
3453 public static String join(Iterator<?> iterator, String separator) {
3454
3455 // handle null, zero and one elements before building a buffer
3456 if (iterator == null) {
3457 return null;
3458 }
3459 if (!iterator.hasNext()) {
3460 return EMPTY;
3461 }
3462 Object first = iterator.next();
3463 if (!iterator.hasNext()) {
3464 return ObjectUtils.toString(first);
3465 }
3466
3467 // two or more elements
3468 StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
3469 if (first != null) {
3470 buf.append(first);
3471 }
3472
3473 while (iterator.hasNext()) {
3474 if (separator != null) {
3475 buf.append(separator);
3476 }
3477 Object obj = iterator.next();
3478 if (obj != null) {
3479 buf.append(obj);
3480 }
3481 }
3482 return buf.toString();
3483 }
3484
3485 /**
3486 * <p>Joins the elements of the provided {@code Iterable} into
3487 * a single String containing the provided elements.</p>
3488 *
3489 * <p>No delimiter is added before or after the list. Null objects or empty
3490 * strings within the iteration are represented by empty strings.</p>
3491 *
3492 * <p>See the examples here: {@link #join(Object[],char)}. </p>
3493 *
3494 * @param iterable the {@code Iterable} providing the values to join together, may be null
3495 * @param separator the separator character to use
3496 * @return the joined String, {@code null} if null iterator input
3497 * @since 2.3
3498 */
3499 public static String join(Iterable<?> iterable, char separator) {
3500 if (iterable == null) {
3501 return null;
3502 }
3503 return join(iterable.iterator(), separator);
3504 }
3505
3506 /**
3507 * <p>Joins the elements of the provided {@code Iterable} into
3508 * a single String containing the provided elements.</p>
3509 *
3510 * <p>No delimiter is added before or after the list.
3511 * A {@code null} separator is the same as an empty String ("").</p>
3512 *
3513 * <p>See the examples here: {@link #join(Object[],String)}. </p>
3514 *
3515 * @param iterable the {@code Iterable} providing the values to join together, may be null
3516 * @param separator the separator character to use, null treated as ""
3517 * @return the joined String, {@code null} if null iterator input
3518 * @since 2.3
3519 */
3520 public static String join(Iterable<?> iterable, String separator) {
3521 if (iterable == null) {
3522 return null;
3523 }
3524 return join(iterable.iterator(), separator);
3525 }
3526
3527 // Delete
3528 //-----------------------------------------------------------------------
3529 /**
3530 * <p>Deletes all whitespaces from a String as defined by
3531 * {@link Character#isWhitespace(char)}.</p>
3532 *
3533 * <pre>
3534 * StringUtils.deleteWhitespace(null) = null
3535 * StringUtils.deleteWhitespace("") = ""
3536 * StringUtils.deleteWhitespace("abc") = "abc"
3537 * StringUtils.deleteWhitespace(" ab c ") = "abc"
3538 * </pre>
3539 *
3540 * @param str the String to delete whitespace from, may be null
3541 * @return the String without whitespaces, {@code null} if null String input
3542 */
3543 public static String deleteWhitespace(String str) {
3544 if (isEmpty(str)) {
3545 return str;
3546 }
3547 int sz = str.length();
3548 char[] chs = new char[sz];
3549 int count = 0;
3550 for (int i = 0; i < sz; i++) {
3551 if (!Character.isWhitespace(str.charAt(i))) {
3552 chs[count++] = str.charAt(i);
3553 }
3554 }
3555 if (count == sz) {
3556 return str;
3557 }
3558 return new String(chs, 0, count);
3559 }
3560
3561 // Remove
3562 //-----------------------------------------------------------------------
3563 /**
3564 * <p>Removes a substring only if it is at the beginning of a source string,
3565 * otherwise returns the source string.</p>
3566 *
3567 * <p>A {@code null} source string will return {@code null}.
3568 * An empty ("") source string will return the empty string.
3569 * A {@code null} search string will return the source string.</p>
3570 *
3571 * <pre>
3572 * StringUtils.removeStart(null, *) = null
3573 * StringUtils.removeStart("", *) = ""
3574 * StringUtils.removeStart(*, null) = *
3575 * StringUtils.removeStart("www.domain.com", "www.") = "domain.com"
3576 * StringUtils.removeStart("domain.com", "www.") = "domain.com"
3577 * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
3578 * StringUtils.removeStart("abc", "") = "abc"
3579 * </pre>
3580 *
3581 * @param str the source String to search, may be null
3582 * @param remove the String to search for and remove, may be null
3583 * @return the substring with the string removed if found,
3584 * {@code null} if null String input
3585 * @since 2.1
3586 */
3587 public static String removeStart(String str, String remove) {
3588 if (isEmpty(str) || isEmpty(remove)) {
3589 return str;
3590 }
3591 if (str.startsWith(remove)){
3592 return str.substring(remove.length());
3593 }
3594 return str;
3595 }
3596
3597 /**
3598 * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
3599 * otherwise returns the source string.</p>
3600 *
3601 * <p>A {@code null} source string will return {@code null}.
3602 * An empty ("") source string will return the empty string.
3603 * A {@code null} search string will return the source string.</p>
3604 *
3605 * <pre>
3606 * StringUtils.removeStartIgnoreCase(null, *) = null
3607 * StringUtils.removeStartIgnoreCase("", *) = ""
3608 * StringUtils.removeStartIgnoreCase(*, null) = *
3609 * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com"
3610 * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com"
3611 * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com"
3612 * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
3613 * StringUtils.removeStartIgnoreCase("abc", "") = "abc"
3614 * </pre>
3615 *
3616 * @param str the source String to search, may be null
3617 * @param remove the String to search for (case insensitive) and remove, may be null
3618 * @return the substring with the string removed if found,
3619 * {@code null} if null String input
3620 * @since 2.4
3621 */
3622 public static String removeStartIgnoreCase(String str, String remove) {
3623 if (isEmpty(str) || isEmpty(remove)) {
3624 return str;
3625 }
3626 if (startsWithIgnoreCase(str, remove)) {
3627 return str.substring(remove.length());
3628 }
3629 return str;
3630 }
3631
3632 /**
3633 * <p>Removes a substring only if it is at the end of a source string,
3634 * otherwise returns the source string.</p>
3635 *
3636 * <p>A {@code null} source string will return {@code null}.
3637 * An empty ("") source string will return the empty string.
3638 * A {@code null} search string will return the source string.</p>
3639 *
3640 * <pre>
3641 * StringUtils.removeEnd(null, *) = null
3642 * StringUtils.removeEnd("", *) = ""
3643 * StringUtils.removeEnd(*, null) = *
3644 * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com"
3645 * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain"
3646 * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
3647 * StringUtils.removeEnd("abc", "") = "abc"
3648 * </pre>
3649 *
3650 * @param str the source String to search, may be null
3651 * @param remove the String to search for and remove, may be null
3652 * @return the substring with the string removed if found,
3653 * {@code null} if null String input
3654 * @since 2.1
3655 */
3656 public static String removeEnd(String str, String remove) {
3657 if (isEmpty(str) || isEmpty(remove)) {
3658 return str;
3659 }
3660 if (str.endsWith(remove)) {
3661 return str.substring(0, str.length() - remove.length());
3662 }
3663 return str;
3664 }
3665
3666 /**
3667 * <p>Case insensitive removal of a substring if it is at the end of a source string,
3668 * otherwise returns the source string.</p>
3669 *
3670 * <p>A {@code null} source string will return {@code null}.
3671 * An empty ("") source string will return the empty string.
3672 * A {@code null} search string will return the source string.</p>
3673 *
3674 * <pre>
3675 * StringUtils.removeEndIgnoreCase(null, *) = null
3676 * StringUtils.removeEndIgnoreCase("", *) = ""
3677 * StringUtils.removeEndIgnoreCase(*, null) = *
3678 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com"
3679 * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain"
3680 * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
3681 * StringUtils.removeEndIgnoreCase("abc", "") = "abc"
3682 * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
3683 * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
3684 * </pre>
3685 *
3686 * @param str the source String to search, may be null
3687 * @param remove the String to search for (case insensitive) and remove, may be null
3688 * @return the substring with the string removed if found,
3689 * {@code null} if null String input
3690 * @since 2.4
3691 */
3692 public static String removeEndIgnoreCase(String str, String remove) {
3693 if (isEmpty(str) || isEmpty(remove)) {
3694 return str;
3695 }
3696 if (endsWithIgnoreCase(str, remove)) {
3697 return str.substring(0, str.length() - remove.length());
3698 }
3699 return str;
3700 }
3701
3702 /**
3703 * <p>Removes all occurrences of a substring from within the source string.</p>
3704 *
3705 * <p>A {@code null} source string will return {@code null}.
3706 * An empty ("") source string will return the empty string.
3707 * A {@code null} remove string will return the source string.
3708 * An empty ("") remove string will return the source string.</p>
3709 *
3710 * <pre>
3711 * StringUtils.remove(null, *) = null
3712 * StringUtils.remove("", *) = ""
3713 * StringUtils.remove(*, null) = *
3714 * StringUtils.remove(*, "") = *
3715 * StringUtils.remove("queued", "ue") = "qd"
3716 * StringUtils.remove("queued", "zz") = "queued"
3717 * </pre>
3718 *
3719 * @param str the source String to search, may be null
3720 * @param remove the String to search for and remove, may be null
3721 * @return the substring with the string removed if found,
3722 * {@code null} if null String input
3723 * @since 2.1
3724 */
3725 public static String remove(String str, String remove) {
3726 if (isEmpty(str) || isEmpty(remove)) {
3727 return str;
3728 }
3729 return replace(str, remove, EMPTY, -1);
3730 }
3731
3732 /**
3733 * <p>Removes all occurrences of a character from within the source string.</p>
3734 *
3735 * <p>A {@code null} source string will return {@code null}.
3736 * An empty ("") source string will return the empty string.</p>
3737 *
3738 * <pre>
3739 * StringUtils.remove(null, *) = null
3740 * StringUtils.remove("", *) = ""
3741 * StringUtils.remove("queued", 'u') = "qeed"
3742 * StringUtils.remove("queued", 'z') = "queued"
3743 * </pre>
3744 *
3745 * @param str the source String to search, may be null
3746 * @param remove the char to search for and remove, may be null
3747 * @return the substring with the char removed if found,
3748 * {@code null} if null String input
3749 * @since 2.1
3750 */
3751 public static String remove(String str, char remove) {
3752 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
3753 return str;
3754 }
3755 char[] chars = str.toCharArray();
3756 int pos = 0;
3757 for (int i = 0; i < chars.length; i++) {
3758 if (chars[i] != remove) {
3759 chars[pos++] = chars[i];
3760 }
3761 }
3762 return new String(chars, 0, pos);
3763 }
3764
3765 // Replacing
3766 //-----------------------------------------------------------------------
3767 /**
3768 * <p>Replaces a String with another String inside a larger String, once.</p>
3769 *
3770 * <p>A {@code null} reference passed to this method is a no-op.</p>
3771 *
3772 * <pre>
3773 * StringUtils.replaceOnce(null, *, *) = null
3774 * StringUtils.replaceOnce("", *, *) = ""
3775 * StringUtils.replaceOnce("any", null, *) = "any"
3776 * StringUtils.replaceOnce("any", *, null) = "any"
3777 * StringUtils.replaceOnce("any", "", *) = "any"
3778 * StringUtils.replaceOnce("aba", "a", null) = "aba"
3779 * StringUtils.replaceOnce("aba", "a", "") = "ba"
3780 * StringUtils.replaceOnce("aba", "a", "z") = "zba"
3781 * </pre>
3782 *
3783 * @see #replace(String text, String searchString, String replacement, int max)
3784 * @param text text to search and replace in, may be null
3785 * @param searchString the String to search for, may be null
3786 * @param replacement the String to replace with, may be null
3787 * @return the text with any replacements processed,
3788 * {@code null} if null String input
3789 */
3790 public static String replaceOnce(String text, String searchString, String replacement) {
3791 return replace(text, searchString, replacement, 1);
3792 }
3793
3794 /**
3795 * <p>Replaces all occurrences of a String within another String.</p>
3796 *
3797 * <p>A {@code null} reference passed to this method is a no-op.</p>
3798 *
3799 * <pre>
3800 * StringUtils.replace(null, *, *) = null
3801 * StringUtils.replace("", *, *) = ""
3802 * StringUtils.replace("any", null, *) = "any"
3803 * StringUtils.replace("any", *, null) = "any"
3804 * StringUtils.replace("any", "", *) = "any"
3805 * StringUtils.replace("aba", "a", null) = "aba"
3806 * StringUtils.replace("aba", "a", "") = "b"
3807 * StringUtils.replace("aba", "a", "z") = "zbz"
3808 * </pre>
3809 *
3810 * @see #replace(String text, String searchString, String replacement, int max)
3811 * @param text text to search and replace in, may be null
3812 * @param searchString the String to search for, may be null
3813 * @param replacement the String to replace it with, may be null
3814 * @return the text with any replacements processed,
3815 * {@code null} if null String input
3816 */
3817 public static String replace(String text, String searchString, String replacement) {
3818 return replace(text, searchString, replacement, -1);
3819 }
3820
3821 /**
3822 * <p>Replaces a String with another String inside a larger String,
3823 * for the first {@code max} values of the search String.</p>
3824 *
3825 * <p>A {@code null} reference passed to this method is a no-op.</p>
3826 *
3827 * <pre>
3828 * StringUtils.replace(null, *, *, *) = null
3829 * StringUtils.replace("", *, *, *) = ""
3830 * StringUtils.replace("any", null, *, *) = "any"
3831 * StringUtils.replace("any", *, null, *) = "any"
3832 * StringUtils.replace("any", "", *, *) = "any"
3833 * StringUtils.replace("any", *, *, 0) = "any"
3834 * StringUtils.replace("abaa", "a", null, -1) = "abaa"
3835 * StringUtils.replace("abaa", "a", "", -1) = "b"
3836 * StringUtils.replace("abaa", "a", "z", 0) = "abaa"
3837 * StringUtils.replace("abaa", "a", "z", 1) = "zbaa"
3838 * StringUtils.replace("abaa", "a", "z", 2) = "zbza"
3839 * StringUtils.replace("abaa", "a", "z", -1) = "zbzz"
3840 * </pre>
3841 *
3842 * @param text text to search and replace in, may be null
3843 * @param searchString the String to search for, may be null
3844 * @param replacement the String to replace it with, may be null
3845 * @param max maximum number of values to replace, or {@code -1} if no maximum
3846 * @return the text with any replacements processed,
3847 * {@code null} if null String input
3848 */
3849 public static String replace(String text, String searchString, String replacement, int max) {
3850 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
3851 return text;
3852 }
3853 int start = 0;
3854 int end = text.indexOf(searchString, start);
3855 if (end == INDEX_NOT_FOUND) {
3856 return text;
3857 }
3858 int replLength = searchString.length();
3859 int increase = replacement.length() - replLength;
3860 increase = (increase < 0 ? 0 : increase);
3861 increase *= (max < 0 ? 16 : (max > 64 ? 64 : max));
3862 StringBuilder buf = new StringBuilder(text.length() + increase);
3863 while (end != INDEX_NOT_FOUND) {
3864 buf.append(text.substring(start, end)).append(replacement);
3865 start = end + replLength;
3866 if (--max == 0) {
3867 break;
3868 }
3869 end = text.indexOf(searchString, start);
3870 }
3871 buf.append(text.substring(start));
3872 return buf.toString();
3873 }
3874
3875 /**
3876 * <p>
3877 * Replaces all occurrences of Strings within another String.
3878 * </p>
3879 *
3880 * <p>
3881 * A {@code null} reference passed to this method is a no-op, or if
3882 * any "search string" or "string to replace" is null, that replace will be
3883 * ignored. This will not repeat. For repeating replaces, call the
3884 * overloaded method.
3885 * </p>
3886 *
3887 * <pre>
3888 * StringUtils.replaceEach(null, *, *) = null
3889 * StringUtils.replaceEach("", *, *) = ""
3890 * StringUtils.replaceEach("aba", null, null) = "aba"
3891 * StringUtils.replaceEach("aba", new String[0], null) = "aba"
3892 * StringUtils.replaceEach("aba", null, new String[0]) = "aba"
3893 * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba"
3894 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b"
3895 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba"
3896 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
3897 * (example of how it does not repeat)
3898 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte"
3899 * </pre>
3900 *
3901 * @param text
3902 * text to search and replace in, no-op if null
3903 * @param searchList
3904 * the Strings to search for, no-op if null
3905 * @param replacementList
3906 * the Strings to replace them with, no-op if null
3907 * @return the text with any replacements processed, {@code null} if
3908 * null String input
3909 * @throws IllegalArgumentException
3910 * if the lengths of the arrays are not the same (null is ok,
3911 * and/or size 0)
3912 * @since 2.4
3913 */
3914 public static String replaceEach(String text, String[] searchList, String[] replacementList) {
3915 return replaceEach(text, searchList, replacementList, false, 0);
3916 }
3917
3918 /**
3919 * <p>
3920 * Replaces all occurrences of Strings within another String.
3921 * </p>
3922 *
3923 * <p>
3924 * A {@code null} reference passed to this method is a no-op, or if
3925 * any "search string" or "string to replace" is null, that replace will be
3926 * ignored.
3927 * </p>
3928 *
3929 * <pre>
3930 * StringUtils.replaceEach(null, *, *, *) = null
3931 * StringUtils.replaceEach("", *, *, *) = ""
3932 * StringUtils.replaceEach("aba", null, null, *) = "aba"
3933 * StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
3934 * StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
3935 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
3936 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
3937 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
3938 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
3939 * (example of how it repeats)
3940 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
3941 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
3942 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, true) = IllegalStateException
3943 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, false) = "dcabe"
3944 * </pre>
3945 *
3946 * @param text
3947 * text to search and replace in, no-op if null
3948 * @param searchList
3949 * the Strings to search for, no-op if null
3950 * @param replacementList
3951 * the Strings to replace them with, no-op if null
3952 * @return the text with any replacements processed, {@code null} if
3953 * null String input
3954 * @throws IllegalStateException
3955 * if the search is repeating and there is an endless loop due
3956 * to outputs of one being inputs to another
3957 * @throws IllegalArgumentException
3958 * if the lengths of the arrays are not the same (null is ok,
3959 * and/or size 0)
3960 * @since 2.4
3961 */
3962 public static String replaceEachRepeatedly(String text, String[] searchList, String[] replacementList) {
3963 // timeToLive should be 0 if not used or nothing to replace, else it's
3964 // the length of the replace array
3965 int timeToLive = searchList == null ? 0 : searchList.length;
3966 return replaceEach(text, searchList, replacementList, true, timeToLive);
3967 }
3968
3969 /**
3970 * <p>
3971 * Replaces all occurrences of Strings within another String.
3972 * </p>
3973 *
3974 * <p>
3975 * A {@code null} reference passed to this method is a no-op, or if
3976 * any "search string" or "string to replace" is null, that replace will be
3977 * ignored.
3978 * </p>
3979 *
3980 * <pre>
3981 * StringUtils.replaceEach(null, *, *, *) = null
3982 * StringUtils.replaceEach("", *, *, *) = ""
3983 * StringUtils.replaceEach("aba", null, null, *) = "aba"
3984 * StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
3985 * StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
3986 * StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
3987 * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
3988 * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
3989 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
3990 * (example of how it repeats)
3991 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
3992 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
3993 * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalStateException
3994 * </pre>
3995 *
3996 * @param text
3997 * text to search and replace in, no-op if null
3998 * @param searchList
3999 * the Strings to search for, no-op if null
4000 * @param replacementList
4001 * the Strings to replace them with, no-op if null
4002 * @param repeat if true, then replace repeatedly
4003 * until there are no more possible replacements or timeToLive < 0
4004 * @param timeToLive
4005 * if less than 0 then there is a circular reference and endless
4006 * loop
4007 * @return the text with any replacements processed, {@code null} if
4008 * null String input
4009 * @throws IllegalStateException
4010 * if the search is repeating and there is an endless loop due
4011 * to outputs of one being inputs to another
4012 * @throws IllegalArgumentException
4013 * if the lengths of the arrays are not the same (null is ok,
4014 * and/or size 0)
4015 * @since 2.4
4016 */
4017 private static String replaceEach(
4018 String text, String[] searchList, String[] replacementList, boolean repeat, int timeToLive) {
4019
4020 // mchyzer Performance note: This creates very few new objects (one major goal)
4021 // let me know if there are performance requests, we can create a harness to measure
4022
4023 if (text == null || text.length() == 0 || searchList == null ||
4024 searchList.length == 0 || replacementList == null || replacementList.length == 0) {
4025 return text;
4026 }
4027
4028 // if recursing, this shouldn't be less than 0
4029 if (timeToLive < 0) {
4030 throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
4031 "output of one loop is the input of another");
4032 }
4033
4034 int searchLength = searchList.length;
4035 int replacementLength = replacementList.length;
4036
4037 // make sure lengths are ok, these need to be equal
4038 if (searchLength != replacementLength) {
4039 throw new IllegalArgumentException("Search and Replace array lengths don't match: "
4040 + searchLength
4041 + " vs "
4042 + replacementLength);
4043 }
4044
4045 // keep track of which still have matches
4046 boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
4047
4048 // index on index that the match was found
4049 int textIndex = -1;
4050 int replaceIndex = -1;
4051 int tempIndex = -1;
4052
4053 // index of replace array that will replace the search string found
4054 // NOTE: logic duplicated below START
4055 for (int i = 0; i < searchLength; i++) {
4056 if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
4057 searchList[i].length() == 0 || replacementList[i] == null) {
4058 continue;
4059 }
4060 tempIndex = text.indexOf(searchList[i]);
4061
4062 // see if we need to keep searching for this
4063 if (tempIndex == -1) {
4064 noMoreMatchesForReplIndex[i] = true;
4065 } else {
4066 if (textIndex == -1 || tempIndex < textIndex) {
4067 textIndex = tempIndex;
4068 replaceIndex = i;
4069 }
4070 }
4071 }
4072 // NOTE: logic mostly below END
4073
4074 // no search strings found, we are done
4075 if (textIndex == -1) {
4076 return text;
4077 }
4078
4079 int start = 0;
4080
4081 // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
4082 int increase = 0;
4083
4084 // count the replacement text elements that are larger than their corresponding text being replaced
4085 for (int i = 0; i < searchList.length; i++) {
4086 if (searchList[i] == null || replacementList[i] == null) {
4087 continue;
4088 }
4089 int greater = replacementList[i].length() - searchList[i].length();
4090 if (greater > 0) {
4091 increase += 3 * greater; // assume 3 matches
4092 }
4093 }
4094 // have upper-bound at 20% increase, then let Java take over
4095 increase = Math.min(increase, text.length() / 5);
4096
4097 StringBuilder buf = new StringBuilder(text.length() + increase);
4098
4099 while (textIndex != -1) {
4100
4101 for (int i = start; i < textIndex; i++) {
4102 buf.append(text.charAt(i));
4103 }
4104 buf.append(replacementList[replaceIndex]);
4105
4106 start = textIndex + searchList[replaceIndex].length();
4107
4108 textIndex = -1;
4109 replaceIndex = -1;
4110 tempIndex = -1;
4111 // find the next earliest match
4112 // NOTE: logic mostly duplicated above START
4113 for (int i = 0; i < searchLength; i++) {
4114 if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
4115 searchList[i].length() == 0 || replacementList[i] == null) {
4116 continue;
4117 }
4118 tempIndex = text.indexOf(searchList[i], start);
4119
4120 // see if we need to keep searching for this
4121 if (tempIndex == -1) {
4122 noMoreMatchesForReplIndex[i] = true;
4123 } else {
4124 if (textIndex == -1 || tempIndex < textIndex) {
4125 textIndex = tempIndex;
4126 replaceIndex = i;
4127 }
4128 }
4129 }
4130 // NOTE: logic duplicated above END
4131
4132 }
4133 int textLength = text.length();
4134 for (int i = start; i < textLength; i++) {
4135 buf.append(text.charAt(i));
4136 }
4137 String result = buf.toString();
4138 if (!repeat) {
4139 return result;
4140 }
4141
4142 return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
4143 }
4144
4145 // Replace, character based
4146 //-----------------------------------------------------------------------
4147 /**
4148 * <p>Replaces all occurrences of a character in a String with another.
4149 * This is a null-safe version of {@link String#replace(char, char)}.</p>
4150 *
4151 * <p>A {@code null} string input returns {@code null}.
4152 * An empty ("") string input returns an empty string.</p>
4153 *
4154 * <pre>
4155 * StringUtils.replaceChars(null, *, *) = null
4156 * StringUtils.replaceChars("", *, *) = ""
4157 * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
4158 * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
4159 * </pre>
4160 *
4161 * @param str String to replace characters in, may be null
4162 * @param searchChar the character to search for, may be null
4163 * @param replaceChar the character to replace, may be null
4164 * @return modified String, {@code null} if null string input
4165 * @since 2.0
4166 */
4167 public static String replaceChars(String str, char searchChar, char replaceChar) {
4168 if (str == null) {
4169 return null;
4170 }
4171 return str.replace(searchChar, replaceChar);
4172 }
4173
4174 /**
4175 * <p>Replaces multiple characters in a String in one go.
4176 * This method can also be used to delete characters.</p>
4177 *
4178 * <p>For example:<br />
4179 * <code>replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly</code>.</p>
4180 *
4181 * <p>A {@code null} string input returns {@code null}.
4182 * An empty ("") string input returns an empty string.
4183 * A null or empty set of search characters returns the input string.</p>
4184 *
4185 * <p>The length of the search characters should normally equal the length
4186 * of the replace characters.
4187 * If the search characters is longer, then the extra search characters
4188 * are deleted.
4189 * If the search characters is shorter, then the extra replace characters
4190 * are ignored.</p>
4191 *
4192 * <pre>
4193 * StringUtils.replaceChars(null, *, *) = null
4194 * StringUtils.replaceChars("", *, *) = ""
4195 * StringUtils.replaceChars("abc", null, *) = "abc"
4196 * StringUtils.replaceChars("abc", "", *) = "abc"
4197 * StringUtils.replaceChars("abc", "b", null) = "ac"
4198 * StringUtils.replaceChars("abc", "b", "") = "ac"
4199 * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya"
4200 * StringUtils.replaceChars("abcba", "bc", "y") = "ayya"
4201 * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
4202 * </pre>
4203 *
4204 * @param str String to replace characters in, may be null
4205 * @param searchChars a set of characters to search for, may be null
4206 * @param replaceChars a set of characters to replace, may be null
4207 * @return modified String, {@code null} if null string input
4208 * @since 2.0
4209 */
4210 public static String replaceChars(String str, String searchChars, String replaceChars) {
4211 if (isEmpty(str) || isEmpty(searchChars)) {
4212 return str;
4213 }
4214 if (replaceChars == null) {
4215 replaceChars = EMPTY;
4216 }
4217 boolean modified = false;
4218 int replaceCharsLength = replaceChars.length();
4219 int strLength = str.length();
4220 StringBuilder buf = new StringBuilder(strLength);
4221 for (int i = 0; i < strLength; i++) {
4222 char ch = str.charAt(i);
4223 int index = searchChars.indexOf(ch);
4224 if (index >= 0) {
4225 modified = true;
4226 if (index < replaceCharsLength) {
4227 buf.append(replaceChars.charAt(index));
4228 }
4229 } else {
4230 buf.append(ch);
4231 }
4232 }
4233 if (modified) {
4234 return buf.toString();
4235 }
4236 return str;
4237 }
4238
4239 // Overlay
4240 //-----------------------------------------------------------------------
4241 /**
4242 * <p>Overlays part of a String with another String.</p>
4243 *
4244 * <p>A {@code null} string input returns {@code null}.
4245 * A negative index is treated as zero.
4246 * An index greater than the string length is treated as the string length.
4247 * The start index is always the smaller of the two indices.</p>
4248 *
4249 * <pre>
4250 * StringUtils.overlay(null, *, *, *) = null
4251 * StringUtils.overlay("", "abc", 0, 0) = "abc"
4252 * StringUtils.overlay("abcdef", null, 2, 4) = "abef"
4253 * StringUtils.overlay("abcdef", "", 2, 4) = "abef"
4254 * StringUtils.overlay("abcdef", "", 4, 2) = "abef"
4255 * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef"
4256 * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef"
4257 * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef"
4258 * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz"
4259 * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
4260 * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz"
4261 * </pre>
4262 *
4263 * @param str the String to do overlaying in, may be null
4264 * @param overlay the String to overlay, may be null
4265 * @param start the position to start overlaying at
4266 * @param end the position to stop overlaying before
4267 * @return overlayed String, {@code null} if null String input
4268 * @since 2.0
4269 */
4270 public static String overlay(String str, String overlay, int start, int end) {
4271 if (str == null) {
4272 return null;
4273 }
4274 if (overlay == null) {
4275 overlay = EMPTY;
4276 }
4277 int len = str.length();
4278 if (start < 0) {
4279 start = 0;
4280 }
4281 if (start > len) {
4282 start = len;
4283 }
4284 if (end < 0) {
4285 end = 0;
4286 }
4287 if (end > len) {
4288 end = len;
4289 }
4290 if (start > end) {
4291 int temp = start;
4292 start = end;
4293 end = temp;
4294 }
4295 return new StringBuilder(len + start - end + overlay.length() + 1)
4296 .append(str.substring(0, start))
4297 .append(overlay)
4298 .append(str.substring(end))
4299 .toString();
4300 }
4301
4302 // Chomping
4303 //-----------------------------------------------------------------------
4304 /**
4305 * <p>Removes one newline from end of a String if it's there,
4306 * otherwise leave it alone. A newline is &quot;{@code \n}&quot;,
4307 * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.</p>
4308 *
4309 * <p>NOTE: This method changed in 2.0.
4310 * It now more closely matches Perl chomp.</p>
4311 *
4312 * <pre>
4313 * StringUtils.chomp(null) = null
4314 * StringUtils.chomp("") = ""
4315 * StringUtils.chomp("abc \r") = "abc "
4316 * StringUtils.chomp("abc\n") = "abc"
4317 * StringUtils.chomp("abc\r\n") = "abc"
4318 * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
4319 * StringUtils.chomp("abc\n\r") = "abc\n"
4320 * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc"
4321 * StringUtils.chomp("\r") = ""
4322 * StringUtils.chomp("\n") = ""
4323 * StringUtils.chomp("\r\n") = ""
4324 * </pre>
4325 *
4326 * @param str the String to chomp a newline from, may be null
4327 * @return String without newline, {@code null} if null String input
4328 */
4329 public static String chomp(String str) {
4330 if (isEmpty(str)) {
4331 return str;
4332 }
4333
4334 if (str.length() == 1) {
4335 char ch = str.charAt(0);
4336 if (ch == CharUtils.CR || ch == CharUtils.LF) {
4337 return EMPTY;
4338 }
4339 return str;
4340 }
4341
4342 int lastIdx = str.length() - 1;
4343 char last = str.charAt(lastIdx);
4344
4345 if (last == CharUtils.LF) {
4346 if (str.charAt(lastIdx - 1) == CharUtils.CR) {
4347 lastIdx--;
4348 }
4349 } else if (last != CharUtils.CR) {
4350 lastIdx++;
4351 }
4352 return str.substring(0, lastIdx);
4353 }
4354
4355 /**
4356 * <p>Removes {@code separator} from the end of
4357 * {@code str} if it's there, otherwise leave it alone.</p>
4358 *
4359 * <p>NOTE: This method changed in version 2.0.
4360 * It now more closely matches Perl chomp.
4361 * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
4362 * This method uses {@link String#endsWith(String)}.</p>
4363 *
4364 * <pre>
4365 * StringUtils.chomp(null, *) = null
4366 * StringUtils.chomp("", *) = ""
4367 * StringUtils.chomp("foobar", "bar") = "foo"
4368 * StringUtils.chomp("foobar", "baz") = "foobar"
4369 * StringUtils.chomp("foo", "foo") = ""
4370 * StringUtils.chomp("foo ", "foo") = "foo "
4371 * StringUtils.chomp(" foo", "foo") = " "
4372 * StringUtils.chomp("foo", "foooo") = "foo"
4373 * StringUtils.chomp("foo", "") = "foo"
4374 * StringUtils.chomp("foo", null) = "foo"
4375 * </pre>
4376 *
4377 * @param str the String to chomp from, may be null
4378 * @param separator separator String, may be null
4379 * @return String without trailing separator, {@code null} if null String input
4380 */
4381 public static String chomp(String str, String separator) {
4382 if (isEmpty(str) || separator == null) {
4383 return str;
4384 }
4385 if (str.endsWith(separator)) {
4386 return str.substring(0, str.length() - separator.length());
4387 }
4388 return str;
4389 }
4390
4391 // Chopping
4392 //-----------------------------------------------------------------------
4393 /**
4394 * <p>Remove the last character from a String.</p>
4395 *
4396 * <p>If the String ends in {@code \r\n}, then remove both
4397 * of them.</p>
4398 *
4399 * <pre>
4400 * StringUtils.chop(null) = null
4401 * StringUtils.chop("") = ""
4402 * StringUtils.chop("abc \r") = "abc "
4403 * StringUtils.chop("abc\n") = "abc"
4404 * StringUtils.chop("abc\r\n") = "abc"
4405 * StringUtils.chop("abc") = "ab"
4406 * StringUtils.chop("abc\nabc") = "abc\nab"
4407 * StringUtils.chop("a") = ""
4408 * StringUtils.chop("\r") = ""
4409 * StringUtils.chop("\n") = ""
4410 * StringUtils.chop("\r\n") = ""
4411 * </pre>
4412 *
4413 * @param str the String to chop last character from, may be null
4414 * @return String without last character, {@code null} if null String input
4415 */
4416 public static String chop(String str) {
4417 if (str == null) {
4418 return null;
4419 }
4420 int strLen = str.length();
4421 if (strLen < 2) {
4422 return EMPTY;
4423 }
4424 int lastIdx = strLen - 1;
4425 String ret = str.substring(0, lastIdx);
4426 char last = str.charAt(lastIdx);
4427 if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
4428 return ret.substring(0, lastIdx - 1);
4429 }
4430 return ret;
4431 }
4432
4433 // Conversion
4434 //-----------------------------------------------------------------------
4435
4436 // Padding
4437 //-----------------------------------------------------------------------
4438 /**
4439 * <p>Repeat a String {@code repeat} times to form a
4440 * new String.</p>
4441 *
4442 * <pre>
4443 * StringUtils.repeat(null, 2) = null
4444 * StringUtils.repeat("", 0) = ""
4445 * StringUtils.repeat("", 2) = ""
4446 * StringUtils.repeat("a", 3) = "aaa"
4447 * StringUtils.repeat("ab", 2) = "abab"
4448 * StringUtils.repeat("a", -2) = ""
4449 * </pre>
4450 *
4451 * @param str the String to repeat, may be null
4452 * @param repeat number of times to repeat str, negative treated as zero
4453 * @return a new String consisting of the original String repeated,
4454 * {@code null} if null String input
4455 */
4456 public static String repeat(String str, int repeat) {
4457 // Performance tuned for 2.0 (JDK1.4)
4458
4459 if (str == null) {
4460 return null;
4461 }
4462 if (repeat <= 0) {
4463 return EMPTY;
4464 }
4465 int inputLength = str.length();
4466 if (repeat == 1 || inputLength == 0) {
4467 return str;
4468 }
4469 if (inputLength == 1 && repeat <= PAD_LIMIT) {
4470 return repeat(str.charAt(0), repeat);
4471 }
4472
4473 int outputLength = inputLength * repeat;
4474 switch (inputLength) {
4475 case 1 :
4476 return repeat(str.charAt(0), repeat);
4477 case 2 :
4478 char ch0 = str.charAt(0);
4479 char ch1 = str.charAt(1);
4480 char[] output2 = new char[outputLength];
4481 for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
4482 output2[i] = ch0;
4483 output2[i + 1] = ch1;
4484 }
4485 return new String(output2);
4486 default :
4487 StringBuilder buf = new StringBuilder(outputLength);
4488 for (int i = 0; i < repeat; i++) {
4489 buf.append(str);
4490 }
4491 return buf.toString();
4492 }
4493 }
4494
4495 /**
4496 * <p>Repeat a String {@code repeat} times to form a
4497 * new String, with a String separator injected each time. </p>
4498 *
4499 * <pre>
4500 * StringUtils.repeat(null, null, 2) = null
4501 * StringUtils.repeat(null, "x", 2) = null
4502 * StringUtils.repeat("", null, 0) = ""
4503 * StringUtils.repeat("", "", 2) = ""
4504 * StringUtils.repeat("", "x", 3) = "xxx"
4505 * StringUtils.repeat("?", ", ", 3) = "?, ?, ?"
4506 * </pre>
4507 *
4508 * @param str the String to repeat, may be null
4509 * @param separator the String to inject, may be null
4510 * @param repeat number of times to repeat str, negative treated as zero
4511 * @return a new String consisting of the original String repeated,
4512 * {@code null} if null String input
4513 * @since 2.5
4514 */
4515 public static String repeat(String str, String separator, int repeat) {
4516 if(str == null || separator == null) {
4517 return repeat(str, repeat);
4518 } else {
4519 // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
4520 String result = repeat(str + separator, repeat);
4521 return removeEnd(result, separator);
4522 }
4523 }
4524
4525 /**
4526 * <p>Returns padding using the specified delimiter repeated
4527 * to a given length.</p>
4528 *
4529 * <pre>
4530 * StringUtils.repeat(0, 'e') = ""
4531 * StringUtils.repeat(3, 'e') = "eee"
4532 * StringUtils.repeat(-2, 'e') = ""
4533 * </pre>
4534 *
4535 * <p>Note: this method doesn't not support padding with
4536 * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
4537 * as they require a pair of {@code char}s to be represented.
4538 * If you are needing to support full I18N of your applications
4539 * consider using {@link #repeat(String, int)} instead.
4540 * </p>
4541 *
4542 * @param ch character to repeat
4543 * @param repeat number of times to repeat char, negative treated as zero
4544 * @return String with repeated character
4545 * @see #repeat(String, int)
4546 */
4547 public static String repeat(char ch, int repeat) {
4548 char[] buf = new char[repeat];
4549 for (int i = repeat - 1; i >= 0; i--) {
4550 buf[i] = ch;
4551 }
4552 return new String(buf);
4553 }
4554
4555 /**
4556 * <p>Right pad a String with spaces (' ').</p>
4557 *
4558 * <p>The String is padded to the size of {@code size}.</p>
4559 *
4560 * <pre>
4561 * StringUtils.rightPad(null, *) = null
4562 * StringUtils.rightPad("", 3) = " "
4563 * StringUtils.rightPad("bat", 3) = "bat"
4564 * StringUtils.rightPad("bat", 5) = "bat "
4565 * StringUtils.rightPad("bat", 1) = "bat"
4566 * StringUtils.rightPad("bat", -1) = "bat"
4567 * </pre>
4568 *
4569 * @param str the String to pad out, may be null
4570 * @param size the size to pad to
4571 * @return right padded String or original String if no padding is necessary,
4572 * {@code null} if null String input
4573 */
4574 public static String rightPad(String str, int size) {
4575 return rightPad(str, size, ' ');
4576 }
4577
4578 /**
4579 * <p>Right pad a String with a specified character.</p>
4580 *
4581 * <p>The String is padded to the size of {@code size}.</p>
4582 *
4583 * <pre>
4584 * StringUtils.rightPad(null, *, *) = null
4585 * StringUtils.rightPad("", 3, 'z') = "zzz"
4586 * StringUtils.rightPad("bat", 3, 'z') = "bat"
4587 * StringUtils.rightPad("bat", 5, 'z') = "batzz"
4588 * StringUtils.rightPad("bat", 1, 'z') = "bat"
4589 * StringUtils.rightPad("bat", -1, 'z') = "bat"
4590 * </pre>
4591 *
4592 * @param str the String to pad out, may be null
4593 * @param size the size to pad to
4594 * @param padChar the character to pad with
4595 * @return right padded String or original String if no padding is necessary,
4596 * {@code null} if null String input
4597 * @since 2.0
4598 */
4599 public static String rightPad(String str, int size, char padChar) {
4600 if (str == null) {
4601 return null;
4602 }
4603 int pads = size - str.length();
4604 if (pads <= 0) {
4605 return str; // returns original String when possible
4606 }
4607 if (pads > PAD_LIMIT) {
4608 return rightPad(str, size, String.valueOf(padChar));
4609 }
4610 return str.concat(repeat(padChar, pads));
4611 }
4612
4613 /**
4614 * <p>Right pad a String with a specified String.</p>
4615 *
4616 * <p>The String is padded to the size of {@code size}.</p>
4617 *
4618 * <pre>
4619 * StringUtils.rightPad(null, *, *) = null
4620 * StringUtils.rightPad("", 3, "z") = "zzz"
4621 * StringUtils.rightPad("bat", 3, "yz") = "bat"
4622 * StringUtils.rightPad("bat", 5, "yz") = "batyz"
4623 * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy"
4624 * StringUtils.rightPad("bat", 1, "yz") = "bat"
4625 * StringUtils.rightPad("bat", -1, "yz") = "bat"
4626 * StringUtils.rightPad("bat", 5, null) = "bat "
4627 * StringUtils.rightPad("bat", 5, "") = "bat "
4628 * </pre>
4629 *
4630 * @param str the String to pad out, may be null
4631 * @param size the size to pad to
4632 * @param padStr the String to pad with, null or empty treated as single space
4633 * @return right padded String or original String if no padding is necessary,
4634 * {@code null} if null String input
4635 */
4636 public static String rightPad(String str, int size, String padStr) {
4637 if (str == null) {
4638 return null;
4639 }
4640 if (isEmpty(padStr)) {
4641 padStr = " ";
4642 }
4643 int padLen = padStr.length();
4644 int strLen = str.length();
4645 int pads = size - strLen;
4646 if (pads <= 0) {
4647 return str; // returns original String when possible
4648 }
4649 if (padLen == 1 && pads <= PAD_LIMIT) {
4650 return rightPad(str, size, padStr.charAt(0));
4651 }
4652
4653 if (pads == padLen) {
4654 return str.concat(padStr);
4655 } else if (pads < padLen) {
4656 return str.concat(padStr.substring(0, pads));
4657 } else {
4658 char[] padding = new char[pads];
4659 char[] padChars = padStr.toCharArray();
4660 for (int i = 0; i < pads; i++) {
4661 padding[i] = padChars[i % padLen];
4662 }
4663 return str.concat(new String(padding));
4664 }
4665 }
4666
4667 /**
4668 * <p>Left pad a String with spaces (' ').</p>
4669 *
4670 * <p>The String is padded to the size of {@code size}.</p>
4671 *
4672 * <pre>
4673 * StringUtils.leftPad(null, *) = null
4674 * StringUtils.leftPad("", 3) = " "
4675 * StringUtils.leftPad("bat", 3) = "bat"
4676 * StringUtils.leftPad("bat", 5) = " bat"
4677 * StringUtils.leftPad("bat", 1) = "bat"
4678 * StringUtils.leftPad("bat", -1) = "bat"
4679 * </pre>
4680 *
4681 * @param str the String to pad out, may be null
4682 * @param size the size to pad to
4683 * @return left padded String or original String if no padding is necessary,
4684 * {@code null} if null String input
4685 */
4686 public static String leftPad(String str, int size) {
4687 return leftPad(str, size, ' ');
4688 }
4689
4690 /**
4691 * <p>Left pad a String with a specified character.</p>
4692 *
4693 * <p>Pad to a size of {@code size}.</p>
4694 *
4695 * <pre>
4696 * StringUtils.leftPad(null, *, *) = null
4697 * StringUtils.leftPad("", 3, 'z') = "zzz"
4698 * StringUtils.leftPad("bat", 3, 'z') = "bat"
4699 * StringUtils.leftPad("bat", 5, 'z') = "zzbat"
4700 * StringUtils.leftPad("bat", 1, 'z') = "bat"
4701 * StringUtils.leftPad("bat", -1, 'z') = "bat"
4702 * </pre>
4703 *
4704 * @param str the String to pad out, may be null
4705 * @param size the size to pad to
4706 * @param padChar the character to pad with
4707 * @return left padded String or original String if no padding is necessary,
4708 * {@code null} if null String input
4709 * @since 2.0
4710 */
4711 public static String leftPad(String str, int size, char padChar) {
4712 if (str == null) {
4713 return null;
4714 }
4715 int pads = size - str.length();
4716 if (pads <= 0) {
4717 return str; // returns original String when possible
4718 }
4719 if (pads > PAD_LIMIT) {
4720 return leftPad(str, size, String.valueOf(padChar));
4721 }
4722 return repeat(padChar, pads).concat(str);
4723 }
4724
4725 /**
4726 * <p>Left pad a String with a specified String.</p>
4727 *
4728 * <p>Pad to a size of {@code size}.</p>
4729 *
4730 * <pre>
4731 * StringUtils.leftPad(null, *, *) = null
4732 * StringUtils.leftPad("", 3, "z") = "zzz"
4733 * StringUtils.leftPad("bat", 3, "yz") = "bat"
4734 * StringUtils.leftPad("bat", 5, "yz") = "yzbat"
4735 * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat"
4736 * StringUtils.leftPad("bat", 1, "yz") = "bat"
4737 * StringUtils.leftPad("bat", -1, "yz") = "bat"
4738 * StringUtils.leftPad("bat", 5, null) = " bat"
4739 * StringUtils.leftPad("bat", 5, "") = " bat"
4740 * </pre>
4741 *
4742 * @param str the String to pad out, may be null
4743 * @param size the size to pad to
4744 * @param padStr the String to pad with, null or empty treated as single space
4745 * @return left padded String or original String if no padding is necessary,
4746 * {@code null} if null String input
4747 */
4748 public static String leftPad(String str, int size, String padStr) {
4749 if (str == null) {
4750 return null;
4751 }
4752 if (isEmpty(padStr)) {
4753 padStr = " ";
4754 }
4755 int padLen = padStr.length();
4756 int strLen = str.length();
4757 int pads = size - strLen;
4758 if (pads <= 0) {
4759 return str; // returns original String when possible
4760 }
4761 if (padLen == 1 && pads <= PAD_LIMIT) {
4762 return leftPad(str, size, padStr.charAt(0));
4763 }
4764
4765 if (pads == padLen) {
4766 return padStr.concat(str);
4767 } else if (pads < padLen) {
4768 return padStr.substring(0, pads).concat(str);
4769 } else {
4770 char[] padding = new char[pads];
4771 char[] padChars = padStr.toCharArray();
4772 for (int i = 0; i < pads; i++) {
4773 padding[i] = padChars[i % padLen];
4774 }
4775 return new String(padding).concat(str);
4776 }
4777 }
4778
4779 /**
4780 * Gets a CharSequence length or {@code 0} if the CharSequence is
4781 * {@code null}.
4782 *
4783 * @param cs
4784 * a CharSequence or {@code null}
4785 * @return CharSequence length or {@code 0} if the CharSequence is
4786 * {@code null}.
4787 * @since 2.4
4788 * @since 3.0 Changed signature from length(String) to length(CharSequence)
4789 */
4790 public static int length(CharSequence cs) {
4791 return cs == null ? 0 : cs.length();
4792 }
4793
4794 // Centering
4795 //-----------------------------------------------------------------------
4796 /**
4797 * <p>Centers a String in a larger String of size {@code size}
4798 * using the space character (' ').<p>
4799 *
4800 * <p>If the size is less than the String length, the String is returned.
4801 * A {@code null} String returns {@code null}.
4802 * A negative size is treated as zero.</p>
4803 *
4804 * <p>Equivalent to {@code center(str, size, " ")}.</p>
4805 *
4806 * <pre>
4807 * StringUtils.center(null, *) = null
4808 * StringUtils.center("", 4) = " "
4809 * StringUtils.center("ab", -1) = "ab"
4810 * StringUtils.center("ab", 4) = " ab "
4811 * StringUtils.center("abcd", 2) = "abcd"
4812 * StringUtils.center("a", 4) = " a "
4813 * </pre>
4814 *
4815 * @param str the String to center, may be null
4816 * @param size the int size of new String, negative treated as zero
4817 * @return centered String, {@code null} if null String input
4818 */
4819 public static String center(String str, int size) {
4820 return center(str, size, ' ');
4821 }
4822
4823 /**
4824 * <p>Centers a String in a larger String of size {@code size}.
4825 * Uses a supplied character as the value to pad the String with.</p>
4826 *
4827 * <p>If the size is less than the String length, the String is returned.
4828 * A {@code null} String returns {@code null}.
4829 * A negative size is treated as zero.</p>
4830 *
4831 * <pre>
4832 * StringUtils.center(null, *, *) = null
4833 * StringUtils.center("", 4, ' ') = " "
4834 * StringUtils.center("ab", -1, ' ') = "ab"
4835 * StringUtils.center("ab", 4, ' ') = " ab"
4836 * StringUtils.center("abcd", 2, ' ') = "abcd"
4837 * StringUtils.center("a", 4, ' ') = " a "
4838 * StringUtils.center("a", 4, 'y') = "yayy"
4839 * </pre>
4840 *
4841 * @param str the String to center, may be null
4842 * @param size the int size of new String, negative treated as zero
4843 * @param padChar the character to pad the new String with
4844 * @return centered String, {@code null} if null String input
4845 * @since 2.0
4846 */
4847 public static String center(String str, int size, char padChar) {
4848 if (str == null || size <= 0) {
4849 return str;
4850 }
4851 int strLen = str.length();
4852 int pads = size - strLen;
4853 if (pads <= 0) {
4854 return str;
4855 }
4856 str = leftPad(str, strLen + pads / 2, padChar);
4857 str = rightPad(str, size, padChar);
4858 return str;
4859 }
4860
4861 /**
4862 * <p>Centers a String in a larger String of size {@code size}.
4863 * Uses a supplied String as the value to pad the String with.</p>
4864 *
4865 * <p>If the size is less than the String length, the String is returned.
4866 * A {@code null} String returns {@code null}.
4867 * A negative size is treated as zero.</p>
4868 *
4869 * <pre>
4870 * StringUtils.center(null, *, *) = null
4871 * StringUtils.center("", 4, " ") = " "
4872 * StringUtils.center("ab", -1, " ") = "ab"
4873 * StringUtils.center("ab", 4, " ") = " ab"
4874 * StringUtils.center("abcd", 2, " ") = "abcd"
4875 * StringUtils.center("a", 4, " ") = " a "
4876 * StringUtils.center("a", 4, "yz") = "yayz"
4877 * StringUtils.center("abc", 7, null) = " abc "
4878 * StringUtils.center("abc", 7, "") = " abc "
4879 * </pre>
4880 *
4881 * @param str the String to center, may be null
4882 * @param size the int size of new String, negative treated as zero
4883 * @param padStr the String to pad the new String with, must not be null or empty
4884 * @return centered String, {@code null} if null String input
4885 * @throws IllegalArgumentException if padStr is {@code null} or empty
4886 */
4887 public static String center(String str, int size, String padStr) {
4888 if (str == null || size <= 0) {
4889 return str;
4890 }
4891 if (isEmpty(padStr)) {
4892 padStr = " ";
4893 }
4894 int strLen = str.length();
4895 int pads = size - strLen;
4896 if (pads <= 0) {
4897 return str;
4898 }
4899 str = leftPad(str, strLen + pads / 2, padStr);
4900 str = rightPad(str, size, padStr);
4901 return str;
4902 }
4903
4904 // Case conversion
4905 //-----------------------------------------------------------------------
4906 /**
4907 * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
4908 *
4909 * <p>A {@code null} input String returns {@code null}.</p>
4910 *
4911 * <pre>
4912 * StringUtils.upperCase(null) = null
4913 * StringUtils.upperCase("") = ""
4914 * StringUtils.upperCase("aBc") = "ABC"
4915 * </pre>
4916 *
4917 * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
4918 * the result of this method is affected by the current locale.
4919 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
4920 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
4921 *
4922 * @param str the String to upper case, may be null
4923 * @return the upper cased String, {@code null} if null String input
4924 */
4925 public static String upperCase(String str) {
4926 if (str == null) {
4927 return null;
4928 }
4929 return str.toUpperCase();
4930 }
4931
4932 /**
4933 * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
4934 *
4935 * <p>A {@code null} input String returns {@code null}.</p>
4936 *
4937 * <pre>
4938 * StringUtils.upperCase(null, Locale.ENGLISH) = null
4939 * StringUtils.upperCase("", Locale.ENGLISH) = ""
4940 * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
4941 * </pre>
4942 *
4943 * @param str the String to upper case, may be null
4944 * @param locale the locale that defines the case transformation rules, must not be null
4945 * @return the upper cased String, {@code null} if null String input
4946 * @since 2.5
4947 */
4948 public static String upperCase(String str, Locale locale) {
4949 if (str == null) {
4950 return null;
4951 }
4952 return str.toUpperCase(locale);
4953 }
4954
4955 /**
4956 * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
4957 *
4958 * <p>A {@code null} input String returns {@code null}.</p>
4959 *
4960 * <pre>
4961 * StringUtils.lowerCase(null) = null
4962 * StringUtils.lowerCase("") = ""
4963 * StringUtils.lowerCase("aBc") = "abc"
4964 * </pre>
4965 *
4966 * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
4967 * the result of this method is affected by the current locale.
4968 * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
4969 * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
4970 *
4971 * @param str the String to lower case, may be null
4972 * @return the lower cased String, {@code null} if null String input
4973 */
4974 public static String lowerCase(String str) {
4975 if (str == null) {
4976 return null;
4977 }
4978 return str.toLowerCase();
4979 }
4980
4981 /**
4982 * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
4983 *
4984 * <p>A {@code null} input String returns {@code null}.</p>
4985 *
4986 * <pre>
4987 * StringUtils.lowerCase(null, Locale.ENGLISH) = null
4988 * StringUtils.lowerCase("", Locale.ENGLISH) = ""
4989 * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
4990 * </pre>
4991 *
4992 * @param str the String to lower case, may be null
4993 * @param locale the locale that defines the case transformation rules, must not be null
4994 * @return the lower cased String, {@code null} if null String input
4995 * @since 2.5
4996 */
4997 public static String lowerCase(String str, Locale locale) {
4998 if (str == null) {
4999 return null;
5000 }
5001 return str.toLowerCase(locale);
5002 }
5003
5004 /**
5005 * <p>Capitalizes a String changing the first letter to title case as
5006 * per {@link Character#toTitleCase(char)}. No other letters are changed.</p>
5007 *
5008 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
5009 * A {@code null} input String returns {@code null}.</p>
5010 *
5011 * <pre>
5012 * StringUtils.capitalize(null) = null
5013 * StringUtils.capitalize("") = ""
5014 * StringUtils.capitalize("cat") = "Cat"
5015 * StringUtils.capitalize("cAt") = "CAt"
5016 * </pre>
5017 *
5018 * @param str the String to capitalize, may be null
5019 * @return the capitalized String, {@code null} if null String input
5020 * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
5021 * @see #uncapitalize(String)
5022 * @since 2.0
5023 */
5024 public static String capitalize(String str) {
5025 int strLen;
5026 if (str == null || (strLen = str.length()) == 0) {
5027 return str;
5028 }
5029 return new StringBuilder(strLen)
5030 .append(Character.toTitleCase(str.charAt(0)))
5031 .append(str.substring(1))
5032 .toString();
5033 }
5034
5035 /**
5036 * <p>Uncapitalizes a String changing the first letter to title case as
5037 * per {@link Character#toLowerCase(char)}. No other letters are changed.</p>
5038 *
5039 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
5040 * A {@code null} input String returns {@code null}.</p>
5041 *
5042 * <pre>
5043 * StringUtils.uncapitalize(null) = null
5044 * StringUtils.uncapitalize("") = ""
5045 * StringUtils.uncapitalize("Cat") = "cat"
5046 * StringUtils.uncapitalize("CAT") = "cAT"
5047 * </pre>
5048 *
5049 * @param str the String to uncapitalize, may be null
5050 * @return the uncapitalized String, {@code null} if null String input
5051 * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
5052 * @see #capitalize(String)
5053 * @since 2.0
5054 */
5055 public static String uncapitalize(String str) {
5056 int strLen;
5057 if (str == null || (strLen = str.length()) == 0) {
5058 return str;
5059 }
5060 return new StringBuilder(strLen)
5061 .append(Character.toLowerCase(str.charAt(0)))
5062 .append(str.substring(1))
5063 .toString();
5064 }
5065
5066 /**
5067 * <p>Swaps the case of a String changing upper and title case to
5068 * lower case, and lower case to upper case.</p>
5069 *
5070 * <ul>
5071 * <li>Upper case character converts to Lower case</li>
5072 * <li>Title case character converts to Lower case</li>
5073 * <li>Lower case character converts to Upper case</li>
5074 * </ul>
5075 *
5076 * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
5077 * A {@code null} input String returns {@code null}.</p>
5078 *
5079 * <pre>
5080 * StringUtils.swapCase(null) = null
5081 * StringUtils.swapCase("") = ""
5082 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
5083 * </pre>
5084 *
5085 * <p>NOTE: This method changed in Lang version 2.0.
5086 * It no longer performs a word based algorithm.
5087 * If you only use ASCII, you will notice no change.
5088 * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
5089 *
5090 * @param str the String to swap case, may be null
5091 * @return the changed String, {@code null} if null String input
5092 */
5093 public static String swapCase(String str) {
5094 if (StringUtils.isEmpty(str)) {
5095 return str;
5096 }
5097
5098 char[] buffer = str.toCharArray();
5099
5100 for (int i = 0; i < buffer.length; i++) {
5101 char ch = buffer[i];
5102 if (Character.isUpperCase(ch)) {
5103 buffer[i] = Character.toLowerCase(ch);
5104 } else if (Character.isTitleCase(ch)) {
5105 buffer[i] = Character.toLowerCase(ch);
5106 } else if (Character.isLowerCase(ch)) {
5107 buffer[i] = Character.toUpperCase(ch);
5108 }
5109 }
5110 return new String(buffer);
5111 }
5112
5113 // Count matches
5114 //-----------------------------------------------------------------------
5115 /**
5116 * <p>Counts how many times the substring appears in the larger string.</p>
5117 *
5118 * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
5119 *
5120 * <pre>
5121 * StringUtils.countMatches(null, *) = 0
5122 * StringUtils.countMatches("", *) = 0
5123 * StringUtils.countMatches("abba", null) = 0
5124 * StringUtils.countMatches("abba", "") = 0
5125 * StringUtils.countMatches("abba", "a") = 2
5126 * StringUtils.countMatches("abba", "ab") = 1
5127 * StringUtils.countMatches("abba", "xxx") = 0
5128 * </pre>
5129 *
5130 * @param str the CharSequence to check, may be null
5131 * @param sub the substring to count, may be null
5132 * @return the number of occurrences, 0 if either CharSequence is {@code null}
5133 * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
5134 */
5135 public static int countMatches(CharSequence str, CharSequence sub) {
5136 if (isEmpty(str) || isEmpty(sub)) {
5137 return 0;
5138 }
5139 int count = 0;
5140 int idx = 0;
5141 while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
5142 count++;
5143 idx += sub.length();
5144 }
5145 return count;
5146 }
5147
5148 // Character Tests
5149 //-----------------------------------------------------------------------
5150 /**
5151 * <p>Checks if the CharSequence contains only Unicode letters.</p>
5152 *
5153 * <p>{@code null} will return {@code false}.
5154 * An empty CharSequence (length()=0) will return {@code false}.</p>
5155 *
5156 * <pre>
5157 * StringUtils.isAlpha(null) = false
5158 * StringUtils.isAlpha("") = false
5159 * StringUtils.isAlpha(" ") = false
5160 * StringUtils.isAlpha("abc") = true
5161 * StringUtils.isAlpha("ab2c") = false
5162 * StringUtils.isAlpha("ab-c") = false
5163 * </pre>
5164 *
5165 * @param cs the CharSequence to check, may be null
5166 * @return {@code true} if only contains letters, and is non-null
5167 * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
5168 * @since 3.0 Changed "" to return false and not true
5169 */
5170 public static boolean isAlpha(CharSequence cs) {
5171 if (cs == null || cs.length() == 0) {
5172 return false;
5173 }
5174 int sz = cs.length();
5175 for (int i = 0; i < sz; i++) {
5176 if (Character.isLetter(cs.charAt(i)) == false) {
5177 return false;
5178 }
5179 }
5180 return true;
5181 }
5182
5183 /**
5184 * <p>Checks if the CharSequence contains only Unicode letters and
5185 * space (' ').</p>
5186 *
5187 * <p>{@code null} will return {@code false}
5188 * An empty CharSequence (length()=0) will return {@code true}.</p>
5189 *
5190 * <pre>
5191 * StringUtils.isAlphaSpace(null) = false
5192 * StringUtils.isAlphaSpace("") = true
5193 * StringUtils.isAlphaSpace(" ") = true
5194 * StringUtils.isAlphaSpace("abc") = true
5195 * StringUtils.isAlphaSpace("ab c") = true
5196 * StringUtils.isAlphaSpace("ab2c") = false
5197 * StringUtils.isAlphaSpace("ab-c") = false
5198 * </pre>
5199 *
5200 * @param cs the CharSequence to check, may be null
5201 * @return {@code true} if only contains letters and space,
5202 * and is non-null
5203 * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
5204 */
5205 public static boolean isAlphaSpace(CharSequence cs) {
5206 if (cs == null) {
5207 return false;
5208 }
5209 int sz = cs.length();
5210 for (int i = 0; i < sz; i++) {
5211 if ((Character.isLetter(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
5212 return false;
5213 }
5214 }
5215 return true;
5216 }
5217
5218 /**
5219 * <p>Checks if the CharSequence contains only Unicode letters or digits.</p>
5220 *
5221 * <p>{@code null} will return {@code false}.
5222 * An empty CharSequence (length()=0) will return {@code false}.</p>
5223 *
5224 * <pre>
5225 * StringUtils.isAlphanumeric(null) = false
5226 * StringUtils.isAlphanumeric("") = false
5227 * StringUtils.isAlphanumeric(" ") = false
5228 * StringUtils.isAlphanumeric("abc") = true
5229 * StringUtils.isAlphanumeric("ab c") = false
5230 * StringUtils.isAlphanumeric("ab2c") = true
5231 * StringUtils.isAlphanumeric("ab-c") = false
5232 * </pre>
5233 *
5234 * @param cs the CharSequence to check, may be null
5235 * @return {@code true} if only contains letters or digits,
5236 * and is non-null
5237 * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
5238 * @since 3.0 Changed "" to return false and not true
5239 */
5240 public static boolean isAlphanumeric(CharSequence cs) {
5241 if (cs == null || cs.length() == 0) {
5242 return false;
5243 }
5244 int sz = cs.length();
5245 for (int i = 0; i < sz; i++) {
5246 if (Character.isLetterOrDigit(cs.charAt(i)) == false) {
5247 return false;
5248 }
5249 }
5250 return true;
5251 }
5252
5253 /**
5254 * <p>Checks if the CharSequence contains only Unicode letters, digits
5255 * or space ({@code ' '}).</p>
5256 *
5257 * <p>{@code null} will return {@code false}.
5258 * An empty CharSequence (length()=0) will return {@code true}.</p>
5259 *
5260 * <pre>
5261 * StringUtils.isAlphanumericSpace(null) = false
5262 * StringUtils.isAlphanumericSpace("") = true
5263 * StringUtils.isAlphanumericSpace(" ") = true
5264 * StringUtils.isAlphanumericSpace("abc") = true
5265 * StringUtils.isAlphanumericSpace("ab c") = true
5266 * StringUtils.isAlphanumericSpace("ab2c") = true
5267 * StringUtils.isAlphanumericSpace("ab-c") = false
5268 * </pre>
5269 *
5270 * @param cs the CharSequence to check, may be null
5271 * @return {@code true} if only contains letters, digits or space,
5272 * and is non-null
5273 * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
5274 */
5275 public static boolean isAlphanumericSpace(CharSequence cs) {
5276 if (cs == null) {
5277 return false;
5278 }
5279 int sz = cs.length();
5280 for (int i = 0; i < sz; i++) {
5281 if ((Character.isLetterOrDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
5282 return false;
5283 }
5284 }
5285 return true;
5286 }
5287
5288 /**
5289 * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
5290 *
5291 * <p>{@code null} will return {@code false}.
5292 * An empty CharSequence (length()=0) will return {@code true}.</p>
5293 *
5294 * <pre>
5295 * StringUtils.isAsciiPrintable(null) = false
5296 * StringUtils.isAsciiPrintable("") = true
5297 * StringUtils.isAsciiPrintable(" ") = true
5298 * StringUtils.isAsciiPrintable("Ceki") = true
5299 * StringUtils.isAsciiPrintable("ab2c") = true
5300 * StringUtils.isAsciiPrintable("!ab-c~") = true
5301 * StringUtils.isAsciiPrintable("\u0020") = true
5302 * StringUtils.isAsciiPrintable("\u0021") = true
5303 * StringUtils.isAsciiPrintable("\u007e") = true
5304 * StringUtils.isAsciiPrintable("\u007f") = false
5305 * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
5306 * </pre>
5307 *
5308 * @param cs the CharSequence to check, may be null
5309 * @return {@code true} if every character is in the range
5310 * 32 thru 126
5311 * @since 2.1
5312 * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
5313 */
5314 public static boolean isAsciiPrintable(CharSequence cs) {
5315 if (cs == null) {
5316 return false;
5317 }
5318 int sz = cs.length();
5319 for (int i = 0; i < sz; i++) {
5320 if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) {
5321 return false;
5322 }
5323 }
5324 return true;
5325 }
5326
5327 /**
5328 * <p>Checks if the CharSequence contains only Unicode digits.
5329 * A decimal point is not a Unicode digit and returns false.</p>
5330 *
5331 * <p>{@code null} will return {@code false}.
5332 * An empty CharSequence (length()=0) will return {@code false}.</p>
5333 *
5334 * <pre>
5335 * StringUtils.isNumeric(null) = false
5336 * StringUtils.isNumeric("") = false
5337 * StringUtils.isNumeric(" ") = false
5338 * StringUtils.isNumeric("123") = true
5339 * StringUtils.isNumeric("12 3") = false
5340 * StringUtils.isNumeric("ab2c") = false
5341 * StringUtils.isNumeric("12-3") = false
5342 * StringUtils.isNumeric("12.3") = false
5343 * </pre>
5344 *
5345 * @param cs the CharSequence to check, may be null
5346 * @return {@code true} if only contains digits, and is non-null
5347 * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
5348 * @since 3.0 Changed "" to return false and not true
5349 */
5350 public static boolean isNumeric(CharSequence cs) {
5351 if (cs == null || cs.length() == 0) {
5352 return false;
5353 }
5354 int sz = cs.length();
5355 for (int i = 0; i < sz; i++) {
5356 if (Character.isDigit(cs.charAt(i)) == false) {
5357 return false;
5358 }
5359 }
5360 return true;
5361 }
5362
5363 /**
5364 * <p>Checks if the CharSequence contains only Unicode digits or space
5365 * ({@code ' '}).
5366 * A decimal point is not a Unicode digit and returns false.</p>
5367 *
5368 * <p>{@code null} will return {@code false}.
5369 * An empty CharSequence (length()=0) will return {@code true}.</p>
5370 *
5371 * <pre>
5372 * StringUtils.isNumericSpace(null) = false
5373 * StringUtils.isNumericSpace("") = true
5374 * StringUtils.isNumericSpace(" ") = true
5375 * StringUtils.isNumericSpace("123") = true
5376 * StringUtils.isNumericSpace("12 3") = true
5377 * StringUtils.isNumericSpace("ab2c") = false
5378 * StringUtils.isNumericSpace("12-3") = false
5379 * StringUtils.isNumericSpace("12.3") = false
5380 * </pre>
5381 *
5382 * @param cs the CharSequence to check, may be null
5383 * @return {@code true} if only contains digits or space,
5384 * and is non-null
5385 * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
5386 */
5387 public static boolean isNumericSpace(CharSequence cs) {
5388 if (cs == null) {
5389 return false;
5390 }
5391 int sz = cs.length();
5392 for (int i = 0; i < sz; i++) {
5393 if ((Character.isDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
5394 return false;
5395 }
5396 }
5397 return true;
5398 }
5399
5400 /**
5401 * <p>Checks if the CharSequence contains only whitespace.</p>
5402 *
5403 * <p>{@code null} will return {@code false}.
5404 * An empty CharSequence (length()=0) will return {@code true}.</p>
5405 *
5406 * <pre>
5407 * StringUtils.isWhitespace(null) = false
5408 * StringUtils.isWhitespace("") = true
5409 * StringUtils.isWhitespace(" ") = true
5410 * StringUtils.isWhitespace("abc") = false
5411 * StringUtils.isWhitespace("ab2c") = false
5412 * StringUtils.isWhitespace("ab-c") = false
5413 * </pre>
5414 *
5415 * @param cs the CharSequence to check, may be null
5416 * @return {@code true} if only contains whitespace, and is non-null
5417 * @since 2.0
5418 * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
5419 */
5420 public static boolean isWhitespace(CharSequence cs) {
5421 if (cs == null) {
5422 return false;
5423 }
5424 int sz = cs.length();
5425 for (int i = 0; i < sz; i++) {
5426 if ((Character.isWhitespace(cs.charAt(i)) == false)) {
5427 return false;
5428 }
5429 }
5430 return true;
5431 }
5432
5433 /**
5434 * <p>Checks if the CharSequence contains only lowercase characters.</p>
5435 *
5436 * <p>{@code null} will return {@code false}.
5437 * An empty CharSequence (length()=0) will return {@code false}.</p>
5438 *
5439 * <pre>
5440 * StringUtils.isAllLowerCase(null) = false
5441 * StringUtils.isAllLowerCase("") = false
5442 * StringUtils.isAllLowerCase(" ") = false
5443 * StringUtils.isAllLowerCase("abc") = true
5444 * StringUtils.isAllLowerCase("abC") = false
5445 * </pre>
5446 *
5447 * @param cs the CharSequence to check, may be null
5448 * @return {@code true} if only contains lowercase characters, and is non-null
5449 * @since 2.5
5450 * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
5451 */
5452 public static boolean isAllLowerCase(CharSequence cs) {
5453 if (cs == null || isEmpty(cs)) {
5454 return false;
5455 }
5456 int sz = cs.length();
5457 for (int i = 0; i < sz; i++) {
5458 if (Character.isLowerCase(cs.charAt(i)) == false) {
5459 return false;
5460 }
5461 }
5462 return true;
5463 }
5464
5465 /**
5466 * <p>Checks if the CharSequence contains only uppercase characters.</p>
5467 *
5468 * <p>{@code null} will return {@code false}.
5469 * An empty String (length()=0) will return {@code false}.</p>
5470 *
5471 * <pre>
5472 * StringUtils.isAllUpperCase(null) = false
5473 * StringUtils.isAllUpperCase("") = false
5474 * StringUtils.isAllUpperCase(" ") = false
5475 * StringUtils.isAllUpperCase("ABC") = true
5476 * StringUtils.isAllUpperCase("aBC") = false
5477 * </pre>
5478 *
5479 * @param cs the CharSequence to check, may be null
5480 * @return {@code true} if only contains uppercase characters, and is non-null
5481 * @since 2.5
5482 * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
5483 */
5484 public static boolean isAllUpperCase(CharSequence cs) {
5485 if (cs == null || isEmpty(cs)) {
5486 return false;
5487 }
5488 int sz = cs.length();
5489 for (int i = 0; i < sz; i++) {
5490 if (Character.isUpperCase(cs.charAt(i)) == false) {
5491 return false;
5492 }
5493 }
5494 return true;
5495 }
5496
5497 // Defaults
5498 //-----------------------------------------------------------------------
5499 /**
5500 * <p>Returns either the passed in String,
5501 * or if the String is {@code null}, an empty String ("").</p>
5502 *
5503 * <pre>
5504 * StringUtils.defaultString(null) = ""
5505 * StringUtils.defaultString("") = ""
5506 * StringUtils.defaultString("bat") = "bat"
5507 * </pre>
5508 *
5509 * @see ObjectUtils#toString(Object)
5510 * @see String#valueOf(Object)
5511 * @param str the String to check, may be null
5512 * @return the passed in String, or the empty String if it
5513 * was {@code null}
5514 */
5515 public static String defaultString(String str) {
5516 return str == null ? EMPTY : str;
5517 }
5518
5519 /**
5520 * <p>Returns either the passed in String, or if the String is
5521 * {@code null}, the value of {@code defaultStr}.</p>
5522 *
5523 * <pre>
5524 * StringUtils.defaultString(null, "NULL") = "NULL"
5525 * StringUtils.defaultString("", "NULL") = ""
5526 * StringUtils.defaultString("bat", "NULL") = "bat"
5527 * </pre>
5528 *
5529 * @see ObjectUtils#toString(Object,String)
5530 * @see String#valueOf(Object)
5531 * @param str the String to check, may be null
5532 * @param defaultStr the default String to return
5533 * if the input is {@code null}, may be null
5534 * @return the passed in String, or the default if it was {@code null}
5535 */
5536 public static String defaultString(String str, String defaultStr) {
5537 return str == null ? defaultStr : str;
5538 }
5539
5540 /**
5541 * <p>Returns either the passed in CharSequence, or if the CharSequence is
5542 * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p>
5543 *
5544 * <pre>
5545 * StringUtils.defaultIfBlank(null, "NULL") = "NULL"
5546 * StringUtils.defaultIfBlank("", "NULL") = "NULL"
5547 * StringUtils.defaultIfBlank(" ", "NULL") = "NULL"
5548 * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
5549 * StringUtils.defaultIfBlank("", null) = null
5550 * </pre>
5551 * @param <T> the specific kind of CharSequence
5552 * @param str the CharSequence to check, may be null
5553 * @param defaultStr the default CharSequence to return
5554 * if the input is whitespace, empty ("") or {@code null}, may be null
5555 * @return the passed in CharSequence, or the default
5556 * @see StringUtils#defaultString(String, String)
5557 */
5558 public static <T extends CharSequence> T defaultIfBlank(T str, T defaultStr) {
5559 return StringUtils.isBlank(str) ? defaultStr : str;
5560 }
5561
5562 /**
5563 * <p>Returns either the passed in CharSequence, or if the CharSequence is
5564 * empty or {@code null}, the value of {@code defaultStr}.</p>
5565 *
5566 * <pre>
5567 * StringUtils.defaultIfEmpty(null, "NULL") = "NULL"
5568 * StringUtils.defaultIfEmpty("", "NULL") = "NULL"
5569 * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
5570 * StringUtils.defaultIfEmpty("", null) = null
5571 * </pre>
5572 * @param <T> the specific kind of CharSequence
5573 * @param str the CharSequence to check, may be null
5574 * @param defaultStr the default CharSequence to return
5575 * if the input is empty ("") or {@code null}, may be null
5576 * @return the passed in CharSequence, or the default
5577 * @see StringUtils#defaultString(String, String)
5578 */
5579 public static <T extends CharSequence> T defaultIfEmpty(T str, T defaultStr) {
5580 return StringUtils.isEmpty(str) ? defaultStr : str;
5581 }
5582
5583 // Reversing
5584 //-----------------------------------------------------------------------
5585 /**
5586 * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
5587 *
5588 * <p>A {@code null} String returns {@code null}.</p>
5589 *
5590 * <pre>
5591 * StringUtils.reverse(null) = null
5592 * StringUtils.reverse("") = ""
5593 * StringUtils.reverse("bat") = "tab"
5594 * </pre>
5595 *
5596 * @param str the String to reverse, may be null
5597 * @return the reversed String, {@code null} if null String input
5598 */
5599 public static String reverse(String str) {
5600 if (str == null) {
5601 return null;
5602 }
5603 return new StringBuilder(str).reverse().toString();
5604 }
5605
5606 /**
5607 * <p>Reverses a String that is delimited by a specific character.</p>
5608 *
5609 * <p>The Strings between the delimiters are not reversed.
5610 * Thus java.lang.String becomes String.lang.java (if the delimiter
5611 * is {@code '.'}).</p>
5612 *
5613 * <pre>
5614 * StringUtils.reverseDelimited(null, *) = null
5615 * StringUtils.reverseDelimited("", *) = ""
5616 * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
5617 * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
5618 * </pre>
5619 *
5620 * @param str the String to reverse, may be null
5621 * @param separatorChar the separator character to use
5622 * @return the reversed String, {@code null} if null String input
5623 * @since 2.0
5624 */
5625 public static String reverseDelimited(String str, char separatorChar) {
5626 if (str == null) {
5627 return null;
5628 }
5629 // could implement manually, but simple way is to reuse other,
5630 // probably slower, methods.
5631 String[] strs = split(str, separatorChar);
5632 ArrayUtils.reverse(strs);
5633 return join(strs, separatorChar);
5634 }
5635
5636 // Abbreviating
5637 //-----------------------------------------------------------------------
5638 /**
5639 * <p>Abbreviates a String using ellipses. This will turn
5640 * "Now is the time for all good men" into "Now is the time for..."</p>
5641 *
5642 * <p>Specifically:
5643 * <ul>
5644 * <li>If {@code str} is less than {@code maxWidth} characters
5645 * long, return it.</li>
5646 * <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
5647 * <li>If {@code maxWidth} is less than {@code 4}, throw an
5648 * {@code IllegalArgumentException}.</li>
5649 * <li>In no case will it return a String of length greater than
5650 * {@code maxWidth}.</li>
5651 * </ul>
5652 * </p>
5653 *
5654 * <pre>
5655 * StringUtils.abbreviate(null, *) = null
5656 * StringUtils.abbreviate("", 4) = ""
5657 * StringUtils.abbreviate("abcdefg", 6) = "abc..."
5658 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
5659 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
5660 * StringUtils.abbreviate("abcdefg", 4) = "a..."
5661 * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
5662 * </pre>
5663 *
5664 * @param str the String to check, may be null
5665 * @param maxWidth maximum length of result String, must be at least 4
5666 * @return abbreviated String, {@code null} if null String input
5667 * @throws IllegalArgumentException if the width is too small
5668 * @since 2.0
5669 */
5670 public static String abbreviate(String str, int maxWidth) {
5671 return abbreviate(str, 0, maxWidth);
5672 }
5673
5674 /**
5675 * <p>Abbreviates a String using ellipses. This will turn
5676 * "Now is the time for all good men" into "...is the time for..."</p>
5677 *
5678 * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
5679 * a "left edge" offset. Note that this left edge is not necessarily going to
5680 * be the leftmost character in the result, or the first character following the
5681 * ellipses, but it will appear somewhere in the result.
5682 *
5683 * <p>In no case will it return a String of length greater than
5684 * {@code maxWidth}.</p>
5685 *
5686 * <pre>
5687 * StringUtils.abbreviate(null, *, *) = null
5688 * StringUtils.abbreviate("", 0, 4) = ""
5689 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
5690 * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..."
5691 * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..."
5692 * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..."
5693 * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..."
5694 * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..."
5695 * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno"
5696 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
5697 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
5698 * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException
5699 * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException
5700 * </pre>
5701 *
5702 * @param str the String to check, may be null
5703 * @param offset left edge of source String
5704 * @param maxWidth maximum length of result String, must be at least 4
5705 * @return abbreviated String, {@code null} if null String input
5706 * @throws IllegalArgumentException if the width is too small
5707 * @since 2.0
5708 */
5709 public static String abbreviate(String str, int offset, int maxWidth) {
5710 if (str == null) {
5711 return null;
5712 }
5713 if (maxWidth < 4) {
5714 throw new IllegalArgumentException("Minimum abbreviation width is 4");
5715 }
5716 if (str.length() <= maxWidth) {
5717 return str;
5718 }
5719 if (offset > str.length()) {
5720 offset = str.length();
5721 }
5722 if ((str.length() - offset) < (maxWidth - 3)) {
5723 offset = str.length() - (maxWidth - 3);
5724 }
5725 final String abrevMarker = "...";
5726 if (offset <= 4) {
5727 return str.substring(0, maxWidth - 3) + abrevMarker;
5728 }
5729 if (maxWidth < 7) {
5730 throw new IllegalArgumentException("Minimum abbreviation width with offset is 7");
5731 }
5732 if ((offset + (maxWidth - 3)) < str.length()) {
5733 return abrevMarker + abbreviate(str.substring(offset), maxWidth - 3);
5734 }
5735 return abrevMarker + str.substring(str.length() - (maxWidth - 3));
5736 }
5737
5738 /**
5739 * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
5740 * replacement String.</p>
5741 *
5742 * <p>This abbreviation only occurs if the following criteria is met:
5743 * <ul>
5744 * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
5745 * <li>The length to truncate to is less than the length of the supplied String</li>
5746 * <li>The length to truncate to is greater than 0</li>
5747 * <li>The abbreviated String will have enough room for the length supplied replacement String
5748 * and the first and last characters of the supplied String for abbreviation</li>
5749 * </ul>
5750 * Otherwise, the returned String will be the same as the supplied String for abbreviation.
5751 * </p>
5752 *
5753 * <pre>
5754 * StringUtils.abbreviateMiddle(null, null, 0) = null
5755 * StringUtils.abbreviateMiddle("abc", null, 0) = "abc"
5756 * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc"
5757 * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc"
5758 * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
5759 * </pre>
5760 *
5761 * @param str the String to abbreviate, may be null
5762 * @param middle the String to replace the middle characters with, may be null
5763 * @param length the length to abbreviate {@code str} to.
5764 * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
5765 * @since 2.5
5766 */
5767 public static String abbreviateMiddle(String str, String middle, int length) {
5768 if (isEmpty(str) || isEmpty(middle)) {
5769 return str;
5770 }
5771
5772 if (length >= str.length() || length < (middle.length()+2)) {
5773 return str;
5774 }
5775
5776 int targetSting = length-middle.length();
5777 int startOffset = targetSting/2+targetSting%2;
5778 int endOffset = str.length()-targetSting/2;
5779
5780 StringBuilder builder = new StringBuilder(length);
5781 builder.append(str.substring(0,startOffset));
5782 builder.append(middle);
5783 builder.append(str.substring(endOffset));
5784
5785 return builder.toString();
5786 }
5787
5788 // Difference
5789 //-----------------------------------------------------------------------
5790 /**
5791 * <p>Compares two Strings, and returns the portion where they differ.
5792 * (More precisely, return the remainder of the second String,
5793 * starting from where it's different from the first.)</p>
5794 *
5795 * <p>For example,
5796 * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
5797 *
5798 * <pre>
5799 * StringUtils.difference(null, null) = null
5800 * StringUtils.difference("", "") = ""
5801 * StringUtils.difference("", "abc") = "abc"
5802 * StringUtils.difference("abc", "") = ""
5803 * StringUtils.difference("abc", "abc") = ""
5804 * StringUtils.difference("ab", "abxyz") = "xyz"
5805 * StringUtils.difference("abcde", "abxyz") = "xyz"
5806 * StringUtils.difference("abcde", "xyz") = "xyz"
5807 * </pre>
5808 *
5809 * @param str1 the first String, may be null
5810 * @param str2 the second String, may be null
5811 * @return the portion of str2 where it differs from str1; returns the
5812 * empty String if they are equal
5813 * @since 2.0
5814 */
5815 public static String difference(String str1, String str2) {
5816 if (str1 == null) {
5817 return str2;
5818 }
5819 if (str2 == null) {
5820 return str1;
5821 }
5822 int at = indexOfDifference(str1, str2);
5823 if (at == INDEX_NOT_FOUND) {
5824 return EMPTY;
5825 }
5826 return str2.substring(at);
5827 }
5828
5829 /**
5830 * <p>Compares two CharSequences, and returns the index at which the
5831 * CharSequences begin to differ.</p>
5832 *
5833 * <p>For example,
5834 * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
5835 *
5836 * <pre>
5837 * StringUtils.indexOfDifference(null, null) = -1
5838 * StringUtils.indexOfDifference("", "") = -1
5839 * StringUtils.indexOfDifference("", "abc") = 0
5840 * StringUtils.indexOfDifference("abc", "") = 0
5841 * StringUtils.indexOfDifference("abc", "abc") = -1
5842 * StringUtils.indexOfDifference("ab", "abxyz") = 2
5843 * StringUtils.indexOfDifference("abcde", "abxyz") = 2
5844 * StringUtils.indexOfDifference("abcde", "xyz") = 0
5845 * </pre>
5846 *
5847 * @param cs1 the first CharSequence, may be null
5848 * @param cs2 the second CharSequence, may be null
5849 * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
5850 * @since 2.0
5851 * @since 3.0 Changed signature from indexOfDifference(String, String) to
5852 * indexOfDifference(CharSequence, CharSequence)
5853 */
5854 public static int indexOfDifference(CharSequence cs1, CharSequence cs2) {
5855 if (cs1 == cs2) {
5856 return INDEX_NOT_FOUND;
5857 }
5858 if (cs1 == null || cs2 == null) {
5859 return 0;
5860 }
5861 int i;
5862 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
5863 if (cs1.charAt(i) != cs2.charAt(i)) {
5864 break;
5865 }
5866 }
5867 if (i < cs2.length() || i < cs1.length()) {
5868 return i;
5869 }
5870 return INDEX_NOT_FOUND;
5871 }
5872
5873 /**
5874 * <p>Compares all CharSequences in an array and returns the index at which the
5875 * CharSequences begin to differ.</p>
5876 *
5877 * <p>For example,
5878 * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7</code></p>
5879 *
5880 * <pre>
5881 * StringUtils.indexOfDifference(null) = -1
5882 * StringUtils.indexOfDifference(new String[] {}) = -1
5883 * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
5884 * StringUtils.indexOfDifference(new String[] {null, null}) = -1
5885 * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
5886 * StringUtils.indexOfDifference(new String[] {"", null}) = 0
5887 * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
5888 * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
5889 * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
5890 * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
5891 * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
5892 * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
5893 * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
5894 * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
5895 * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
5896 * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
5897 * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
5898 * </pre>
5899 *
5900 * @param css array of CharSequences, entries may be null
5901 * @return the index where the strings begin to differ; -1 if they are all equal
5902 * @since 2.4
5903 * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
5904 */
5905 public static int indexOfDifference(CharSequence... css) {
5906 if (css == null || css.length <= 1) {
5907 return INDEX_NOT_FOUND;
5908 }
5909 boolean anyStringNull = false;
5910 boolean allStringsNull = true;
5911 int arrayLen = css.length;
5912 int shortestStrLen = Integer.MAX_VALUE;
5913 int longestStrLen = 0;
5914
5915 // find the min and max string lengths; this avoids checking to make
5916 // sure we are not exceeding the length of the string each time through
5917 // the bottom loop.
5918 for (int i = 0; i < arrayLen; i++) {
5919 if (css[i] == null) {
5920 anyStringNull = true;
5921 shortestStrLen = 0;
5922 } else {
5923 allStringsNull = false;
5924 shortestStrLen = Math.min(css[i].length(), shortestStrLen);
5925 longestStrLen = Math.max(css[i].length(), longestStrLen);
5926 }
5927 }
5928
5929 // handle lists containing all nulls or all empty strings
5930 if (allStringsNull || (longestStrLen == 0 && !anyStringNull)) {
5931 return INDEX_NOT_FOUND;
5932 }
5933
5934 // handle lists containing some nulls or some empty strings
5935 if (shortestStrLen == 0) {
5936 return 0;
5937 }
5938
5939 // find the position with the first difference across all strings
5940 int firstDiff = -1;
5941 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
5942 char comparisonChar = css[0].charAt(stringPos);
5943 for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
5944 if (css[arrayPos].charAt(stringPos) != comparisonChar) {
5945 firstDiff = stringPos;
5946 break;
5947 }
5948 }
5949 if (firstDiff != -1) {
5950 break;
5951 }
5952 }
5953
5954 if (firstDiff == -1 && shortestStrLen != longestStrLen) {
5955 // we compared all of the characters up to the length of the
5956 // shortest string and didn't find a match, but the string lengths
5957 // vary, so return the length of the shortest string.
5958 return shortestStrLen;
5959 }
5960 return firstDiff;
5961 }
5962
5963 /**
5964 * <p>Compares all Strings in an array and returns the initial sequence of
5965 * characters that is common to all of them.</p>
5966 *
5967 * <p>For example,
5968 * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "</code></p>
5969 *
5970 * <pre>
5971 * StringUtils.getCommonPrefix(null) = ""
5972 * StringUtils.getCommonPrefix(new String[] {}) = ""
5973 * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
5974 * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
5975 * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
5976 * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
5977 * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
5978 * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
5979 * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
5980 * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
5981 * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
5982 * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
5983 * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
5984 * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
5985 * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
5986 * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
5987 * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
5988 * </pre>
5989 *
5990 * @param strs array of String objects, entries may be null
5991 * @return the initial sequence of characters that are common to all Strings
5992 * in the array; empty String if the array is null, the elements are all null
5993 * or if there is no common prefix.
5994 * @since 2.4
5995 */
5996 public static String getCommonPrefix(String... strs) {
5997 if (strs == null || strs.length == 0) {
5998 return EMPTY;
5999 }
6000 int smallestIndexOfDiff = indexOfDifference(strs);
6001 if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
6002 // all strings were identical
6003 if (strs[0] == null) {
6004 return EMPTY;
6005 }
6006 return strs[0];
6007 } else if (smallestIndexOfDiff == 0) {
6008 // there were no common initial characters
6009 return EMPTY;
6010 } else {
6011 // we found a common initial character sequence
6012 return strs[0].substring(0, smallestIndexOfDiff);
6013 }
6014 }
6015
6016 // Misc
6017 //-----------------------------------------------------------------------
6018 /**
6019 * <p>Find the Levenshtein distance between two Strings.</p>
6020 *
6021 * <p>This is the number of changes needed to change one String into
6022 * another, where each change is a single character modification (deletion,
6023 * insertion or substitution).</p>
6024 *
6025 * <p>The previous implementation of the Levenshtein distance algorithm
6026 * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
6027 *
6028 * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
6029 * which can occur when my Java implementation is used with very large strings.<br>
6030 * This implementation of the Levenshtein distance algorithm
6031 * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
6032 *
6033 * <pre>
6034 * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException
6035 * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException
6036 * StringUtils.getLevenshteinDistance("","") = 0
6037 * StringUtils.getLevenshteinDistance("","a") = 1
6038 * StringUtils.getLevenshteinDistance("aaapppp", "") = 7
6039 * StringUtils.getLevenshteinDistance("frog", "fog") = 1
6040 * StringUtils.getLevenshteinDistance("fly", "ant") = 3
6041 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
6042 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
6043 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
6044 * StringUtils.getLevenshteinDistance("hello", "hallo") = 1
6045 * </pre>
6046 *
6047 * @param s the first String, must not be null
6048 * @param t the second String, must not be null
6049 * @return result distance
6050 * @throws IllegalArgumentException if either String input {@code null}
6051 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
6052 * getLevenshteinDistance(CharSequence, CharSequence)
6053 */
6054 public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
6055 if (s == null || t == null) {
6056 throw new IllegalArgumentException("Strings must not be null");
6057 }
6058
6059 /*
6060 The difference between this impl. and the previous is that, rather
6061 than creating and retaining a matrix of size s.length() + 1 by t.length() + 1,
6062 we maintain two single-dimensional arrays of length s.length() + 1. The first, d,
6063 is the 'current working' distance array that maintains the newest distance cost
6064 counts as we iterate through the characters of String s. Each time we increment
6065 the index of String t we are comparing, d is copied to p, the second int[]. Doing so
6066 allows us to retain the previous cost counts as required by the algorithm (taking
6067 the minimum of the cost count to the left, up one, and diagonally up and to the left
6068 of the current cost count being calculated). (Note that the arrays aren't really
6069 copied anymore, just switched...this is clearly much better than cloning an array
6070 or doing a System.arraycopy() each time through the outer loop.)
6071
6072 Effectively, the difference between the two implementations is this one does not
6073 cause an out of memory condition when calculating the LD over two very large strings.
6074 */
6075
6076 int n = s.length(); // length of s
6077 int m = t.length(); // length of t
6078
6079 if (n == 0) {
6080 return m;
6081 } else if (m == 0) {
6082 return n;
6083 }
6084
6085 if (n > m) {
6086 // swap the input strings to consume less memory
6087 CharSequence tmp = s;
6088 s = t;
6089 t = tmp;
6090 n = m;
6091 m = t.length();
6092 }
6093
6094 int p[] = new int[n + 1]; //'previous' cost array, horizontally
6095 int d[] = new int[n + 1]; // cost array, horizontally
6096 int _d[]; //placeholder to assist in swapping p and d
6097
6098 // indexes into strings s and t
6099 int i; // iterates through s
6100 int j; // iterates through t
6101
6102 char t_j; // jth character of t
6103
6104 int cost; // cost
6105
6106 for (i = 0; i <= n; i++) {
6107 p[i] = i;
6108 }
6109
6110 for (j = 1; j <= m; j++) {
6111 t_j = t.charAt(j - 1);
6112 d[0] = j;
6113
6114 for (i = 1; i <= n; i++) {
6115 cost = s.charAt(i - 1) == t_j ? 0 : 1;
6116 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
6117 d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
6118 }
6119
6120 // copy current distance counts to 'previous row' distance counts
6121 _d = p;
6122 p = d;
6123 d = _d;
6124 }
6125
6126 // our last action in the above loop was to switch d and p, so p now
6127 // actually has the most recent cost counts
6128 return p[n];
6129 }
6130
6131 /**
6132 * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
6133 * threshold.</p>
6134 *
6135 * <p>This is the number of changes needed to change one String into
6136 * another, where each change is a single character modification (deletion,
6137 * insertion or substitution).</p>
6138 *
6139 * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
6140 * and Chas Emerick's implementation of the Levenshtein distance algorithm from
6141 * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
6142 *
6143 * <pre>
6144 * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException
6145 * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException
6146 * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException
6147 * StringUtils.getLevenshteinDistance("","", 0) = 0
6148 * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7
6149 * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7
6150 * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1
6151 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
6152 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
6153 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
6154 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
6155 * </pre>
6156 *
6157 * @param s the first String, must not be null
6158 * @param t the second String, must not be null
6159 * @param threshold the target threshold, must not be negative
6160 * @return result distance, or {@code -1} if the distance would be greater than the threshold
6161 * @throws IllegalArgumentException if either String input {@code null} or negative threshold
6162 */
6163 public static int getLevenshteinDistance(CharSequence s, CharSequence t, int threshold) {
6164 if (s == null || t == null) {
6165 throw new IllegalArgumentException("Strings must not be null");
6166 }
6167 if (threshold < 0) {
6168 throw new IllegalArgumentException("Threshold must not be negative");
6169 }
6170
6171 /*
6172 This implementation only computes the distance if it's less than or equal to the
6173 threshold value, returning -1 if it's greater. The advantage is performance: unbounded
6174 distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
6175 computing a diagonal stripe of width 2k + 1 of the cost table.
6176 It is also possible to use this to compute the unbounded Levenshtein distance by starting
6177 the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
6178 d is the distance.
6179
6180 One subtlety comes from needing to ignore entries on the border of our stripe
6181 eg.
6182 p[] = |#|#|#|*
6183 d[] = *|#|#|#|
6184 We must ignore the entry to the left of the leftmost member
6185 We must ignore the entry above the rightmost member
6186
6187 Another subtlety comes from our stripe running off the matrix if the strings aren't
6188 of the same size. Since string s is always swapped to be the shorter of the two,
6189 the stripe will always run off to the upper right instead of the lower left of the matrix.
6190
6191 As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
6192 In this case we're going to walk a stripe of length 3. The matrix would look like so:
6193
6194 1 2 3 4 5
6195 1 |#|#| | | |
6196 2 |#|#|#| | |
6197 3 | |#|#|#| |
6198 4 | | |#|#|#|
6199 5 | | | |#|#|
6200 6 | | | | |#|
6201 7 | | | | | |
6202
6203 Note how the stripe leads off the table as there is no possible way to turn a string of length 5
6204 into one of length 7 in edit distance of 1.
6205
6206 Additionally, this implementation decreases memory usage by using two
6207 single-dimensional arrays and swapping them back and forth instead of allocating
6208 an entire n by m matrix. This requires a few minor changes, such as immediately returning
6209 when it's detected that the stripe has run off the matrix and initially filling the arrays with
6210 large values so that entries we don't compute are ignored.
6211
6212 See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
6213 */
6214
6215 int n = s.length(); // length of s
6216 int m = t.length(); // length of t
6217
6218 // if one string is empty, the edit distance is necessarily the length of the other
6219 if (n == 0) {
6220 return m <= threshold ? m : -1;
6221 } else if (m == 0) {
6222 return n <= threshold ? n : -1;
6223 }
6224
6225 if (n > m) {
6226 // swap the two strings to consume less memory
6227 CharSequence tmp = s;
6228 s = t;
6229 t = tmp;
6230 n = m;
6231 m = t.length();
6232 }
6233
6234 int p[] = new int[n + 1]; // 'previous' cost array, horizontally
6235 int d[] = new int[n + 1]; // cost array, horizontally
6236 int _d[]; // placeholder to assist in swapping p and d
6237
6238 // fill in starting table values
6239 int boundary = Math.min(n, threshold) + 1;
6240 for (int i = 0; i < boundary; i++) {
6241 p[i] = i;
6242 }
6243 // these fills ensure that the value above the rightmost entry of our
6244 // stripe will be ignored in following loop iterations
6245 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
6246 Arrays.fill(d, Integer.MAX_VALUE);
6247
6248 // iterates through t
6249 for (int j = 1; j <= m; j++) {
6250 char t_j = t.charAt(j - 1); // jth character of t
6251 d[0] = j;
6252
6253 // compute stripe indices, constrain to array size
6254 int min = Math.max(1, j - threshold);
6255 int max = Math.min(n, j + threshold);
6256
6257 // the stripe may lead off of the table if s and t are of different sizes
6258 if (min > max) {
6259 return -1;
6260 }
6261
6262 // ignore entry left of leftmost
6263 if (min > 1) {
6264 d[min - 1] = Integer.MAX_VALUE;
6265 }
6266
6267 // iterates through [min, max] in s
6268 for (int i = min; i <= max; i++) {
6269 if (s.charAt(i - 1) == t_j) {
6270 // diagonally left and up
6271 d[i] = p[i - 1];
6272 } else {
6273 // 1 + minimum of cell to the left, to the top, diagonally left and up
6274 d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
6275 }
6276 }
6277
6278 // copy current distance counts to 'previous row' distance counts
6279 _d = p;
6280 p = d;
6281 d = _d;
6282 }
6283
6284 // if p[n] is greater than the threshold, there's no guarantee on it being the correct
6285 // distance
6286 if (p[n] <= threshold) {
6287 return p[n];
6288 } else {
6289 return -1;
6290 }
6291 }
6292
6293 // startsWith
6294 //-----------------------------------------------------------------------
6295
6296 /**
6297 * <p>Check if a CharSequence starts with a specified prefix.</p>
6298 *
6299 * <p>{@code null}s are handled without exceptions. Two {@code null}
6300 * references are considered to be equal. The comparison is case sensitive.</p>
6301 *
6302 * <pre>
6303 * StringUtils.startsWith(null, null) = true
6304 * StringUtils.startsWith(null, "abc") = false
6305 * StringUtils.startsWith("abcdef", null) = false
6306 * StringUtils.startsWith("abcdef", "abc") = true
6307 * StringUtils.startsWith("ABCDEF", "abc") = false
6308 * </pre>
6309 *
6310 * @see java.lang.String#startsWith(String)
6311 * @param str the CharSequence to check, may be null
6312 * @param prefix the prefix to find, may be null
6313 * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
6314 * both {@code null}
6315 * @since 2.4
6316 * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
6317 */
6318 public static boolean startsWith(CharSequence str, CharSequence prefix) {
6319 return startsWith(str, prefix, false);
6320 }
6321
6322 /**
6323 * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
6324 *
6325 * <p>{@code null}s are handled without exceptions. Two {@code null}
6326 * references are considered to be equal. The comparison is case insensitive.</p>
6327 *
6328 * <pre>
6329 * StringUtils.startsWithIgnoreCase(null, null) = true
6330 * StringUtils.startsWithIgnoreCase(null, "abc") = false
6331 * StringUtils.startsWithIgnoreCase("abcdef", null) = false
6332 * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
6333 * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
6334 * </pre>
6335 *
6336 * @see java.lang.String#startsWith(String)
6337 * @param str the CharSequence to check, may be null
6338 * @param prefix the prefix to find, may be null
6339 * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
6340 * both {@code null}
6341 * @since 2.4
6342 * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
6343 */
6344 public static boolean startsWithIgnoreCase(CharSequence str, CharSequence prefix) {
6345 return startsWith(str, prefix, true);
6346 }
6347
6348 /**
6349 * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
6350 *
6351 * @see java.lang.String#startsWith(String)
6352 * @param str the CharSequence to check, may be null
6353 * @param prefix the prefix to find, may be null
6354 * @param ignoreCase indicates whether the compare should ignore case
6355 * (case insensitive) or not.
6356 * @return {@code true} if the CharSequence starts with the prefix or
6357 * both {@code null}
6358 */
6359 private static boolean startsWith(CharSequence str, CharSequence prefix, boolean ignoreCase) {
6360 if (str == null || prefix == null) {
6361 return (str == null && prefix == null);
6362 }
6363 if (prefix.length() > str.length()) {
6364 return false;
6365 }
6366 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
6367 }
6368
6369 /**
6370 * <p>Check if a CharSequence starts with any of an array of specified strings.</p>
6371 *
6372 * <pre>
6373 * StringUtils.startsWithAny(null, null) = false
6374 * StringUtils.startsWithAny(null, new String[] {"abc"}) = false
6375 * StringUtils.startsWithAny("abcxyz", null) = false
6376 * StringUtils.startsWithAny("abcxyz", new String[] {""}) = false
6377 * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
6378 * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
6379 * </pre>
6380 *
6381 * @param string the CharSequence to check, may be null
6382 * @param searchStrings the CharSequences to find, may be null or empty
6383 * @return {@code true} if the CharSequence starts with any of the the prefixes, case insensitive, or
6384 * both {@code null}
6385 * @since 2.5
6386 * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
6387 */
6388 public static boolean startsWithAny(CharSequence string, CharSequence... searchStrings) {
6389 if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
6390 return false;
6391 }
6392 for (CharSequence searchString : searchStrings) {
6393 if (StringUtils.startsWith(string, searchString)) {
6394 return true;
6395 }
6396 }
6397 return false;
6398 }
6399
6400 // endsWith
6401 //-----------------------------------------------------------------------
6402
6403 /**
6404 * <p>Check if a CharSequence ends with a specified suffix.</p>
6405 *
6406 * <p>{@code null}s are handled without exceptions. Two {@code null}
6407 * references are considered to be equal. The comparison is case sensitive.</p>
6408 *
6409 * <pre>
6410 * StringUtils.endsWith(null, null) = true
6411 * StringUtils.endsWith(null, "def") = false
6412 * StringUtils.endsWith("abcdef", null) = false
6413 * StringUtils.endsWith("abcdef", "def") = true
6414 * StringUtils.endsWith("ABCDEF", "def") = false
6415 * StringUtils.endsWith("ABCDEF", "cde") = false
6416 * </pre>
6417 *
6418 * @see java.lang.String#endsWith(String)
6419 * @param str the CharSequence to check, may be null
6420 * @param suffix the suffix to find, may be null
6421 * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
6422 * both {@code null}
6423 * @since 2.4
6424 * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
6425 */
6426 public static boolean endsWith(CharSequence str, CharSequence suffix) {
6427 return endsWith(str, suffix, false);
6428 }
6429
6430 /**
6431 * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p>
6432 *
6433 * <p>{@code null}s are handled without exceptions. Two {@code null}
6434 * references are considered to be equal. The comparison is case insensitive.</p>
6435 *
6436 * <pre>
6437 * StringUtils.endsWithIgnoreCase(null, null) = true
6438 * StringUtils.endsWithIgnoreCase(null, "def") = false
6439 * StringUtils.endsWithIgnoreCase("abcdef", null) = false
6440 * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
6441 * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
6442 * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
6443 * </pre>
6444 *
6445 * @see java.lang.String#endsWith(String)
6446 * @param str the CharSequence to check, may be null
6447 * @param suffix the suffix to find, may be null
6448 * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
6449 * both {@code null}
6450 * @since 2.4
6451 * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
6452 */
6453 public static boolean endsWithIgnoreCase(CharSequence str, CharSequence suffix) {
6454 return endsWith(str, suffix, true);
6455 }
6456
6457 /**
6458 * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p>
6459 *
6460 * @see java.lang.String#endsWith(String)
6461 * @param str the CharSequence to check, may be null
6462 * @param suffix the suffix to find, may be null
6463 * @param ignoreCase indicates whether the compare should ignore case
6464 * (case insensitive) or not.
6465 * @return {@code true} if the CharSequence starts with the prefix or
6466 * both {@code null}
6467 */
6468 private static boolean endsWith(CharSequence str, CharSequence suffix, boolean ignoreCase) {
6469 if (str == null || suffix == null) {
6470 return str == null && suffix == null;
6471 }
6472 if (suffix.length() > str.length()) {
6473 return false;
6474 }
6475 int strOffset = str.length() - suffix.length();
6476 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
6477 }
6478
6479 /**
6480 * <p>
6481 * Similar to <a
6482 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
6483 * -space</a>
6484 * </p>
6485 * <p>
6486 * The function returns the argument string with whitespace normalized by using
6487 * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace
6488 * and then replacing sequences of whitespace characters by a single space.
6489 * </p>
6490 * In XML Whitespace characters are the same as those allowed by the <a
6491 * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
6492 * <p>
6493 * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
6494 * <p>
6495 * For reference:
6496 * <ul>
6497 * <li>\x0B = vertical tab</li>
6498 * <li>\f = #xC = form feed</li>
6499 * <li>#x20 = space</li>
6500 * <li>#x9 = \t</li>
6501 * <li>#xA = \n</li>
6502 * <li>#xD = \r</li>
6503 * </ul>
6504 * </p>
6505 * <p>
6506 * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
6507 * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char &lt;= 32) from both
6508 * ends of this String.
6509 * </p>
6510 *
6511 * @see Pattern
6512 * @see #trim(String)
6513 * @see <a
6514 * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
6515 * @param str the source String to normalize whitespaces from, may be null
6516 * @return the modified string with whitespace normalized, {@code null} if null String input
6517 *
6518 * @since 3.0
6519 */
6520 public static String normalizeSpace(String str) {
6521 if (str == null) {
6522 return null;
6523 }
6524 return WHITESPACE_BLOCK.matcher(trim(str)).replaceAll(" ");
6525 }
6526
6527 /**
6528 * <p>Check if a CharSequence ends with any of an array of specified strings.</p>
6529 *
6530 * <pre>
6531 * StringUtils.endsWithAny(null, null) = false
6532 * StringUtils.endsWithAny(null, new String[] {"abc"}) = false
6533 * StringUtils.endsWithAny("abcxyz", null) = false
6534 * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
6535 * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
6536 * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
6537 * </pre>
6538 *
6539 * @param string the CharSequence to check, may be null
6540 * @param searchStrings the CharSequences to find, may be null or empty
6541 * @return {@code true} if the CharSequence ends with any of the the prefixes, case insensitive, or
6542 * both {@code null}
6543 * @since 3.0
6544 */
6545 public static boolean endsWithAny(CharSequence string, CharSequence... searchStrings) {
6546 if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
6547 return false;
6548 }
6549 for (CharSequence searchString : searchStrings) {
6550 if (StringUtils.endsWith(string, searchString)) {
6551 return true;
6552 }
6553 }
6554 return false;
6555 }
6556
6557 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.io.File;
19
20 /**
21 * <p>
22 * Helpers for {@code java.lang.System}.
23 * </p>
24 * <p>
25 * If a system property cannot be read due to security restrictions, the corresponding field in this class will be set
26 * to {@code null} and a message will be written to {@code System.err}.
27 * </p>
28 * <p>
29 * #ThreadSafe#
30 * </p>
31 *
32 * @since 1.0
33 * @version $Id: SystemUtils.java 1088899 2011-04-05 05:31:27Z bayard $
34 */
35 public class SystemUtils {
36
37 /**
38 * The prefix String for all Windows OS.
39 */
40 private static final String OS_NAME_WINDOWS_PREFIX = "Windows";
41
42 // System property constants
43 // -----------------------------------------------------------------------
44 // These MUST be declared first. Other constants depend on this.
45
46 /**
47 * The System property key for the user home directory.
48 */
49 private static final String USER_HOME_KEY = "user.home";
50
51 /**
52 * The System property key for the user directory.
53 */
54 private static final String USER_DIR_KEY = "user.dir";
55
56 /**
57 * The System property key for the Java IO temporary directory.
58 */
59 private static final String JAVA_IO_TMPDIR_KEY = "java.io.tmpdir";
60
61 /**
62 * The System property key for the Java home directory.
63 */
64 private static final String JAVA_HOME_KEY = "java.home";
65
66 /**
67 * <p>
68 * The {@code awt.toolkit} System Property.
69 * </p>
70 * <p>
71 * Holds a class name, on Windows XP this is {@code sun.awt.windows.WToolkit}.
72 * </p>
73 * <p>
74 * <b>On platforms without a GUI, this value is {@code null}.</b>
75 * </p>
76 * <p>
77 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
78 * not exist.
79 * </p>
80 * <p>
81 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
82 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
83 * sync with that System property.
84 * </p>
85 *
86 * @since 2.1
87 */
88 public static final String AWT_TOOLKIT = getSystemProperty("awt.toolkit");
89
90 /**
91 * <p>
92 * The {@code file.encoding} System Property.
93 * </p>
94 * <p>
95 * File encoding, such as {@code Cp1252}.
96 * </p>
97 * <p>
98 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
99 * not exist.
100 * </p>
101 * <p>
102 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
103 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
104 * sync with that System property.
105 * </p>
106 *
107 * @since 2.0
108 * @since Java 1.2
109 */
110 public static final String FILE_ENCODING = getSystemProperty("file.encoding");
111
112 /**
113 * <p>
114 * The {@code file.separator} System Property. File separator (<code>&quot;/&quot;</code> on UNIX).
115 * </p>
116 * <p>
117 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
118 * not exist.
119 * </p>
120 * <p>
121 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
122 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
123 * sync with that System property.
124 * </p>
125 *
126 * @since Java 1.1
127 */
128 public static final String FILE_SEPARATOR = getSystemProperty("file.separator");
129
130 /**
131 * <p>
132 * The {@code java.awt.fonts} System Property.
133 * </p>
134 * <p>
135 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
136 * not exist.
137 * </p>
138 * <p>
139 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
140 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
141 * sync with that System property.
142 * </p>
143 *
144 * @since 2.1
145 */
146 public static final String JAVA_AWT_FONTS = getSystemProperty("java.awt.fonts");
147
148 /**
149 * <p>
150 * The {@code java.awt.graphicsenv} System Property.
151 * </p>
152 * <p>
153 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
154 * not exist.
155 * </p>
156 * <p>
157 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
158 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
159 * sync with that System property.
160 * </p>
161 *
162 * @since 2.1
163 */
164 public static final String JAVA_AWT_GRAPHICSENV = getSystemProperty("java.awt.graphicsenv");
165
166 /**
167 * <p>
168 * The {@code java.awt.headless} System Property. The value of this property is the String {@code "true"} or
169 * {@code "false"}.
170 * </p>
171 * <p>
172 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
173 * not exist.
174 * </p>
175 * <p>
176 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
177 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
178 * sync with that System property.
179 * </p>
180 *
181 * @see #isJavaAwtHeadless()
182 * @since 2.1
183 * @since Java 1.4
184 */
185 public static final String JAVA_AWT_HEADLESS = getSystemProperty("java.awt.headless");
186
187 /**
188 * <p>
189 * The {@code java.awt.printerjob} System Property.
190 * </p>
191 * <p>
192 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
193 * not exist.
194 * </p>
195 * <p>
196 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
197 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
198 * sync with that System property.
199 * </p>
200 *
201 * @since 2.1
202 */
203 public static final String JAVA_AWT_PRINTERJOB = getSystemProperty("java.awt.printerjob");
204
205 /**
206 * <p>
207 * The {@code java.class.path} System Property. Java class path.
208 * </p>
209 * <p>
210 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
211 * not exist.
212 * </p>
213 * <p>
214 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
215 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
216 * sync with that System property.
217 * </p>
218 *
219 * @since Java 1.1
220 */
221 public static final String JAVA_CLASS_PATH = getSystemProperty("java.class.path");
222
223 /**
224 * <p>
225 * The {@code java.class.version} System Property. Java class format version number.
226 * </p>
227 * <p>
228 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
229 * not exist.
230 * </p>
231 * <p>
232 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
233 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
234 * sync with that System property.
235 * </p>
236 *
237 * @since Java 1.1
238 */
239 public static final String JAVA_CLASS_VERSION = getSystemProperty("java.class.version");
240
241 /**
242 * <p>
243 * The {@code java.compiler} System Property. Name of JIT compiler to use. First in JDK version 1.2. Not used in Sun
244 * JDKs after 1.2.
245 * </p>
246 * <p>
247 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
248 * not exist.
249 * </p>
250 * <p>
251 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
252 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
253 * sync with that System property.
254 * </p>
255 *
256 * @since Java 1.2. Not used in Sun versions after 1.2.
257 */
258 public static final String JAVA_COMPILER = getSystemProperty("java.compiler");
259
260 /**
261 * <p>
262 * The {@code java.endorsed.dirs} System Property. Path of endorsed directory or directories.
263 * </p>
264 * <p>
265 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
266 * not exist.
267 * </p>
268 * <p>
269 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
270 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
271 * sync with that System property.
272 * </p>
273 *
274 * @since Java 1.4
275 */
276 public static final String JAVA_ENDORSED_DIRS = getSystemProperty("java.endorsed.dirs");
277
278 /**
279 * <p>
280 * The {@code java.ext.dirs} System Property. Path of extension directory or directories.
281 * </p>
282 * <p>
283 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
284 * not exist.
285 * </p>
286 * <p>
287 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
288 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
289 * sync with that System property.
290 * </p>
291 *
292 * @since Java 1.3
293 */
294 public static final String JAVA_EXT_DIRS = getSystemProperty("java.ext.dirs");
295
296 /**
297 * <p>
298 * The {@code java.home} System Property. Java installation directory.
299 * </p>
300 * <p>
301 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
302 * not exist.
303 * </p>
304 * <p>
305 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
306 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
307 * sync with that System property.
308 * </p>
309 *
310 * @since Java 1.1
311 */
312 public static final String JAVA_HOME = getSystemProperty(JAVA_HOME_KEY);
313
314 /**
315 * <p>
316 * The {@code java.io.tmpdir} System Property. Default temp file path.
317 * </p>
318 * <p>
319 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
320 * not exist.
321 * </p>
322 * <p>
323 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
324 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
325 * sync with that System property.
326 * </p>
327 *
328 * @since Java 1.2
329 */
330 public static final String JAVA_IO_TMPDIR = getSystemProperty(JAVA_IO_TMPDIR_KEY);
331
332 /**
333 * <p>
334 * The {@code java.library.path} System Property. List of paths to search when loading libraries.
335 * </p>
336 * <p>
337 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
338 * not exist.
339 * </p>
340 * <p>
341 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
342 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
343 * sync with that System property.
344 * </p>
345 *
346 * @since Java 1.2
347 */
348 public static final String JAVA_LIBRARY_PATH = getSystemProperty("java.library.path");
349
350 /**
351 * <p>
352 * The {@code java.runtime.name} System Property. Java Runtime Environment name.
353 * </p>
354 * <p>
355 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
356 * not exist.
357 * </p>
358 * <p>
359 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
360 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
361 * sync with that System property.
362 * </p>
363 *
364 * @since 2.0
365 * @since Java 1.3
366 */
367 public static final String JAVA_RUNTIME_NAME = getSystemProperty("java.runtime.name");
368
369 /**
370 * <p>
371 * The {@code java.runtime.version} System Property. Java Runtime Environment version.
372 * </p>
373 * <p>
374 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
375 * not exist.
376 * </p>
377 * <p>
378 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
379 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
380 * sync with that System property.
381 * </p>
382 *
383 * @since 2.0
384 * @since Java 1.3
385 */
386 public static final String JAVA_RUNTIME_VERSION = getSystemProperty("java.runtime.version");
387
388 /**
389 * <p>
390 * The {@code java.specification.name} System Property. Java Runtime Environment specification name.
391 * </p>
392 * <p>
393 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
394 * not exist.
395 * </p>
396 * <p>
397 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
398 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
399 * sync with that System property.
400 * </p>
401 *
402 * @since Java 1.2
403 */
404 public static final String JAVA_SPECIFICATION_NAME = getSystemProperty("java.specification.name");
405
406 /**
407 * <p>
408 * The {@code java.specification.vendor} System Property. Java Runtime Environment specification vendor.
409 * </p>
410 * <p>
411 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
412 * not exist.
413 * </p>
414 * <p>
415 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
416 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
417 * sync with that System property.
418 * </p>
419 *
420 * @since Java 1.2
421 */
422 public static final String JAVA_SPECIFICATION_VENDOR = getSystemProperty("java.specification.vendor");
423
424 /**
425 * <p>
426 * The {@code java.specification.version} System Property. Java Runtime Environment specification version.
427 * </p>
428 * <p>
429 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
430 * not exist.
431 * </p>
432 * <p>
433 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
434 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
435 * sync with that System property.
436 * </p>
437 *
438 * @since Java 1.3
439 */
440 public static final String JAVA_SPECIFICATION_VERSION = getSystemProperty("java.specification.version");
441 private static final JavaVersion JAVA_SPECIFICATION_VERSION_AS_ENUM = JavaVersion.get(JAVA_SPECIFICATION_VERSION);
442
443 /**
444 * <p>
445 * The {@code java.util.prefs.PreferencesFactory} System Property. A class name.
446 * </p>
447 * <p>
448 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
449 * not exist.
450 * </p>
451 * <p>
452 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
453 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
454 * sync with that System property.
455 * </p>
456 *
457 * @since 2.1
458 * @since Java 1.4
459 */
460 public static final String JAVA_UTIL_PREFS_PREFERENCES_FACTORY =
461 getSystemProperty("java.util.prefs.PreferencesFactory");
462
463 /**
464 * <p>
465 * The {@code java.vendor} System Property. Java vendor-specific string.
466 * </p>
467 * <p>
468 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
469 * not exist.
470 * </p>
471 * <p>
472 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
473 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
474 * sync with that System property.
475 * </p>
476 *
477 * @since Java 1.1
478 */
479 public static final String JAVA_VENDOR = getSystemProperty("java.vendor");
480
481 /**
482 * <p>
483 * The {@code java.vendor.url} System Property. Java vendor URL.
484 * </p>
485 * <p>
486 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
487 * not exist.
488 * </p>
489 * <p>
490 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
491 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
492 * sync with that System property.
493 * </p>
494 *
495 * @since Java 1.1
496 */
497 public static final String JAVA_VENDOR_URL = getSystemProperty("java.vendor.url");
498
499 /**
500 * <p>
501 * The {@code java.version} System Property. Java version number.
502 * </p>
503 * <p>
504 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
505 * not exist.
506 * </p>
507 * <p>
508 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
509 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
510 * sync with that System property.
511 * </p>
512 *
513 * @since Java 1.1
514 */
515 public static final String JAVA_VERSION = getSystemProperty("java.version");
516
517 /**
518 * <p>
519 * The {@code java.vm.info} System Property. Java Virtual Machine implementation info.
520 * </p>
521 * <p>
522 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
523 * not exist.
524 * </p>
525 * <p>
526 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
527 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
528 * sync with that System property.
529 * </p>
530 *
531 * @since 2.0
532 * @since Java 1.2
533 */
534 public static final String JAVA_VM_INFO = getSystemProperty("java.vm.info");
535
536 /**
537 * <p>
538 * The {@code java.vm.name} System Property. Java Virtual Machine implementation name.
539 * </p>
540 * <p>
541 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
542 * not exist.
543 * </p>
544 * <p>
545 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
546 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
547 * sync with that System property.
548 * </p>
549 *
550 * @since Java 1.2
551 */
552 public static final String JAVA_VM_NAME = getSystemProperty("java.vm.name");
553
554 /**
555 * <p>
556 * The {@code java.vm.specification.name} System Property. Java Virtual Machine specification name.
557 * </p>
558 * <p>
559 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
560 * not exist.
561 * </p>
562 * <p>
563 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
564 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
565 * sync with that System property.
566 * </p>
567 *
568 * @since Java 1.2
569 */
570 public static final String JAVA_VM_SPECIFICATION_NAME = getSystemProperty("java.vm.specification.name");
571
572 /**
573 * <p>
574 * The {@code java.vm.specification.vendor} System Property. Java Virtual Machine specification vendor.
575 * </p>
576 * <p>
577 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
578 * not exist.
579 * </p>
580 * <p>
581 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
582 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
583 * sync with that System property.
584 * </p>
585 *
586 * @since Java 1.2
587 */
588 public static final String JAVA_VM_SPECIFICATION_VENDOR = getSystemProperty("java.vm.specification.vendor");
589
590 /**
591 * <p>
592 * The {@code java.vm.specification.version} System Property. Java Virtual Machine specification version.
593 * </p>
594 * <p>
595 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
596 * not exist.
597 * </p>
598 * <p>
599 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
600 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
601 * sync with that System property.
602 * </p>
603 *
604 * @since Java 1.2
605 */
606 public static final String JAVA_VM_SPECIFICATION_VERSION = getSystemProperty("java.vm.specification.version");
607
608 /**
609 * <p>
610 * The {@code java.vm.vendor} System Property. Java Virtual Machine implementation vendor.
611 * </p>
612 * <p>
613 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
614 * not exist.
615 * </p>
616 * <p>
617 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
618 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
619 * sync with that System property.
620 * </p>
621 *
622 * @since Java 1.2
623 */
624 public static final String JAVA_VM_VENDOR = getSystemProperty("java.vm.vendor");
625
626 /**
627 * <p>
628 * The {@code java.vm.version} System Property. Java Virtual Machine implementation version.
629 * </p>
630 * <p>
631 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
632 * not exist.
633 * </p>
634 * <p>
635 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
636 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
637 * sync with that System property.
638 * </p>
639 *
640 * @since Java 1.2
641 */
642 public static final String JAVA_VM_VERSION = getSystemProperty("java.vm.version");
643
644 /**
645 * <p>
646 * The {@code line.separator} System Property. Line separator (<code>&quot;\n&quot;</code> on UNIX).
647 * </p>
648 * <p>
649 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
650 * not exist.
651 * </p>
652 * <p>
653 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
654 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
655 * sync with that System property.
656 * </p>
657 *
658 * @since Java 1.1
659 */
660 public static final String LINE_SEPARATOR = getSystemProperty("line.separator");
661
662 /**
663 * <p>
664 * The {@code os.arch} System Property. Operating system architecture.
665 * </p>
666 * <p>
667 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
668 * not exist.
669 * </p>
670 * <p>
671 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
672 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
673 * sync with that System property.
674 * </p>
675 *
676 * @since Java 1.1
677 */
678 public static final String OS_ARCH = getSystemProperty("os.arch");
679
680 /**
681 * <p>
682 * The {@code os.name} System Property. Operating system name.
683 * </p>
684 * <p>
685 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
686 * not exist.
687 * </p>
688 * <p>
689 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
690 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
691 * sync with that System property.
692 * </p>
693 *
694 * @since Java 1.1
695 */
696 public static final String OS_NAME = getSystemProperty("os.name");
697
698 /**
699 * <p>
700 * The {@code os.version} System Property. Operating system version.
701 * </p>
702 * <p>
703 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
704 * not exist.
705 * </p>
706 * <p>
707 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
708 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
709 * sync with that System property.
710 * </p>
711 *
712 * @since Java 1.1
713 */
714 public static final String OS_VERSION = getSystemProperty("os.version");
715
716 /**
717 * <p>
718 * The {@code path.separator} System Property. Path separator (<code>&quot;:&quot;</code> on UNIX).
719 * </p>
720 * <p>
721 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
722 * not exist.
723 * </p>
724 * <p>
725 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
726 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
727 * sync with that System property.
728 * </p>
729 *
730 * @since Java 1.1
731 */
732 public static final String PATH_SEPARATOR = getSystemProperty("path.separator");
733
734 /**
735 * <p>
736 * The {@code user.country} or {@code user.region} System Property. User's country code, such as {@code GB}. First
737 * in Java version 1.2 as {@code user.region}. Renamed to {@code user.country} in 1.4
738 * </p>
739 * <p>
740 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
741 * not exist.
742 * </p>
743 * <p>
744 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
745 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
746 * sync with that System property.
747 * </p>
748 *
749 * @since 2.0
750 * @since Java 1.2
751 */
752 public static final String USER_COUNTRY = getSystemProperty("user.country") == null ?
753 getSystemProperty("user.region") : getSystemProperty("user.country");
754
755 /**
756 * <p>
757 * The {@code user.dir} System Property. User's current working directory.
758 * </p>
759 * <p>
760 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
761 * not exist.
762 * </p>
763 * <p>
764 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
765 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
766 * sync with that System property.
767 * </p>
768 *
769 * @since Java 1.1
770 */
771 public static final String USER_DIR = getSystemProperty(USER_DIR_KEY);
772
773 /**
774 * <p>
775 * The {@code user.home} System Property. User's home directory.
776 * </p>
777 * <p>
778 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
779 * not exist.
780 * </p>
781 * <p>
782 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
783 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
784 * sync with that System property.
785 * </p>
786 *
787 * @since Java 1.1
788 */
789 public static final String USER_HOME = getSystemProperty(USER_HOME_KEY);
790
791 /**
792 * <p>
793 * The {@code user.language} System Property. User's language code, such as {@code "en"}.
794 * </p>
795 * <p>
796 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
797 * not exist.
798 * </p>
799 * <p>
800 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
801 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
802 * sync with that System property.
803 * </p>
804 *
805 * @since 2.0
806 * @since Java 1.2
807 */
808 public static final String USER_LANGUAGE = getSystemProperty("user.language");
809
810 /**
811 * <p>
812 * The {@code user.name} System Property. User's account name.
813 * </p>
814 * <p>
815 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
816 * not exist.
817 * </p>
818 * <p>
819 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
820 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
821 * sync with that System property.
822 * </p>
823 *
824 * @since Java 1.1
825 */
826 public static final String USER_NAME = getSystemProperty("user.name");
827
828 /**
829 * <p>
830 * The {@code user.timezone} System Property. For example: {@code "America/Los_Angeles"}.
831 * </p>
832 * <p>
833 * Defaults to {@code null} if the runtime does not have security access to read this property or the property does
834 * not exist.
835 * </p>
836 * <p>
837 * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
838 * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
839 * sync with that System property.
840 * </p>
841 *
842 * @since 2.1
843 */
844 public static final String USER_TIMEZONE = getSystemProperty("user.timezone");
845
846 // Java version checks
847 // -----------------------------------------------------------------------
848 // These MUST be declared after those above as they depend on the
849 // values being set up
850
851 /**
852 * <p>
853 * Is {@code true} if this is Java version 1.1 (also 1.1.x versions).
854 * </p>
855 * <p>
856 * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
857 * </p>
858 */
859 public static final boolean IS_JAVA_1_1 = getJavaVersionMatches("1.1");
860
861 /**
862 * <p>
863 * Is {@code true} if this is Java version 1.2 (also 1.2.x versions).
864 * </p>
865 * <p>
866 * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
867 * </p>
868 */
869 public static final boolean IS_JAVA_1_2 = getJavaVersionMatches("1.2");
870
871 /**
872 * <p>
873 * Is {@code true} if this is Java version 1.3 (also 1.3.x versions).
874 * </p>
875 * <p>
876 * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
877 * </p>
878 */
879 public static final boolean IS_JAVA_1_3 = getJavaVersionMatches("1.3");
880
881 /**
882 * <p>
883 * Is {@code true} if this is Java version 1.4 (also 1.4.x versions).
884 * </p>
885 * <p>
886 * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
887 * </p>
888 */
889 public static final boolean IS_JAVA_1_4 = getJavaVersionMatches("1.4");
890
891 /**
892 * <p>
893 * Is {@code true} if this is Java version 1.5 (also 1.5.x versions).
894 * </p>
895 * <p>
896 * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
897 * </p>
898 */
899 public static final boolean IS_JAVA_1_5 = getJavaVersionMatches("1.5");
900
901 /**
902 * <p>
903 * Is {@code true} if this is Java version 1.6 (also 1.6.x versions).
904 * </p>
905 * <p>
906 * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
907 * </p>
908 */
909 public static final boolean IS_JAVA_1_6 = getJavaVersionMatches("1.6");
910
911 /**
912 * <p>
913 * Is {@code true} if this is Java version 1.7 (also 1.7.x versions).
914 * </p>
915 * <p>
916 * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
917 * </p>
918 *
919 * @since 3.0
920 */
921 public static final boolean IS_JAVA_1_7 = getJavaVersionMatches("1.7");
922
923 // Operating system checks
924 // -----------------------------------------------------------------------
925 // These MUST be declared after those above as they depend on the
926 // values being set up
927 // OS names from http://www.vamphq.com/os.html
928 // Selected ones included - please advise dev@commons.apache.org
929 // if you want another added or a mistake corrected
930
931 /**
932 * <p>
933 * Is {@code true} if this is AIX.
934 * </p>
935 * <p>
936 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
937 * </p>
938 *
939 * @since 2.0
940 */
941 public static final boolean IS_OS_AIX = getOSMatchesName("AIX");
942
943 /**
944 * <p>
945 * Is {@code true} if this is HP-UX.
946 * </p>
947 * <p>
948 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
949 * </p>
950 *
951 * @since 2.0
952 */
953 public static final boolean IS_OS_HP_UX = getOSMatchesName("HP-UX");
954
955 /**
956 * <p>
957 * Is {@code true} if this is Irix.
958 * </p>
959 * <p>
960 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
961 * </p>
962 *
963 * @since 2.0
964 */
965 public static final boolean IS_OS_IRIX = getOSMatchesName("Irix");
966
967 /**
968 * <p>
969 * Is {@code true} if this is Linux.
970 * </p>
971 * <p>
972 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
973 * </p>
974 *
975 * @since 2.0
976 */
977 public static final boolean IS_OS_LINUX = getOSMatchesName("Linux") || getOSMatchesName("LINUX");
978
979 /**
980 * <p>
981 * Is {@code true} if this is Mac.
982 * </p>
983 * <p>
984 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
985 * </p>
986 *
987 * @since 2.0
988 */
989 public static final boolean IS_OS_MAC = getOSMatchesName("Mac");
990
991 /**
992 * <p>
993 * Is {@code true} if this is Mac.
994 * </p>
995 * <p>
996 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
997 * </p>
998 *
999 * @since 2.0
1000 */
1001 public static final boolean IS_OS_MAC_OSX = getOSMatchesName("Mac OS X");
1002
1003 /**
1004 * <p>
1005 * Is {@code true} if this is OS/2.
1006 * </p>
1007 * <p>
1008 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1009 * </p>
1010 *
1011 * @since 2.0
1012 */
1013 public static final boolean IS_OS_OS2 = getOSMatchesName("OS/2");
1014
1015 /**
1016 * <p>
1017 * Is {@code true} if this is Solaris.
1018 * </p>
1019 * <p>
1020 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1021 * </p>
1022 *
1023 * @since 2.0
1024 */
1025 public static final boolean IS_OS_SOLARIS = getOSMatchesName("Solaris");
1026
1027 /**
1028 * <p>
1029 * Is {@code true} if this is SunOS.
1030 * </p>
1031 * <p>
1032 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1033 * </p>
1034 *
1035 * @since 2.0
1036 */
1037 public static final boolean IS_OS_SUN_OS = getOSMatchesName("SunOS");
1038
1039 /**
1040 * <p>
1041 * Is {@code true} if this is a UNIX like system, as in any of AIX, HP-UX, Irix, Linux, MacOSX, Solaris or SUN OS.
1042 * </p>
1043 * <p>
1044 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1045 * </p>
1046 *
1047 * @since 2.1
1048 */
1049 public static final boolean IS_OS_UNIX = IS_OS_AIX || IS_OS_HP_UX || IS_OS_IRIX || IS_OS_LINUX || IS_OS_MAC_OSX
1050 || IS_OS_SOLARIS || IS_OS_SUN_OS;
1051
1052 /**
1053 * <p>
1054 * Is {@code true} if this is Windows.
1055 * </p>
1056 * <p>
1057 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1058 * </p>
1059 *
1060 * @since 2.0
1061 */
1062 public static final boolean IS_OS_WINDOWS = getOSMatchesName(OS_NAME_WINDOWS_PREFIX);
1063
1064 /**
1065 * <p>
1066 * Is {@code true} if this is Windows 2000.
1067 * </p>
1068 * <p>
1069 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1070 * </p>
1071 *
1072 * @since 2.0
1073 */
1074 public static final boolean IS_OS_WINDOWS_2000 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.0");
1075
1076 /**
1077 * <p>
1078 * Is {@code true} if this is Windows 95.
1079 * </p>
1080 * <p>
1081 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1082 * </p>
1083 *
1084 * @since 2.0
1085 */
1086 public static final boolean IS_OS_WINDOWS_95 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " 9", "4.0");
1087 // Java 1.2 running on Windows98 returns 'Windows 95', hence the above
1088
1089 /**
1090 * <p>
1091 * Is {@code true} if this is Windows 98.
1092 * </p>
1093 * <p>
1094 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1095 * </p>
1096 *
1097 * @since 2.0
1098 */
1099 public static final boolean IS_OS_WINDOWS_98 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " 9", "4.1");
1100 // Java 1.2 running on Windows98 returns 'Windows 95', hence the above
1101
1102 /**
1103 * <p>
1104 * Is {@code true} if this is Windows ME.
1105 * </p>
1106 * <p>
1107 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1108 * </p>
1109 *
1110 * @since 2.0
1111 */
1112 public static final boolean IS_OS_WINDOWS_ME = getOSMatches(OS_NAME_WINDOWS_PREFIX, "4.9");
1113 // Java 1.2 running on WindowsME may return 'Windows 95', hence the above
1114
1115 /**
1116 * <p>
1117 * Is {@code true} if this is Windows NT.
1118 * </p>
1119 * <p>
1120 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1121 * </p>
1122 *
1123 * @since 2.0
1124 */
1125 public static final boolean IS_OS_WINDOWS_NT = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " NT");
1126 // Windows 2000 returns 'Windows 2000' but may suffer from same Java1.2 problem
1127
1128 /**
1129 * <p>
1130 * Is {@code true} if this is Windows XP.
1131 * </p>
1132 * <p>
1133 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1134 * </p>
1135 *
1136 * @since 2.0
1137 */
1138 public static final boolean IS_OS_WINDOWS_XP = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.1");
1139
1140 // -----------------------------------------------------------------------
1141 /**
1142 * <p>
1143 * Is {@code true} if this is Windows Vista.
1144 * </p>
1145 * <p>
1146 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1147 * </p>
1148 *
1149 * @since 2.4
1150 */
1151 public static final boolean IS_OS_WINDOWS_VISTA = getOSMatches(OS_NAME_WINDOWS_PREFIX, "6.0");
1152
1153 /**
1154 * <p>
1155 * Is {@code true} if this is Windows 7.
1156 * </p>
1157 * <p>
1158 * The field will return {@code false} if {@code OS_NAME} is {@code null}.
1159 * </p>
1160 *
1161 * @since 3.0
1162 */
1163 public static final boolean IS_OS_WINDOWS_7 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "6.1");
1164
1165 /**
1166 * <p>
1167 * Gets the Java home directory as a {@code File}.
1168 * </p>
1169 *
1170 * @return a directory
1171 * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow
1172 * access to the specified system property.
1173 * @see System#getProperty(String)
1174 * @since 2.1
1175 */
1176 public static File getJavaHome() {
1177 return new File(System.getProperty(JAVA_HOME_KEY));
1178 }
1179
1180 /**
1181 * <p>
1182 * Gets the Java IO temporary directory as a {@code File}.
1183 * </p>
1184 *
1185 * @return a directory
1186 * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow
1187 * access to the specified system property.
1188 * @see System#getProperty(String)
1189 * @since 2.1
1190 */
1191 public static File getJavaIoTmpDir() {
1192 return new File(System.getProperty(JAVA_IO_TMPDIR_KEY));
1193 }
1194
1195 /**
1196 * <p>
1197 * Decides if the Java version matches.
1198 * </p>
1199 *
1200 * @param versionPrefix the prefix for the java version
1201 * @return true if matches, or false if not or can't determine
1202 */
1203 private static boolean getJavaVersionMatches(String versionPrefix) {
1204 return isJavaVersionMatch(JAVA_SPECIFICATION_VERSION, versionPrefix);
1205 }
1206
1207 /**
1208 * Decides if the operating system matches.
1209 *
1210 * @param osNamePrefix the prefix for the os name
1211 * @param osVersionPrefix the prefix for the version
1212 * @return true if matches, or false if not or can't determine
1213 */
1214 private static boolean getOSMatches(String osNamePrefix, String osVersionPrefix) {
1215 return isOSMatch(OS_NAME, OS_VERSION, osNamePrefix, osVersionPrefix);
1216 }
1217
1218 /**
1219 * Decides if the operating system matches.
1220 *
1221 * @param osNamePrefix the prefix for the os name
1222 * @return true if matches, or false if not or can't determine
1223 */
1224 private static boolean getOSMatchesName(String osNamePrefix) {
1225 return isOSNameMatch(OS_NAME, osNamePrefix);
1226 }
1227
1228 // -----------------------------------------------------------------------
1229 /**
1230 * <p>
1231 * Gets a System property, defaulting to {@code null} if the property cannot be read.
1232 * </p>
1233 * <p>
1234 * If a {@code SecurityException} is caught, the return value is {@code null} and a message is written to
1235 * {@code System.err}.
1236 * </p>
1237 *
1238 * @param property the system property name
1239 * @return the system property value or {@code null} if a security problem occurs
1240 */
1241 private static String getSystemProperty(String property) {
1242 try {
1243 return System.getProperty(property);
1244 } catch (SecurityException ex) {
1245 // we are not allowed to look at this property
1246 System.err.println("Caught a SecurityException reading the system property '" + property
1247 + "'; the SystemUtils property value will default to null.");
1248 return null;
1249 }
1250 }
1251
1252 /**
1253 * <p>
1254 * Gets the user directory as a {@code File}.
1255 * </p>
1256 *
1257 * @return a directory
1258 * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow
1259 * access to the specified system property.
1260 * @see System#getProperty(String)
1261 * @since 2.1
1262 */
1263 public static File getUserDir() {
1264 return new File(System.getProperty(USER_DIR_KEY));
1265 }
1266
1267 /**
1268 * <p>
1269 * Gets the user home directory as a {@code File}.
1270 * </p>
1271 *
1272 * @return a directory
1273 * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow
1274 * access to the specified system property.
1275 * @see System#getProperty(String)
1276 * @since 2.1
1277 */
1278 public static File getUserHome() {
1279 return new File(System.getProperty(USER_HOME_KEY));
1280 }
1281
1282 /**
1283 * Returns whether the {@link #JAVA_AWT_HEADLESS} value is {@code true}.
1284 *
1285 * @return {@code true} if {@code JAVA_AWT_HEADLESS} is {@code "true"}, {@code false} otherwise.
1286 * @see #JAVA_AWT_HEADLESS
1287 * @since 2.1
1288 * @since Java 1.4
1289 */
1290 public static boolean isJavaAwtHeadless() {
1291 return JAVA_AWT_HEADLESS != null ? JAVA_AWT_HEADLESS.equals(Boolean.TRUE.toString()) : false;
1292 }
1293
1294 /**
1295 * <p>
1296 * Is the Java version at least the requested version.
1297 * </p>
1298 * <p>
1299 * Example input:
1300 * </p>
1301 * <ul>
1302 * <li>{@code 1.2f} to test for Java 1.2</li>
1303 * <li>{@code 1.31f} to test for Java 1.3.1</li>
1304 * </ul>
1305 *
1306 * @param requiredVersion the required version, for example 1.31f
1307 * @return {@code true} if the actual version is equal or greater than the required version
1308 */
1309 public static boolean isJavaVersionAtLeast(JavaVersion requiredVersion) {
1310 return JAVA_SPECIFICATION_VERSION_AS_ENUM.atLeast(requiredVersion);
1311 }
1312
1313 /**
1314 * <p>
1315 * Decides if the Java version matches.
1316 * </p>
1317 * <p>
1318 * This method is package private instead of private to support unit test invocation.
1319 * </p>
1320 *
1321 * @param version the actual Java version
1322 * @param versionPrefix the prefix for the expected Java version
1323 * @return true if matches, or false if not or can't determine
1324 */
1325 static boolean isJavaVersionMatch(String version, String versionPrefix) {
1326 if (version == null) {
1327 return false;
1328 }
1329 return version.startsWith(versionPrefix);
1330 }
1331
1332 /**
1333 * Decides if the operating system matches.
1334 * <p>
1335 * This method is package private instead of private to support unit test invocation.
1336 * </p>
1337 *
1338 * @param osName the actual OS name
1339 * @param osVersion the actual OS version
1340 * @param osNamePrefix the prefix for the expected OS name
1341 * @param osVersionPrefix the prefix for the expected OS version
1342 * @return true if matches, or false if not or can't determine
1343 */
1344 static boolean isOSMatch(String osName, String osVersion, String osNamePrefix, String osVersionPrefix) {
1345 if (osName == null || osVersion == null) {
1346 return false;
1347 }
1348 return osName.startsWith(osNamePrefix) && osVersion.startsWith(osVersionPrefix);
1349 }
1350
1351 /**
1352 * Decides if the operating system matches.
1353 * <p>
1354 * This method is package private instead of private to support unit test invocation.
1355 * </p>
1356 *
1357 * @param osName the actual OS name
1358 * @param osNamePrefix the prefix for the expected OS name
1359 * @return true if matches, or false if not or can't determine
1360 */
1361 static boolean isOSNameMatch(String osName, String osNamePrefix) {
1362 if (osName == null) {
1363 return false;
1364 }
1365 return osName.startsWith(osNamePrefix);
1366 }
1367
1368 // -----------------------------------------------------------------------
1369 /**
1370 * <p>
1371 * SystemUtils instances should NOT be constructed in standard programming. Instead, the class should be used as
1372 * {@code SystemUtils.FILE_SEPARATOR}.
1373 * </p>
1374 * <p>
1375 * This constructor is public to permit tools that require a JavaBean instance to operate.
1376 * </p>
1377 */
1378 public SystemUtils() {
1379 super();
1380 }
1381
1382 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.util.Collection;
19 import java.util.Iterator;
20 import java.util.Map;
21 import java.util.regex.Pattern;
22
23 /**
24 * <p>This class assists in validating arguments. The validation methods are
25 * based along the following principles:
26 * <ul>
27 * <li>An invalid {@code null} argument causes a {@link NullPointerException}.</li>
28 * <li>A non-{@code null} argument causes an {@link IllegalArgumentException}.</li>
29 * <li>An invalid index into an array/collection/map/string causes an {@link IndexOutOfBoundsException}.</li>
30 * </ul>
31 *
32 * <p>All exceptions messages are
33 * <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Formatter.html#syntax">format strings</a>
34 * as defined by the Java platform. For example:</p>
35 *
36 * <pre>
37 * Validate.isTrue(i > 0, "The value must be greater than zero: %d", i);
38 * Validate.notNull(surname, "The surname must not be %s", null);
39 * </pre>
40 *
41 * <p>#ThreadSafe#</p>
42 * @version $Id: Validate.java 1153490 2011-08-03 13:53:35Z ggregory $
43 * @see java.lang.String#format(String, Object...)
44 * @since 2.0
45 */
46 public class Validate {
47
48 private static final String DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE =
49 "The value %s is not in the specified exclusive range of %s to %s";
50 private static final String DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE =
51 "The value %s is not in the specified inclusive range of %s to %s";
52 private static final String DEFAULT_MATCHES_PATTERN_EX = "The string %s does not match the pattern %s";
53 private static final String DEFAULT_IS_NULL_EX_MESSAGE = "The validated object is null";
54 private static final String DEFAULT_IS_TRUE_EX_MESSAGE = "The validated expression is false";
55 private static final String DEFAULT_NO_NULL_ELEMENTS_ARRAY_EX_MESSAGE =
56 "The validated array contains null element at index: %d";
57 private static final String DEFAULT_NO_NULL_ELEMENTS_COLLECTION_EX_MESSAGE =
58 "The validated collection contains null element at index: %d";
59 private static final String DEFAULT_NOT_BLANK_EX_MESSAGE = "The validated character sequence is blank";
60 private static final String DEFAULT_NOT_EMPTY_ARRAY_EX_MESSAGE = "The validated array is empty";
61 private static final String DEFAULT_NOT_EMPTY_CHAR_SEQUENCE_EX_MESSAGE =
62 "The validated character sequence is empty";
63 private static final String DEFAULT_NOT_EMPTY_COLLECTION_EX_MESSAGE = "The validated collection is empty";
64 private static final String DEFAULT_NOT_EMPTY_MAP_EX_MESSAGE = "The validated map is empty";
65 private static final String DEFAULT_VALID_INDEX_ARRAY_EX_MESSAGE = "The validated array index is invalid: %d";
66 private static final String DEFAULT_VALID_INDEX_CHAR_SEQUENCE_EX_MESSAGE =
67 "The validated character sequence index is invalid: %d";
68 private static final String DEFAULT_VALID_INDEX_COLLECTION_EX_MESSAGE =
69 "The validated collection index is invalid: %d";
70 private static final String DEFAULT_VALID_STATE_EX_MESSAGE = "The validated state is false";
71 private static final String DEFAULT_IS_ASSIGNABLE_EX_MESSAGE =
72 "The validated class can not be converted to the %s class";
73 private static final String DEFAULT_IS_INSTANCE_OF_EX_MESSAGE = "The validated object is not an instance of %s";
74
75 /**
76 * Constructor. This class should not normally be instantiated.
77 */
78 public Validate() {
79 super();
80 }
81
82 // isTrue
83 //---------------------------------------------------------------------------------
84
85 /**
86 * <p>Validate that the argument condition is {@code true}; otherwise
87 * throwing an exception with the specified message. This method is useful when
88 * validating according to an arbitrary boolean expression, such as validating a
89 * primitive number or using your own custom validation expression.</p>
90 *
91 * <pre>Validate.isTrue(i > 0.0, "The value must be greater than zero: %d", i);</pre>
92 *
93 * <p>For performance reasons, the long value is passed as a separate parameter and
94 * appended to the exception message only in the case of an error.</p>
95 *
96 * @param expression the boolean expression to check
97 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
98 * @param value the value to append to the message when invalid
99 * @throws IllegalArgumentException if expression is {@code false}
100 * @see #isTrue(boolean)
101 * @see #isTrue(boolean, String, double)
102 * @see #isTrue(boolean, String, Object...)
103 */
104 public static void isTrue(boolean expression, String message, long value) {
105 if (expression == false) {
106 throw new IllegalArgumentException(String.format(message, Long.valueOf(value)));
107 }
108 }
109
110 /**
111 * <p>Validate that the argument condition is {@code true}; otherwise
112 * throwing an exception with the specified message. This method is useful when
113 * validating according to an arbitrary boolean expression, such as validating a
114 * primitive number or using your own custom validation expression.</p>
115 *
116 * <pre>Validate.isTrue(d > 0.0, "The value must be greater than zero: %s", d);</pre>
117 *
118 * <p>For performance reasons, the double value is passed as a separate parameter and
119 * appended to the exception message only in the case of an error.</p>
120 *
121 * @param expression the boolean expression to check
122 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
123 * @param value the value to append to the message when invalid
124 * @throws IllegalArgumentException if expression is {@code false}
125 * @see #isTrue(boolean)
126 * @see #isTrue(boolean, String, long)
127 * @see #isTrue(boolean, String, Object...)
128 */
129 public static void isTrue(boolean expression, String message, double value) {
130 if (expression == false) {
131 throw new IllegalArgumentException(String.format(message, Double.valueOf(value)));
132 }
133 }
134
135 /**
136 * <p>Validate that the argument condition is {@code true}; otherwise
137 * throwing an exception with the specified message. This method is useful when
138 * validating according to an arbitrary boolean expression, such as validating a
139 * primitive number or using your own custom validation expression.</p>
140 *
141 * <pre>
142 * Validate.isTrue(i >= min && i <= max, "The value must be between %d and %d", min, max);
143 * Validate.isTrue(myObject.isOk(), "The object is not okay");</pre>
144 *
145 * @param expression the boolean expression to check
146 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
147 * @param values the optional values for the formatted exception message, null array not recommended
148 * @throws IllegalArgumentException if expression is {@code false}
149 * @see #isTrue(boolean)
150 * @see #isTrue(boolean, String, long)
151 * @see #isTrue(boolean, String, double)
152 */
153 public static void isTrue(boolean expression, String message, Object... values) {
154 if (expression == false) {
155 throw new IllegalArgumentException(String.format(message, values));
156 }
157 }
158
159 /**
160 * <p>Validate that the argument condition is {@code true}; otherwise
161 * throwing an exception. This method is useful when validating according
162 * to an arbitrary boolean expression, such as validating a
163 * primitive number or using your own custom validation expression.</p>
164 *
165 * <pre>
166 * Validate.isTrue(i > 0);
167 * Validate.isTrue(myObject.isOk());</pre>
168 *
169 * <p>The message of the exception is &quot;The validated expression is
170 * false&quot;.</p>
171 *
172 * @param expression the boolean expression to check
173 * @throws IllegalArgumentException if expression is {@code false}
174 * @see #isTrue(boolean, String, long)
175 * @see #isTrue(boolean, String, double)
176 * @see #isTrue(boolean, String, Object...)
177 */
178 public static void isTrue(boolean expression) {
179 if (expression == false) {
180 throw new IllegalArgumentException(DEFAULT_IS_TRUE_EX_MESSAGE);
181 }
182 }
183
184 // notNull
185 //---------------------------------------------------------------------------------
186
187 /**
188 * <p>Validate that the specified argument is not {@code null};
189 * otherwise throwing an exception.
190 *
191 * <pre>Validate.notNull(myObject, "The object must not be null");</pre>
192 *
193 * <p>The message of the exception is &quot;The validated object is
194 * null&quot;.</p>
195 *
196 * @param <T> the object type
197 * @param object the object to check
198 * @return the validated object (never {@code null} for method chaining)
199 * @throws NullPointerException if the object is {@code null}
200 * @see #notNull(Object, String, Object...)
201 */
202 public static <T> T notNull(T object) {
203 return notNull(object, DEFAULT_IS_NULL_EX_MESSAGE);
204 }
205
206 /**
207 * <p>Validate that the specified argument is not {@code null};
208 * otherwise throwing an exception with the specified message.
209 *
210 * <pre>Validate.notNull(myObject, "The object must not be null");</pre>
211 *
212 * @param <T> the object type
213 * @param object the object to check
214 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
215 * @param values the optional values for the formatted exception message
216 * @return the validated object (never {@code null} for method chaining)
217 * @throws NullPointerException if the object is {@code null}
218 * @see #notNull(Object)
219 */
220 public static <T> T notNull(T object, String message, Object... values) {
221 if (object == null) {
222 throw new NullPointerException(String.format(message, values));
223 }
224 return object;
225 }
226
227 // notEmpty array
228 //---------------------------------------------------------------------------------
229
230 /**
231 * <p>Validate that the specified argument array is neither {@code null}
232 * nor a length of zero (no elements); otherwise throwing an exception
233 * with the specified message.
234 *
235 * <pre>Validate.notEmpty(myArray, "The array must not be empty");</pre>
236 *
237 * @param <T> the array type
238 * @param array the array to check, validated not null by this method
239 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
240 * @param values the optional values for the formatted exception message, null array not recommended
241 * @return the validated array (never {@code null} method for chaining)
242 * @throws NullPointerException if the array is {@code null}
243 * @throws IllegalArgumentException if the array is empty
244 * @see #notEmpty(Object[])
245 */
246 public static <T> T[] notEmpty(T[] array, String message, Object... values) {
247 if (array == null) {
248 throw new NullPointerException(String.format(message, values));
249 }
250 if (array.length == 0) {
251 throw new IllegalArgumentException(String.format(message, values));
252 }
253 return array;
254 }
255
256 /**
257 * <p>Validate that the specified argument array is neither {@code null}
258 * nor a length of zero (no elements); otherwise throwing an exception.
259 *
260 * <pre>Validate.notEmpty(myArray);</pre>
261 *
262 * <p>The message in the exception is &quot;The validated array is
263 * empty&quot;.
264 *
265 * @param <T> the array type
266 * @param array the array to check, validated not null by this method
267 * @return the validated array (never {@code null} method for chaining)
268 * @throws NullPointerException if the array is {@code null}
269 * @throws IllegalArgumentException if the array is empty
270 * @see #notEmpty(Object[], String, Object...)
271 */
272 public static <T> T[] notEmpty(T[] array) {
273 return notEmpty(array, DEFAULT_NOT_EMPTY_ARRAY_EX_MESSAGE);
274 }
275
276 // notEmpty collection
277 //---------------------------------------------------------------------------------
278
279 /**
280 * <p>Validate that the specified argument collection is neither {@code null}
281 * nor a size of zero (no elements); otherwise throwing an exception
282 * with the specified message.
283 *
284 * <pre>Validate.notEmpty(myCollection, "The collection must not be empty");</pre>
285 *
286 * @param <T> the collection type
287 * @param collection the collection to check, validated not null by this method
288 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
289 * @param values the optional values for the formatted exception message, null array not recommended
290 * @return the validated collection (never {@code null} method for chaining)
291 * @throws NullPointerException if the collection is {@code null}
292 * @throws IllegalArgumentException if the collection is empty
293 * @see #notEmpty(Object[])
294 */
295 public static <T extends Collection<?>> T notEmpty(T collection, String message, Object... values) {
296 if (collection == null) {
297 throw new NullPointerException(String.format(message, values));
298 }
299 if (collection.size() == 0) {
300 throw new IllegalArgumentException(String.format(message, values));
301 }
302 return collection;
303 }
304
305 /**
306 * <p>Validate that the specified argument collection is neither {@code null}
307 * nor a size of zero (no elements); otherwise throwing an exception.
308 *
309 * <pre>Validate.notEmpty(myCollection);</pre>
310 *
311 * <p>The message in the exception is &quot;The validated collection is
312 * empty&quot;.</p>
313 *
314 * @param <T> the collection type
315 * @param collection the collection to check, validated not null by this method
316 * @return the validated collection (never {@code null} method for chaining)
317 * @throws NullPointerException if the collection is {@code null}
318 * @throws IllegalArgumentException if the collection is empty
319 * @see #notEmpty(Collection, String, Object...)
320 */
321 public static <T extends Collection<?>> T notEmpty(T collection) {
322 return notEmpty(collection, DEFAULT_NOT_EMPTY_COLLECTION_EX_MESSAGE);
323 }
324
325 // notEmpty map
326 //---------------------------------------------------------------------------------
327
328 /**
329 * <p>Validate that the specified argument map is neither {@code null}
330 * nor a size of zero (no elements); otherwise throwing an exception
331 * with the specified message.
332 *
333 * <pre>Validate.notEmpty(myMap, "The map must not be empty");</pre>
334 *
335 * @param <T> the map type
336 * @param map the map to check, validated not null by this method
337 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
338 * @param values the optional values for the formatted exception message, null array not recommended
339 * @return the validated map (never {@code null} method for chaining)
340 * @throws NullPointerException if the map is {@code null}
341 * @throws IllegalArgumentException if the map is empty
342 * @see #notEmpty(Object[])
343 */
344 public static <T extends Map<?, ?>> T notEmpty(T map, String message, Object... values) {
345 if (map == null) {
346 throw new NullPointerException(String.format(message, values));
347 }
348 if (map.size() == 0) {
349 throw new IllegalArgumentException(String.format(message, values));
350 }
351 return map;
352 }
353
354 /**
355 * <p>Validate that the specified argument map is neither {@code null}
356 * nor a size of zero (no elements); otherwise throwing an exception.
357 *
358 * <pre>Validate.notEmpty(myMap);</pre>
359 *
360 * <p>The message in the exception is &quot;The validated map is
361 * empty&quot;.</p>
362 *
363 * @param <T> the map type
364 * @param map the map to check, validated not null by this method
365 * @return the validated map (never {@code null} method for chaining)
366 * @throws NullPointerException if the map is {@code null}
367 * @throws IllegalArgumentException if the map is empty
368 * @see #notEmpty(Map, String, Object...)
369 */
370 public static <T extends Map<?, ?>> T notEmpty(T map) {
371 return notEmpty(map, DEFAULT_NOT_EMPTY_MAP_EX_MESSAGE);
372 }
373
374 // notEmpty string
375 //---------------------------------------------------------------------------------
376
377 /**
378 * <p>Validate that the specified argument character sequence is
379 * neither {@code null} nor a length of zero (no characters);
380 * otherwise throwing an exception with the specified message.
381 *
382 * <pre>Validate.notEmpty(myString, "The string must not be empty");</pre>
383 *
384 * @param <T> the character sequence type
385 * @param chars the character sequence to check, validated not null by this method
386 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
387 * @param values the optional values for the formatted exception message, null array not recommended
388 * @return the validated character sequence (never {@code null} method for chaining)
389 * @throws NullPointerException if the character sequence is {@code null}
390 * @throws IllegalArgumentException if the character sequence is empty
391 * @see #notEmpty(CharSequence)
392 */
393 public static <T extends CharSequence> T notEmpty(T chars, String message, Object... values) {
394 if (chars == null) {
395 throw new NullPointerException(String.format(message, values));
396 }
397 if (chars.length() == 0) {
398 throw new IllegalArgumentException(String.format(message, values));
399 }
400 return chars;
401 }
402
403 /**
404 * <p>Validate that the specified argument character sequence is
405 * neither {@code null} nor a length of zero (no characters);
406 * otherwise throwing an exception with the specified message.
407 *
408 * <pre>Validate.notEmpty(myString);</pre>
409 *
410 * <p>The message in the exception is &quot;The validated
411 * character sequence is empty&quot;.</p>
412 *
413 * @param <T> the character sequence type
414 * @param chars the character sequence to check, validated not null by this method
415 * @return the validated character sequence (never {@code null} method for chaining)
416 * @throws NullPointerException if the character sequence is {@code null}
417 * @throws IllegalArgumentException if the character sequence is empty
418 * @see #notEmpty(CharSequence, String, Object...)
419 */
420 public static <T extends CharSequence> T notEmpty(T chars) {
421 return notEmpty(chars, DEFAULT_NOT_EMPTY_CHAR_SEQUENCE_EX_MESSAGE);
422 }
423
424 // notBlank string
425 //---------------------------------------------------------------------------------
426
427 /**
428 * <p>Validate that the specified argument character sequence is
429 * neither {@code null}, a length of zero (no characters), empty
430 * nor whitespace; otherwise throwing an exception with the specified
431 * message.
432 *
433 * <pre>Validate.notBlank(myString, "The string must not be blank");</pre>
434 *
435 * @param <T> the character sequence type
436 * @param chars the character sequence to check, validated not null by this method
437 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
438 * @param values the optional values for the formatted exception message, null array not recommended
439 * @return the validated character sequence (never {@code null} method for chaining)
440 * @throws NullPointerException if the character sequence is {@code null}
441 * @throws IllegalArgumentException if the character sequence is blank
442 * @see #notBlank(CharSequence)
443 *
444 * @since 3.0
445 */
446 public static <T extends CharSequence> T notBlank(T chars, String message, Object... values) {
447 if (chars == null) {
448 throw new NullPointerException(String.format(message, values));
449 }
450 if (StringUtils.isBlank(chars)) {
451 throw new IllegalArgumentException(String.format(message, values));
452 }
453 return chars;
454 }
455
456 /**
457 * <p>Validate that the specified argument character sequence is
458 * neither {@code null}, a length of zero (no characters), empty
459 * nor whitespace; otherwise throwing an exception.
460 *
461 * <pre>Validate.notBlank(myString);</pre>
462 *
463 * <p>The message in the exception is &quot;The validated character
464 * sequence is blank&quot;.</p>
465 *
466 * @param <T> the character sequence type
467 * @param chars the character sequence to check, validated not null by this method
468 * @return the validated character sequence (never {@code null} method for chaining)
469 * @throws NullPointerException if the character sequence is {@code null}
470 * @throws IllegalArgumentException if the character sequence is blank
471 * @see #notBlank(CharSequence, String, Object...)
472 *
473 * @since 3.0
474 */
475 public static <T extends CharSequence> T notBlank(T chars) {
476 return notBlank(chars, DEFAULT_NOT_BLANK_EX_MESSAGE);
477 }
478
479 // noNullElements array
480 //---------------------------------------------------------------------------------
481
482 /**
483 * <p>Validate that the specified argument array is neither
484 * {@code null} nor contains any elements that are {@code null};
485 * otherwise throwing an exception with the specified message.
486 *
487 * <pre>Validate.noNullElements(myArray, "The array contain null at position %d");</pre>
488 *
489 * <p>If the array is {@code null}, then the message in the exception
490 * is &quot;The validated object is null&quot;.</p>
491 *
492 * <p>If the array has a {@code null} element, then the iteration
493 * index of the invalid element is appended to the {@code values}
494 * argument.</p>
495 *
496 * @param <T> the array type
497 * @param array the array to check, validated not null by this method
498 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
499 * @param values the optional values for the formatted exception message, null array not recommended
500 * @return the validated array (never {@code null} method for chaining)
501 * @throws NullPointerException if the array is {@code null}
502 * @throws IllegalArgumentException if an element is {@code null}
503 * @see #noNullElements(Object[])
504 */
505 public static <T> T[] noNullElements(T[] array, String message, Object... values) {
506 Validate.notNull(array);
507 for (int i = 0; i < array.length; i++) {
508 if (array[i] == null) {
509 Object[] values2 = ArrayUtils.add(values, Integer.valueOf(i));
510 throw new IllegalArgumentException(String.format(message, values2));
511 }
512 }
513 return array;
514 }
515
516 /**
517 * <p>Validate that the specified argument array is neither
518 * {@code null} nor contains any elements that are {@code null};
519 * otherwise throwing an exception.
520 *
521 * <pre>Validate.noNullElements(myArray);</pre>
522 *
523 * <p>If the array is {@code null}, then the message in the exception
524 * is &quot;The validated object is null&quot;.</p>
525 *
526 * <p>If the array has a {@code null} element, then the message in the
527 * exception is &quot;The validated array contains null element at index:
528 * &quot followed by the index.</p>
529 *
530 * @param <T> the array type
531 * @param array the array to check, validated not null by this method
532 * @return the validated array (never {@code null} method for chaining)
533 * @throws NullPointerException if the array is {@code null}
534 * @throws IllegalArgumentException if an element is {@code null}
535 * @see #noNullElements(Object[], String, Object...)
536 */
537 public static <T> T[] noNullElements(T[] array) {
538 return noNullElements(array, DEFAULT_NO_NULL_ELEMENTS_ARRAY_EX_MESSAGE);
539 }
540
541 // noNullElements iterable
542 //---------------------------------------------------------------------------------
543
544 /**
545 * <p>Validate that the specified argument iterable is neither
546 * {@code null} nor contains any elements that are {@code null};
547 * otherwise throwing an exception with the specified message.
548 *
549 * <pre>Validate.noNullElements(myCollection, "The collection contains null at position %d");</pre>
550 *
551 * <p>If the iterable is {@code null}, then the message in the exception
552 * is &quot;The validated object is null&quot;.</p>
553 *
554 * <p>If the iterable has a {@code null} element, then the iteration
555 * index of the invalid element is appended to the {@code values}
556 * argument.</p>
557 *
558 * @param <T> the iterable type
559 * @param iterable the iterable to check, validated not null by this method
560 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
561 * @param values the optional values for the formatted exception message, null array not recommended
562 * @return the validated iterable (never {@code null} method for chaining)
563 * @throws NullPointerException if the array is {@code null}
564 * @throws IllegalArgumentException if an element is {@code null}
565 * @see #noNullElements(Iterable)
566 */
567 public static <T extends Iterable<?>> T noNullElements(T iterable, String message, Object... values) {
568 Validate.notNull(iterable);
569 int i = 0;
570 for (Iterator<?> it = iterable.iterator(); it.hasNext(); i++) {
571 if (it.next() == null) {
572 Object[] values2 = ArrayUtils.addAll(values, Integer.valueOf(i));
573 throw new IllegalArgumentException(String.format(message, values2));
574 }
575 }
576 return iterable;
577 }
578
579 /**
580 * <p>Validate that the specified argument iterable is neither
581 * {@code null} nor contains any elements that are {@code null};
582 * otherwise throwing an exception.
583 *
584 * <pre>Validate.noNullElements(myCollection);</pre>
585 *
586 * <p>If the iterable is {@code null}, then the message in the exception
587 * is &quot;The validated object is null&quot;.</p>
588 *
589 * <p>If the array has a {@code null} element, then the message in the
590 * exception is &quot;The validated iterable contains null element at index:
591 * &quot followed by the index.</p>
592 *
593 * @param <T> the iterable type
594 * @param iterable the iterable to check, validated not null by this method
595 * @return the validated iterable (never {@code null} method for chaining)
596 * @throws NullPointerException if the array is {@code null}
597 * @throws IllegalArgumentException if an element is {@code null}
598 * @see #noNullElements(Iterable, String, Object...)
599 */
600 public static <T extends Iterable<?>> T noNullElements(T iterable) {
601 return noNullElements(iterable, DEFAULT_NO_NULL_ELEMENTS_COLLECTION_EX_MESSAGE);
602 }
603
604 // validIndex array
605 //---------------------------------------------------------------------------------
606
607 /**
608 * <p>Validates that the index is within the bounds of the argument
609 * array; otherwise throwing an exception with the specified message.</p>
610 *
611 * <pre>Validate.validIndex(myArray, 2, "The array index is invalid: ");</pre>
612 *
613 * <p>If the array is {@code null}, then the message of the exception
614 * is &quot;The validated object is null&quot;.</p>
615 *
616 * @param <T> the array type
617 * @param array the array to check, validated not null by this method
618 * @param index the index to check
619 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
620 * @param values the optional values for the formatted exception message, null array not recommended
621 * @return the validated array (never {@code null} for method chaining)
622 * @throws NullPointerException if the array is {@code null}
623 * @throws IndexOutOfBoundsException if the index is invalid
624 * @see #validIndex(Object[], int)
625 *
626 * @since 3.0
627 */
628 public static <T> T[] validIndex(T[] array, int index, String message, Object... values) {
629 Validate.notNull(array);
630 if (index < 0 || index >= array.length) {
631 throw new IndexOutOfBoundsException(String.format(message, values));
632 }
633 return array;
634 }
635
636 /**
637 * <p>Validates that the index is within the bounds of the argument
638 * array; otherwise throwing an exception.</p>
639 *
640 * <pre>Validate.validIndex(myArray, 2);</pre>
641 *
642 * <p>If the array is {@code null}, then the message of the exception
643 * is &quot;The validated object is null&quot;.</p>
644 *
645 * <p>If the index is invalid, then the message of the exception is
646 * &quot;The validated array index is invalid: &quot; followed by the
647 * index.</p>
648 *
649 * @param <T> the array type
650 * @param array the array to check, validated not null by this method
651 * @param index the index to check
652 * @return the validated array (never {@code null} for method chaining)
653 * @throws NullPointerException if the array is {@code null}
654 * @throws IndexOutOfBoundsException if the index is invalid
655 * @see #validIndex(Object[], int, String, Object...)
656 *
657 * @since 3.0
658 */
659 public static <T> T[] validIndex(T[] array, int index) {
660 return validIndex(array, index, DEFAULT_VALID_INDEX_ARRAY_EX_MESSAGE, Integer.valueOf(index));
661 }
662
663 // validIndex collection
664 //---------------------------------------------------------------------------------
665
666 /**
667 * <p>Validates that the index is within the bounds of the argument
668 * collection; otherwise throwing an exception with the specified message.</p>
669 *
670 * <pre>Validate.validIndex(myCollection, 2, "The collection index is invalid: ");</pre>
671 *
672 * <p>If the collection is {@code null}, then the message of the
673 * exception is &quot;The validated object is null&quot;.</p>
674 *
675 * @param <T> the collection type
676 * @param collection the collection to check, validated not null by this method
677 * @param index the index to check
678 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
679 * @param values the optional values for the formatted exception message, null array not recommended
680 * @return the validated collection (never {@code null} for chaining)
681 * @throws NullPointerException if the collection is {@code null}
682 * @throws IndexOutOfBoundsException if the index is invalid
683 * @see #validIndex(Collection, int)
684 *
685 * @since 3.0
686 */
687 public static <T extends Collection<?>> T validIndex(T collection, int index, String message, Object... values) {
688 Validate.notNull(collection);
689 if (index < 0 || index >= collection.size()) {
690 throw new IndexOutOfBoundsException(String.format(message, values));
691 }
692 return collection;
693 }
694
695 /**
696 * <p>Validates that the index is within the bounds of the argument
697 * collection; otherwise throwing an exception.</p>
698 *
699 * <pre>Validate.validIndex(myCollection, 2);</pre>
700 *
701 * <p>If the index is invalid, then the message of the exception
702 * is &quot;The validated collection index is invalid: &quot;
703 * followed by the index.</p>
704 *
705 * @param <T> the collection type
706 * @param collection the collection to check, validated not null by this method
707 * @param index the index to check
708 * @return the validated collection (never {@code null} for method chaining)
709 * @throws NullPointerException if the collection is {@code null}
710 * @throws IndexOutOfBoundsException if the index is invalid
711 * @see #validIndex(Collection, int, String, Object...)
712 *
713 * @since 3.0
714 */
715 public static <T extends Collection<?>> T validIndex(T collection, int index) {
716 return validIndex(collection, index, DEFAULT_VALID_INDEX_COLLECTION_EX_MESSAGE, Integer.valueOf(index));
717 }
718
719 // validIndex string
720 //---------------------------------------------------------------------------------
721
722 /**
723 * <p>Validates that the index is within the bounds of the argument
724 * character sequence; otherwise throwing an exception with the
725 * specified message.</p>
726 *
727 * <pre>Validate.validIndex(myStr, 2, "The string index is invalid: ");</pre>
728 *
729 * <p>If the character sequence is {@code null}, then the message
730 * of the exception is &quot;The validated object is null&quot;.</p>
731 *
732 * @param <T> the character sequence type
733 * @param chars the character sequence to check, validated not null by this method
734 * @param index the index to check
735 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
736 * @param values the optional values for the formatted exception message, null array not recommended
737 * @return the validated character sequence (never {@code null} for method chaining)
738 * @throws NullPointerException if the character sequence is {@code null}
739 * @throws IndexOutOfBoundsException if the index is invalid
740 * @see #validIndex(CharSequence, int)
741 *
742 * @since 3.0
743 */
744 public static <T extends CharSequence> T validIndex(T chars, int index, String message, Object... values) {
745 Validate.notNull(chars);
746 if (index < 0 || index >= chars.length()) {
747 throw new IndexOutOfBoundsException(String.format(message, values));
748 }
749 return chars;
750 }
751
752 /**
753 * <p>Validates that the index is within the bounds of the argument
754 * character sequence; otherwise throwing an exception.</p>
755 *
756 * <pre>Validate.validIndex(myStr, 2);</pre>
757 *
758 * <p>If the character sequence is {@code null}, then the message
759 * of the exception is &quot;The validated object is
760 * null&quot;.</p>
761 *
762 * <p>If the index is invalid, then the message of the exception
763 * is &quot;The validated character sequence index is invalid: &quot;
764 * followed by the index.</p>
765 *
766 * @param <T> the character sequence type
767 * @param chars the character sequence to check, validated not null by this method
768 * @param index the index to check
769 * @return the validated character sequence (never {@code null} for method chaining)
770 * @throws NullPointerException if the character sequence is {@code null}
771 * @throws IndexOutOfBoundsException if the index is invalid
772 * @see #validIndex(CharSequence, int, String, Object...)
773 *
774 * @since 3.0
775 */
776 public static <T extends CharSequence> T validIndex(T chars, int index) {
777 return validIndex(chars, index, DEFAULT_VALID_INDEX_CHAR_SEQUENCE_EX_MESSAGE, Integer.valueOf(index));
778 }
779
780 // validState
781 //---------------------------------------------------------------------------------
782
783 /**
784 * <p>Validate that the stateful condition is {@code true}; otherwise
785 * throwing an exception. This method is useful when validating according
786 * to an arbitrary boolean expression, such as validating a
787 * primitive number or using your own custom validation expression.</p>
788 *
789 * <pre>
790 * Validate.validState(field > 0);
791 * Validate.validState(this.isOk());</pre>
792 *
793 * <p>The message of the exception is &quot;The validated state is
794 * false&quot;.</p>
795 *
796 * @param expression the boolean expression to check
797 * @throws IllegalStateException if expression is {@code false}
798 * @see #validState(boolean, String, Object...)
799 *
800 * @since 3.0
801 */
802 public static void validState(boolean expression) {
803 if (expression == false) {
804 throw new IllegalStateException(DEFAULT_VALID_STATE_EX_MESSAGE);
805 }
806 }
807
808 /**
809 * <p>Validate that the stateful condition is {@code true}; otherwise
810 * throwing an exception with the specified message. This method is useful when
811 * validating according to an arbitrary boolean expression, such as validating a
812 * primitive number or using your own custom validation expression.</p>
813 *
814 * <pre>Validate.validState(this.isOk(), "The state is not OK: %s", myObject);</pre>
815 *
816 * @param expression the boolean expression to check
817 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
818 * @param values the optional values for the formatted exception message, null array not recommended
819 * @throws IllegalStateException if expression is {@code false}
820 * @see #validState(boolean)
821 *
822 * @since 3.0
823 */
824 public static void validState(boolean expression, String message, Object... values) {
825 if (expression == false) {
826 throw new IllegalStateException(String.format(message, values));
827 }
828 }
829
830 // matchesPattern
831 //---------------------------------------------------------------------------------
832
833 /**
834 * <p>Validate that the specified argument character sequence matches the specified regular
835 * expression pattern; otherwise throwing an exception.</p>
836 *
837 * <pre>Validate.matchesPattern("hi", "[a-z]*");</pre>
838 *
839 * <p>The syntax of the pattern is the one used in the {@link Pattern} class.</p>
840 *
841 * @param input the character sequence to validate, not null
842 * @param pattern the regular expression pattern, not null
843 * @throws IllegalArgumentException if the character sequence does not match the pattern
844 * @see #matchesPattern(CharSequence, String, String, Object...)
845 *
846 * @since 3.0
847 */
848 public static void matchesPattern(CharSequence input, String pattern) {
849 if (Pattern.matches(pattern, input) == false) {
850 throw new IllegalArgumentException(String.format(DEFAULT_MATCHES_PATTERN_EX, input, pattern));
851 }
852 }
853
854 /**
855 * <p>Validate that the specified argument character sequence matches the specified regular
856 * expression pattern; otherwise throwing an exception with the specified message.</p>
857 *
858 * <pre>Validate.matchesPattern("hi", "[a-z]*", "%s does not match %s", "hi" "[a-z]*");</pre>
859 *
860 * <p>The syntax of the pattern is the one used in the {@link Pattern} class.</p>
861 *
862 * @param input the character sequence to validate, not null
863 * @param pattern the regular expression pattern, not null
864 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
865 * @param values the optional values for the formatted exception message, null array not recommended
866 * @throws IllegalArgumentException if the character sequence does not match the pattern
867 * @see #matchesPattern(CharSequence, String)
868 *
869 * @since 3.0
870 */
871 public static void matchesPattern(CharSequence input, String pattern, String message, Object... values) {
872 if (Pattern.matches(pattern, input) == false) {
873 throw new IllegalArgumentException(String.format(message, values));
874 }
875 }
876
877 // inclusiveBetween
878 //---------------------------------------------------------------------------------
879
880 /**
881 * <p>Validate that the specified argument object fall between the two
882 * inclusive values specified; otherwise, throws an exception.</p>
883 *
884 * <pre>Validate.inclusiveBetween(0, 2, 1);</pre>
885 *
886 * @param <T> the type of the argument object
887 * @param start the inclusive start value, not null
888 * @param end the inclusive end value, not null
889 * @param value the object to validate, not null
890 * @throws IllegalArgumentException if the value falls out of the boundaries
891 * @see #inclusiveBetween(Object, Object, Comparable, String, Object...)
892 *
893 * @since 3.0
894 */
895 public static <T> void inclusiveBetween(T start, T end, Comparable<T> value) {
896 if (value.compareTo(start) < 0 || value.compareTo(end) > 0) {
897 throw new IllegalArgumentException(String.format(DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end));
898 }
899 }
900
901 /**
902 * <p>Validate that the specified argument object fall between the two
903 * inclusive values specified; otherwise, throws an exception with the
904 * specified message.</p>
905 *
906 * <pre>Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");</pre>
907 *
908 * @param <T> the type of the argument object
909 * @param start the inclusive start value, not null
910 * @param end the inclusive end value, not null
911 * @param value the object to validate, not null
912 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
913 * @param values the optional values for the formatted exception message, null array not recommended
914 * @throws IllegalArgumentException if the value falls out of the boundaries
915 * @see #inclusiveBetween(Object, Object, Comparable)
916 *
917 * @since 3.0
918 */
919 public static <T> void inclusiveBetween(T start, T end, Comparable<T> value, String message, Object... values) {
920 if (value.compareTo(start) < 0 || value.compareTo(end) > 0) {
921 throw new IllegalArgumentException(String.format(message, values));
922 }
923 }
924
925 // exclusiveBetween
926 //---------------------------------------------------------------------------------
927
928 /**
929 * <p>Validate that the specified argument object fall between the two
930 * exclusive values specified; otherwise, throws an exception.</p>
931 *
932 * <pre>Validate.inclusiveBetween(0, 2, 1);</pre>
933 *
934 * @param <T> the type of the argument object
935 * @param start the exclusive start value, not null
936 * @param end the exclusive end value, not null
937 * @param value the object to validate, not null
938 * @throws IllegalArgumentException if the value falls out of the boundaries
939 * @see #exclusiveBetween(Object, Object, Comparable, String, Object...)
940 *
941 * @since 3.0
942 */
943 public static <T> void exclusiveBetween(T start, T end, Comparable<T> value) {
944 if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) {
945 throw new IllegalArgumentException(String.format(DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end));
946 }
947 }
948
949 /**
950 * <p>Validate that the specified argument object fall between the two
951 * exclusive values specified; otherwise, throws an exception with the
952 * specified message.</p>
953 *
954 * <pre>Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");</pre>
955 *
956 * @param <T> the type of the argument object
957 * @param start the exclusive start value, not null
958 * @param end the exclusive end value, not null
959 * @param value the object to validate, not null
960 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
961 * @param values the optional values for the formatted exception message, null array not recommended
962 * @throws IllegalArgumentException if the value falls out of the boundaries
963 * @see #exclusiveBetween(Object, Object, Comparable)
964 *
965 * @since 3.0
966 */
967 public static <T> void exclusiveBetween(T start, T end, Comparable<T> value, String message, Object... values) {
968 if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) {
969 throw new IllegalArgumentException(String.format(message, values));
970 }
971 }
972
973 // isInstanceOf
974 //---------------------------------------------------------------------------------
975
976 /**
977 * <p>Validate that the argument is an instance of the specified class; otherwise
978 * throwing an exception. This method is useful when validating according to an arbitrary
979 * class</p>
980 *
981 * <pre>Validate.isInstanceOf(OkClass.class, object);</pre>
982 *
983 * <p>The message of the exception is &quot;The validated object is not an instance of&quot;
984 * followed by the name of the class</p>
985 *
986 * @param type the class the object must be validated against, not null
987 * @param obj the object to check, null throws an exception
988 * @throws IllegalArgumentException if argument is not of specified class
989 * @see #isInstanceOf(Class, Object, String, Object...)
990 *
991 * @since 3.0
992 */
993 public static void isInstanceOf(Class<?> type, Object obj) {
994 if (type.isInstance(obj) == false) {
995 throw new IllegalArgumentException(String.format(DEFAULT_IS_INSTANCE_OF_EX_MESSAGE, type.getName()));
996 }
997 }
998
999 /**
1000 * <p>Validate that the argument is an instance of the specified class; otherwise
1001 * throwing an exception with the specified message. This method is useful when
1002 * validating according to an arbitrary class</p>
1003 *
1004 * <pre>Validate.isInstanceOf(OkClass.classs, object, "Wrong class, object is of class %s",
1005 * object.getClass().getName());</pre>
1006 *
1007 * @param type the class the object must be validated against, not null
1008 * @param obj the object to check, null throws an exception
1009 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
1010 * @param values the optional values for the formatted exception message, null array not recommended
1011 * @throws IllegalArgumentException if argument is not of specified class
1012 * @see #isInstanceOf(Class, Object)
1013 *
1014 * @since 3.0
1015 */
1016 public static void isInstanceOf(Class<?> type, Object obj, String message, Object... values) {
1017 if (type.isInstance(obj) == false) {
1018 throw new IllegalArgumentException(String.format(message, values));
1019 }
1020 }
1021
1022 // isAssignableFrom
1023 //---------------------------------------------------------------------------------
1024
1025 /**
1026 * <p>Validate that the argument can be converted to the specified class; otherwise
1027 * throwing an exception with the specified message. This method is useful when
1028 * validating if there will be no casting errors.</p>
1029 *
1030 * <pre>Validate.isAssignableFrom(SuperClass.class, object.getClass());</pre>
1031 *
1032 * <p>The message of the exception is &quot;The validated object can not be converted to the&quot;
1033 * followed by the name of the class and &quot;class&quot;</p>
1034 *
1035 * @param superType the class the class must be validated against, not null
1036 * @param type the class to check, not null
1037 * @throws IllegalArgumentException if argument can not be converted to the specified class
1038 * @see #isAssignableFrom(Class, Class, String, Object...)
1039 *
1040 * @since 3.0
1041 */
1042 public static void isAssignableFrom(Class<?> superType, Class<?> type) {
1043 if (superType.isAssignableFrom(type) == false) {
1044 throw new IllegalArgumentException(String.format(DEFAULT_IS_ASSIGNABLE_EX_MESSAGE, superType.getName()));
1045 }
1046 }
1047
1048 /**
1049 * <p>Validate that the argument can be converted to the specified class; otherwise
1050 * throwing an exception. This method is useful when validating if there will be no
1051 * casting errors.</p>
1052 *
1053 * <pre>Validate.isAssignableFrom(SuperClass.class, object.getClass());</pre>
1054 *
1055 * <p>The message of the exception is &quot;The validated object can not be converted to the&quot;
1056 * followed by the name of the class and &quot;class&quot;</p>
1057 *
1058 * @param superType the class the class must be validated against, not null
1059 * @param type the class to check, not null
1060 * @param message the {@link String#format(String, Object...)} exception message if invalid, not null
1061 * @param values the optional values for the formatted exception message, null array not recommended
1062 * @throws IllegalArgumentException if argument can not be converted to the specified class
1063 * @see #isAssignableFrom(Class, Class)
1064 */
1065 public static void isAssignableFrom(Class<?> superType, Class<?> type, String message, Object... values) {
1066 if (superType.isAssignableFrom(type) == false) {
1067 throw new IllegalArgumentException(String.format(message, values));
1068 }
1069 }
1070 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 /**
19 * <p>
20 * The Builder interface is designed to designate a class as a <em>builder</em>
21 * object in the Builder design pattern. Builders are capable of creating and
22 * configuring objects or results that normally take multiple steps to construct
23 * or are very complex to derive.
24 * </p>
25 *
26 * <p>
27 * The builder interface defines a single method, {@link #build()}, that
28 * classes must implement. The result of this method should be the final
29 * configured object or result after all building operations are performed.
30 * </p>
31 *
32 * <p>
33 * It is a recommended practice that the methods supplied to configure the
34 * object or result being built return a reference to {@code this} so that
35 * method calls can be chained together.
36 * </p>
37 *
38 * <p>
39 * Example Builder:
40 * <code><pre>
41 * class FontBuilder implements Builder&lt;Font&gt; {
42 * private Font font;
43 *
44 * public FontBuilder(String fontName) {
45 * this.font = new Font(fontName, Font.PLAIN, 12);
46 * }
47 *
48 * public FontBuilder bold() {
49 * this.font = this.font.deriveFont(Font.BOLD);
50 * return this; // Reference returned so calls can be chained
51 * }
52 *
53 * public FontBuilder size(float pointSize) {
54 * this.font = this.font.deriveFont(pointSize);
55 * return this; // Reference returned so calls can be chained
56 * }
57 *
58 * // Other Font construction methods
59 *
60 * public Font build() {
61 * return this.font;
62 * }
63 * }
64 * </pre></code>
65 *
66 * Example Builder Usage:
67 * <code><pre>
68 * Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
69 * .size(14.0f)
70 * .build();
71 * </pre></code>
72 * </p>
73 *
74 * @param <T> the type of object that the builder will construct or compute.
75 *
76 * @since 3.0
77 * @version $Id: Builder.java 1088899 2011-04-05 05:31:27Z bayard $
78 */
79 public interface Builder<T> {
80
81 /**
82 * Returns a reference to the object being constructed or result being
83 * calculated by the builder.
84 *
85 * @return the object constructed or result calculated by the builder.
86 */
87 public T build();
88 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.lang.reflect.AccessibleObject;
19 import java.lang.reflect.Field;
20 import java.lang.reflect.Modifier;
21 import java.util.Collection;
22 import java.util.Comparator;
23
24 import org.apache.commons.lang3.ArrayUtils;
25
26 /**
27 * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods.
28 *
29 * It is consistent with <code>equals(Object)</code> and
30 * <code>hashcode()</code> built with {@link EqualsBuilder} and
31 * {@link HashCodeBuilder}.</p>
32 *
33 * <p>Two Objects that compare equal using <code>equals(Object)</code> should normally
34 * also compare equal using <code>compareTo(Object)</code>.</p>
35 *
36 * <p>All relevant fields should be included in the calculation of the
37 * comparison. Derived fields may be ignored. The same fields, in the same
38 * order, should be used in both <code>compareTo(Object)</code> and
39 * <code>equals(Object)</code>.</p>
40 *
41 * <p>To use this class write code as follows:</p>
42 *
43 * <pre>
44 * public class MyClass {
45 * String field1;
46 * int field2;
47 * boolean field3;
48 *
49 * ...
50 *
51 * public int compareTo(Object o) {
52 * MyClass myClass = (MyClass) o;
53 * return new CompareToBuilder()
54 * .appendSuper(super.compareTo(o)
55 * .append(this.field1, myClass.field1)
56 * .append(this.field2, myClass.field2)
57 * .append(this.field3, myClass.field3)
58 * .toComparison();
59 * }
60 * }
61 * </pre>
62 *
63 * <p>Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use
64 * reflection to determine the fields to append. Because fields can be private,
65 * <code>reflectionCompare</code> uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to
66 * bypass normal access control checks. This will fail under a security manager,
67 * unless the appropriate permissions are set up correctly. It is also
68 * slower than appending explicitly.</p>
69 *
70 * <p>A typical implementation of <code>compareTo(Object)</code> using
71 * <code>reflectionCompare</code> looks like:</p>
72
73 * <pre>
74 * public int compareTo(Object o) {
75 * return CompareToBuilder.reflectionCompare(this, o);
76 * }
77 * </pre>
78 *
79 * @see java.lang.Comparable
80 * @see java.lang.Object#equals(Object)
81 * @see java.lang.Object#hashCode()
82 * @see EqualsBuilder
83 * @see HashCodeBuilder
84 * @since 1.0
85 * @version $Id: CompareToBuilder.java 1090813 2011-04-10 15:03:23Z mbenson $
86 */
87 public class CompareToBuilder implements Builder<Integer> {
88
89 /**
90 * Current state of the comparison as appended fields are checked.
91 */
92 private int comparison;
93
94 /**
95 * <p>Constructor for CompareToBuilder.</p>
96 *
97 * <p>Starts off assuming that the objects are equal. Multiple calls are
98 * then made to the various append methods, followed by a call to
99 * {@link #toComparison} to get the result.</p>
100 */
101 public CompareToBuilder() {
102 super();
103 comparison = 0;
104 }
105
106 //-----------------------------------------------------------------------
107 /**
108 * <p>Compares two <code>Object</code>s via reflection.</p>
109 *
110 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
111 * is used to bypass normal access control checks. This will fail under a
112 * security manager unless the appropriate permissions are set.</p>
113 *
114 * <ul>
115 * <li>Static fields will not be compared</li>
116 * <li>Transient members will be not be compared, as they are likely derived
117 * fields</li>
118 * <li>Superclass fields will be compared</li>
119 * </ul>
120 *
121 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
122 * they are considered equal.</p>
123 *
124 * @param lhs left-hand object
125 * @param rhs right-hand object
126 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
127 * is less than, equal to, or greater than <code>rhs</code>
128 * @throws NullPointerException if either (but not both) parameters are
129 * <code>null</code>
130 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
131 * with <code>lhs</code>
132 */
133 public static int reflectionCompare(Object lhs, Object rhs) {
134 return reflectionCompare(lhs, rhs, false, null);
135 }
136
137 /**
138 * <p>Compares two <code>Object</code>s via reflection.</p>
139 *
140 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
141 * is used to bypass normal access control checks. This will fail under a
142 * security manager unless the appropriate permissions are set.</p>
143 *
144 * <ul>
145 * <li>Static fields will not be compared</li>
146 * <li>If <code>compareTransients</code> is <code>true</code>,
147 * compares transient members. Otherwise ignores them, as they
148 * are likely derived fields.</li>
149 * <li>Superclass fields will be compared</li>
150 * </ul>
151 *
152 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
153 * they are considered equal.</p>
154 *
155 * @param lhs left-hand object
156 * @param rhs right-hand object
157 * @param compareTransients whether to compare transient fields
158 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
159 * is less than, equal to, or greater than <code>rhs</code>
160 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
161 * (but not both) is <code>null</code>
162 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
163 * with <code>lhs</code>
164 */
165 public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients) {
166 return reflectionCompare(lhs, rhs, compareTransients, null);
167 }
168
169 /**
170 * <p>Compares two <code>Object</code>s via reflection.</p>
171 *
172 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
173 * is used to bypass normal access control checks. This will fail under a
174 * security manager unless the appropriate permissions are set.</p>
175 *
176 * <ul>
177 * <li>Static fields will not be compared</li>
178 * <li>If <code>compareTransients</code> is <code>true</code>,
179 * compares transient members. Otherwise ignores them, as they
180 * are likely derived fields.</li>
181 * <li>Superclass fields will be compared</li>
182 * </ul>
183 *
184 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
185 * they are considered equal.</p>
186 *
187 * @param lhs left-hand object
188 * @param rhs right-hand object
189 * @param excludeFields Collection of String fields to exclude
190 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
191 * is less than, equal to, or greater than <code>rhs</code>
192 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
193 * (but not both) is <code>null</code>
194 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
195 * with <code>lhs</code>
196 * @since 2.2
197 */
198 public static int reflectionCompare(Object lhs, Object rhs, Collection<String> excludeFields) {
199 return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
200 }
201
202 /**
203 * <p>Compares two <code>Object</code>s via reflection.</p>
204 *
205 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
206 * is used to bypass normal access control checks. This will fail under a
207 * security manager unless the appropriate permissions are set.</p>
208 *
209 * <ul>
210 * <li>Static fields will not be compared</li>
211 * <li>If <code>compareTransients</code> is <code>true</code>,
212 * compares transient members. Otherwise ignores them, as they
213 * are likely derived fields.</li>
214 * <li>Superclass fields will be compared</li>
215 * </ul>
216 *
217 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
218 * they are considered equal.</p>
219 *
220 * @param lhs left-hand object
221 * @param rhs right-hand object
222 * @param excludeFields array of fields to exclude
223 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
224 * is less than, equal to, or greater than <code>rhs</code>
225 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
226 * (but not both) is <code>null</code>
227 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
228 * with <code>lhs</code>
229 * @since 2.2
230 */
231 public static int reflectionCompare(Object lhs, Object rhs, String... excludeFields) {
232 return reflectionCompare(lhs, rhs, false, null, excludeFields);
233 }
234
235 /**
236 * <p>Compares two <code>Object</code>s via reflection.</p>
237 *
238 * <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
239 * is used to bypass normal access control checks. This will fail under a
240 * security manager unless the appropriate permissions are set.</p>
241 *
242 * <ul>
243 * <li>Static fields will not be compared</li>
244 * <li>If the <code>compareTransients</code> is <code>true</code>,
245 * compares transient members. Otherwise ignores them, as they
246 * are likely derived fields.</li>
247 * <li>Compares superclass fields up to and including <code>reflectUpToClass</code>.
248 * If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
249 * </ul>
250 *
251 * <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
252 * they are considered equal.</p>
253 *
254 * @param lhs left-hand object
255 * @param rhs right-hand object
256 * @param compareTransients whether to compare transient fields
257 * @param reflectUpToClass last superclass for which fields are compared
258 * @param excludeFields fields to exclude
259 * @return a negative integer, zero, or a positive integer as <code>lhs</code>
260 * is less than, equal to, or greater than <code>rhs</code>
261 * @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
262 * (but not both) is <code>null</code>
263 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
264 * with <code>lhs</code>
265 * @since 2.2 (2.0 as <code>reflectionCompare(Object, Object, boolean, Class)</code>)
266 */
267 public static int reflectionCompare(
268 Object lhs,
269 Object rhs,
270 boolean compareTransients,
271 Class<?> reflectUpToClass,
272 String... excludeFields) {
273
274 if (lhs == rhs) {
275 return 0;
276 }
277 if (lhs == null || rhs == null) {
278 throw new NullPointerException();
279 }
280 Class<?> lhsClazz = lhs.getClass();
281 if (!lhsClazz.isInstance(rhs)) {
282 throw new ClassCastException();
283 }
284 CompareToBuilder compareToBuilder = new CompareToBuilder();
285 reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
286 while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) {
287 lhsClazz = lhsClazz.getSuperclass();
288 reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
289 }
290 return compareToBuilder.toComparison();
291 }
292
293 /**
294 * <p>Appends to <code>builder</code> the comparison of <code>lhs</code>
295 * to <code>rhs</code> using the fields defined in <code>clazz</code>.</p>
296 *
297 * @param lhs left-hand object
298 * @param rhs right-hand object
299 * @param clazz <code>Class</code> that defines fields to be compared
300 * @param builder <code>CompareToBuilder</code> to append to
301 * @param useTransients whether to compare transient fields
302 * @param excludeFields fields to exclude
303 */
304 private static void reflectionAppend(
305 Object lhs,
306 Object rhs,
307 Class<?> clazz,
308 CompareToBuilder builder,
309 boolean useTransients,
310 String[] excludeFields) {
311
312 Field[] fields = clazz.getDeclaredFields();
313 AccessibleObject.setAccessible(fields, true);
314 for (int i = 0; i < fields.length && builder.comparison == 0; i++) {
315 Field f = fields[i];
316 if (!ArrayUtils.contains(excludeFields, f.getName())
317 && (f.getName().indexOf('$') == -1)
318 && (useTransients || !Modifier.isTransient(f.getModifiers()))
319 && (!Modifier.isStatic(f.getModifiers()))) {
320 try {
321 builder.append(f.get(lhs), f.get(rhs));
322 } catch (IllegalAccessException e) {
323 // This can't happen. Would get a Security exception instead.
324 // Throw a runtime exception in case the impossible happens.
325 throw new InternalError("Unexpected IllegalAccessException");
326 }
327 }
328 }
329 }
330
331 //-----------------------------------------------------------------------
332 /**
333 * <p>Appends to the <code>builder</code> the <code>compareTo(Object)</code>
334 * result of the superclass.</p>
335 *
336 * @param superCompareTo result of calling <code>super.compareTo(Object)</code>
337 * @return this - used to chain append calls
338 * @since 2.0
339 */
340 public CompareToBuilder appendSuper(int superCompareTo) {
341 if (comparison != 0) {
342 return this;
343 }
344 comparison = superCompareTo;
345 return this;
346 }
347
348 //-----------------------------------------------------------------------
349 /**
350 * <p>Appends to the <code>builder</code> the comparison of
351 * two <code>Object</code>s.</p>
352 *
353 * <ol>
354 * <li>Check if <code>lhs == rhs</code></li>
355 * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
356 * a <code>null</code> object is less than a non-<code>null</code> object</li>
357 * <li>Check the object contents</li>
358 * </ol>
359 *
360 * <p><code>lhs</code> must either be an array or implement {@link Comparable}.</p>
361 *
362 * @param lhs left-hand object
363 * @param rhs right-hand object
364 * @return this - used to chain append calls
365 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
366 * with <code>lhs</code>
367 */
368 public CompareToBuilder append(Object lhs, Object rhs) {
369 return append(lhs, rhs, null);
370 }
371
372 /**
373 * <p>Appends to the <code>builder</code> the comparison of
374 * two <code>Object</code>s.</p>
375 *
376 * <ol>
377 * <li>Check if <code>lhs == rhs</code></li>
378 * <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
379 * a <code>null</code> object is less than a non-<code>null</code> object</li>
380 * <li>Check the object contents</li>
381 * </ol>
382 *
383 * <p>If <code>lhs</code> is an array, array comparison methods will be used.
384 * Otherwise <code>comparator</code> will be used to compare the objects.
385 * If <code>comparator</code> is <code>null</code>, <code>lhs</code> must
386 * implement {@link Comparable} instead.</p>
387 *
388 * @param lhs left-hand object
389 * @param rhs right-hand object
390 * @param comparator <code>Comparator</code> used to compare the objects,
391 * <code>null</code> means treat lhs as <code>Comparable</code>
392 * @return this - used to chain append calls
393 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
394 * with <code>lhs</code>
395 * @since 2.0
396 */
397 public CompareToBuilder append(Object lhs, Object rhs, Comparator<?> comparator) {
398 if (comparison != 0) {
399 return this;
400 }
401 if (lhs == rhs) {
402 return this;
403 }
404 if (lhs == null) {
405 comparison = -1;
406 return this;
407 }
408 if (rhs == null) {
409 comparison = +1;
410 return this;
411 }
412 if (lhs.getClass().isArray()) {
413 // switch on type of array, to dispatch to the correct handler
414 // handles multi dimensional arrays
415 // throws a ClassCastException if rhs is not the correct array type
416 if (lhs instanceof long[]) {
417 append((long[]) lhs, (long[]) rhs);
418 } else if (lhs instanceof int[]) {
419 append((int[]) lhs, (int[]) rhs);
420 } else if (lhs instanceof short[]) {
421 append((short[]) lhs, (short[]) rhs);
422 } else if (lhs instanceof char[]) {
423 append((char[]) lhs, (char[]) rhs);
424 } else if (lhs instanceof byte[]) {
425 append((byte[]) lhs, (byte[]) rhs);
426 } else if (lhs instanceof double[]) {
427 append((double[]) lhs, (double[]) rhs);
428 } else if (lhs instanceof float[]) {
429 append((float[]) lhs, (float[]) rhs);
430 } else if (lhs instanceof boolean[]) {
431 append((boolean[]) lhs, (boolean[]) rhs);
432 } else {
433 // not an array of primitives
434 // throws a ClassCastException if rhs is not an array
435 append((Object[]) lhs, (Object[]) rhs, comparator);
436 }
437 } else {
438 // the simple case, not an array, just test the element
439 if (comparator == null) {
440 @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
441 final Comparable<Object> comparable = (Comparable<Object>) lhs;
442 comparison = comparable.compareTo(rhs);
443 } else {
444 @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
445 final Comparator<Object> comparator2 = (Comparator<Object>) comparator;
446 comparison = comparator2.compare(lhs, rhs);
447 }
448 }
449 return this;
450 }
451
452 //-------------------------------------------------------------------------
453 /**
454 * Appends to the <code>builder</code> the comparison of
455 * two <code>long</code>s.
456 *
457 * @param lhs left-hand value
458 * @param rhs right-hand value
459 * @return this - used to chain append calls
460 */
461 public CompareToBuilder append(long lhs, long rhs) {
462 if (comparison != 0) {
463 return this;
464 }
465 comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
466 return this;
467 }
468
469 /**
470 * Appends to the <code>builder</code> the comparison of
471 * two <code>int</code>s.
472 *
473 * @param lhs left-hand value
474 * @param rhs right-hand value
475 * @return this - used to chain append calls
476 */
477 public CompareToBuilder append(int lhs, int rhs) {
478 if (comparison != 0) {
479 return this;
480 }
481 comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
482 return this;
483 }
484
485 /**
486 * Appends to the <code>builder</code> the comparison of
487 * two <code>short</code>s.
488 *
489 * @param lhs left-hand value
490 * @param rhs right-hand value
491 * @return this - used to chain append calls
492 */
493 public CompareToBuilder append(short lhs, short rhs) {
494 if (comparison != 0) {
495 return this;
496 }
497 comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
498 return this;
499 }
500
501 /**
502 * Appends to the <code>builder</code> the comparison of
503 * two <code>char</code>s.
504 *
505 * @param lhs left-hand value
506 * @param rhs right-hand value
507 * @return this - used to chain append calls
508 */
509 public CompareToBuilder append(char lhs, char rhs) {
510 if (comparison != 0) {
511 return this;
512 }
513 comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
514 return this;
515 }
516
517 /**
518 * Appends to the <code>builder</code> the comparison of
519 * two <code>byte</code>s.
520 *
521 * @param lhs left-hand value
522 * @param rhs right-hand value
523 * @return this - used to chain append calls
524 */
525 public CompareToBuilder append(byte lhs, byte rhs) {
526 if (comparison != 0) {
527 return this;
528 }
529 comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
530 return this;
531 }
532
533 /**
534 * <p>Appends to the <code>builder</code> the comparison of
535 * two <code>double</code>s.</p>
536 *
537 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
538 *
539 * <p>It is compatible with the hash code generated by
540 * <code>HashCodeBuilder</code>.</p>
541 *
542 * @param lhs left-hand value
543 * @param rhs right-hand value
544 * @return this - used to chain append calls
545 */
546 public CompareToBuilder append(double lhs, double rhs) {
547 if (comparison != 0) {
548 return this;
549 }
550 comparison = Double.compare(lhs, rhs);
551 return this;
552 }
553
554 /**
555 * <p>Appends to the <code>builder</code> the comparison of
556 * two <code>float</code>s.</p>
557 *
558 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
559 *
560 * <p>It is compatible with the hash code generated by
561 * <code>HashCodeBuilder</code>.</p>
562 *
563 * @param lhs left-hand value
564 * @param rhs right-hand value
565 * @return this - used to chain append calls
566 */
567 public CompareToBuilder append(float lhs, float rhs) {
568 if (comparison != 0) {
569 return this;
570 }
571 comparison = Float.compare(lhs, rhs);
572 return this;
573 }
574
575 /**
576 * Appends to the <code>builder</code> the comparison of
577 * two <code>booleans</code>s.
578 *
579 * @param lhs left-hand value
580 * @param rhs right-hand value
581 * @return this - used to chain append calls
582 */
583 public CompareToBuilder append(boolean lhs, boolean rhs) {
584 if (comparison != 0) {
585 return this;
586 }
587 if (lhs == rhs) {
588 return this;
589 }
590 if (lhs == false) {
591 comparison = -1;
592 } else {
593 comparison = +1;
594 }
595 return this;
596 }
597
598 //-----------------------------------------------------------------------
599 /**
600 * <p>Appends to the <code>builder</code> the deep comparison of
601 * two <code>Object</code> arrays.</p>
602 *
603 * <ol>
604 * <li>Check if arrays are the same using <code>==</code></li>
605 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
606 * <li>Check array length, a short length array is less than a long length array</li>
607 * <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
608 * </ol>
609 *
610 * <p>This method will also will be called for the top level of multi-dimensional,
611 * ragged, and multi-typed arrays.</p>
612 *
613 * @param lhs left-hand array
614 * @param rhs right-hand array
615 * @return this - used to chain append calls
616 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
617 * with <code>lhs</code>
618 */
619 public CompareToBuilder append(Object[] lhs, Object[] rhs) {
620 return append(lhs, rhs, null);
621 }
622
623 /**
624 * <p>Appends to the <code>builder</code> the deep comparison of
625 * two <code>Object</code> arrays.</p>
626 *
627 * <ol>
628 * <li>Check if arrays are the same using <code>==</code></li>
629 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
630 * <li>Check array length, a short length array is less than a long length array</li>
631 * <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
632 * </ol>
633 *
634 * <p>This method will also will be called for the top level of multi-dimensional,
635 * ragged, and multi-typed arrays.</p>
636 *
637 * @param lhs left-hand array
638 * @param rhs right-hand array
639 * @param comparator <code>Comparator</code> to use to compare the array elements,
640 * <code>null</code> means to treat <code>lhs</code> elements as <code>Comparable</code>.
641 * @return this - used to chain append calls
642 * @throws ClassCastException if <code>rhs</code> is not assignment-compatible
643 * with <code>lhs</code>
644 * @since 2.0
645 */
646 public CompareToBuilder append(Object[] lhs, Object[] rhs, Comparator<?> comparator) {
647 if (comparison != 0) {
648 return this;
649 }
650 if (lhs == rhs) {
651 return this;
652 }
653 if (lhs == null) {
654 comparison = -1;
655 return this;
656 }
657 if (rhs == null) {
658 comparison = +1;
659 return this;
660 }
661 if (lhs.length != rhs.length) {
662 comparison = (lhs.length < rhs.length) ? -1 : +1;
663 return this;
664 }
665 for (int i = 0; i < lhs.length && comparison == 0; i++) {
666 append(lhs[i], rhs[i], comparator);
667 }
668 return this;
669 }
670
671 /**
672 * <p>Appends to the <code>builder</code> the deep comparison of
673 * two <code>long</code> arrays.</p>
674 *
675 * <ol>
676 * <li>Check if arrays are the same using <code>==</code></li>
677 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
678 * <li>Check array length, a shorter length array is less than a longer length array</li>
679 * <li>Check array contents element by element using {@link #append(long, long)}</li>
680 * </ol>
681 *
682 * @param lhs left-hand array
683 * @param rhs right-hand array
684 * @return this - used to chain append calls
685 */
686 public CompareToBuilder append(long[] lhs, long[] rhs) {
687 if (comparison != 0) {
688 return this;
689 }
690 if (lhs == rhs) {
691 return this;
692 }
693 if (lhs == null) {
694 comparison = -1;
695 return this;
696 }
697 if (rhs == null) {
698 comparison = +1;
699 return this;
700 }
701 if (lhs.length != rhs.length) {
702 comparison = (lhs.length < rhs.length) ? -1 : +1;
703 return this;
704 }
705 for (int i = 0; i < lhs.length && comparison == 0; i++) {
706 append(lhs[i], rhs[i]);
707 }
708 return this;
709 }
710
711 /**
712 * <p>Appends to the <code>builder</code> the deep comparison of
713 * two <code>int</code> arrays.</p>
714 *
715 * <ol>
716 * <li>Check if arrays are the same using <code>==</code></li>
717 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
718 * <li>Check array length, a shorter length array is less than a longer length array</li>
719 * <li>Check array contents element by element using {@link #append(int, int)}</li>
720 * </ol>
721 *
722 * @param lhs left-hand array
723 * @param rhs right-hand array
724 * @return this - used to chain append calls
725 */
726 public CompareToBuilder append(int[] lhs, int[] rhs) {
727 if (comparison != 0) {
728 return this;
729 }
730 if (lhs == rhs) {
731 return this;
732 }
733 if (lhs == null) {
734 comparison = -1;
735 return this;
736 }
737 if (rhs == null) {
738 comparison = +1;
739 return this;
740 }
741 if (lhs.length != rhs.length) {
742 comparison = (lhs.length < rhs.length) ? -1 : +1;
743 return this;
744 }
745 for (int i = 0; i < lhs.length && comparison == 0; i++) {
746 append(lhs[i], rhs[i]);
747 }
748 return this;
749 }
750
751 /**
752 * <p>Appends to the <code>builder</code> the deep comparison of
753 * two <code>short</code> arrays.</p>
754 *
755 * <ol>
756 * <li>Check if arrays are the same using <code>==</code></li>
757 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
758 * <li>Check array length, a shorter length array is less than a longer length array</li>
759 * <li>Check array contents element by element using {@link #append(short, short)}</li>
760 * </ol>
761 *
762 * @param lhs left-hand array
763 * @param rhs right-hand array
764 * @return this - used to chain append calls
765 */
766 public CompareToBuilder append(short[] lhs, short[] rhs) {
767 if (comparison != 0) {
768 return this;
769 }
770 if (lhs == rhs) {
771 return this;
772 }
773 if (lhs == null) {
774 comparison = -1;
775 return this;
776 }
777 if (rhs == null) {
778 comparison = +1;
779 return this;
780 }
781 if (lhs.length != rhs.length) {
782 comparison = (lhs.length < rhs.length) ? -1 : +1;
783 return this;
784 }
785 for (int i = 0; i < lhs.length && comparison == 0; i++) {
786 append(lhs[i], rhs[i]);
787 }
788 return this;
789 }
790
791 /**
792 * <p>Appends to the <code>builder</code> the deep comparison of
793 * two <code>char</code> arrays.</p>
794 *
795 * <ol>
796 * <li>Check if arrays are the same using <code>==</code></li>
797 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
798 * <li>Check array length, a shorter length array is less than a longer length array</li>
799 * <li>Check array contents element by element using {@link #append(char, char)}</li>
800 * </ol>
801 *
802 * @param lhs left-hand array
803 * @param rhs right-hand array
804 * @return this - used to chain append calls
805 */
806 public CompareToBuilder append(char[] lhs, char[] rhs) {
807 if (comparison != 0) {
808 return this;
809 }
810 if (lhs == rhs) {
811 return this;
812 }
813 if (lhs == null) {
814 comparison = -1;
815 return this;
816 }
817 if (rhs == null) {
818 comparison = +1;
819 return this;
820 }
821 if (lhs.length != rhs.length) {
822 comparison = (lhs.length < rhs.length) ? -1 : +1;
823 return this;
824 }
825 for (int i = 0; i < lhs.length && comparison == 0; i++) {
826 append(lhs[i], rhs[i]);
827 }
828 return this;
829 }
830
831 /**
832 * <p>Appends to the <code>builder</code> the deep comparison of
833 * two <code>byte</code> arrays.</p>
834 *
835 * <ol>
836 * <li>Check if arrays are the same using <code>==</code></li>
837 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
838 * <li>Check array length, a shorter length array is less than a longer length array</li>
839 * <li>Check array contents element by element using {@link #append(byte, byte)}</li>
840 * </ol>
841 *
842 * @param lhs left-hand array
843 * @param rhs right-hand array
844 * @return this - used to chain append calls
845 */
846 public CompareToBuilder append(byte[] lhs, byte[] rhs) {
847 if (comparison != 0) {
848 return this;
849 }
850 if (lhs == rhs) {
851 return this;
852 }
853 if (lhs == null) {
854 comparison = -1;
855 return this;
856 }
857 if (rhs == null) {
858 comparison = +1;
859 return this;
860 }
861 if (lhs.length != rhs.length) {
862 comparison = (lhs.length < rhs.length) ? -1 : +1;
863 return this;
864 }
865 for (int i = 0; i < lhs.length && comparison == 0; i++) {
866 append(lhs[i], rhs[i]);
867 }
868 return this;
869 }
870
871 /**
872 * <p>Appends to the <code>builder</code> the deep comparison of
873 * two <code>double</code> arrays.</p>
874 *
875 * <ol>
876 * <li>Check if arrays are the same using <code>==</code></li>
877 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
878 * <li>Check array length, a shorter length array is less than a longer length array</li>
879 * <li>Check array contents element by element using {@link #append(double, double)}</li>
880 * </ol>
881 *
882 * @param lhs left-hand array
883 * @param rhs right-hand array
884 * @return this - used to chain append calls
885 */
886 public CompareToBuilder append(double[] lhs, double[] rhs) {
887 if (comparison != 0) {
888 return this;
889 }
890 if (lhs == rhs) {
891 return this;
892 }
893 if (lhs == null) {
894 comparison = -1;
895 return this;
896 }
897 if (rhs == null) {
898 comparison = +1;
899 return this;
900 }
901 if (lhs.length != rhs.length) {
902 comparison = (lhs.length < rhs.length) ? -1 : +1;
903 return this;
904 }
905 for (int i = 0; i < lhs.length && comparison == 0; i++) {
906 append(lhs[i], rhs[i]);
907 }
908 return this;
909 }
910
911 /**
912 * <p>Appends to the <code>builder</code> the deep comparison of
913 * two <code>float</code> arrays.</p>
914 *
915 * <ol>
916 * <li>Check if arrays are the same using <code>==</code></li>
917 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
918 * <li>Check array length, a shorter length array is less than a longer length array</li>
919 * <li>Check array contents element by element using {@link #append(float, float)}</li>
920 * </ol>
921 *
922 * @param lhs left-hand array
923 * @param rhs right-hand array
924 * @return this - used to chain append calls
925 */
926 public CompareToBuilder append(float[] lhs, float[] rhs) {
927 if (comparison != 0) {
928 return this;
929 }
930 if (lhs == rhs) {
931 return this;
932 }
933 if (lhs == null) {
934 comparison = -1;
935 return this;
936 }
937 if (rhs == null) {
938 comparison = +1;
939 return this;
940 }
941 if (lhs.length != rhs.length) {
942 comparison = (lhs.length < rhs.length) ? -1 : +1;
943 return this;
944 }
945 for (int i = 0; i < lhs.length && comparison == 0; i++) {
946 append(lhs[i], rhs[i]);
947 }
948 return this;
949 }
950
951 /**
952 * <p>Appends to the <code>builder</code> the deep comparison of
953 * two <code>boolean</code> arrays.</p>
954 *
955 * <ol>
956 * <li>Check if arrays are the same using <code>==</code></li>
957 * <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
958 * <li>Check array length, a shorter length array is less than a longer length array</li>
959 * <li>Check array contents element by element using {@link #append(boolean, boolean)}</li>
960 * </ol>
961 *
962 * @param lhs left-hand array
963 * @param rhs right-hand array
964 * @return this - used to chain append calls
965 */
966 public CompareToBuilder append(boolean[] lhs, boolean[] rhs) {
967 if (comparison != 0) {
968 return this;
969 }
970 if (lhs == rhs) {
971 return this;
972 }
973 if (lhs == null) {
974 comparison = -1;
975 return this;
976 }
977 if (rhs == null) {
978 comparison = +1;
979 return this;
980 }
981 if (lhs.length != rhs.length) {
982 comparison = (lhs.length < rhs.length) ? -1 : +1;
983 return this;
984 }
985 for (int i = 0; i < lhs.length && comparison == 0; i++) {
986 append(lhs[i], rhs[i]);
987 }
988 return this;
989 }
990
991 //-----------------------------------------------------------------------
992 /**
993 * Returns a negative integer, a positive integer, or zero as
994 * the <code>builder</code> has judged the "left-hand" side
995 * as less than, greater than, or equal to the "right-hand"
996 * side.
997 *
998 * @return final comparison result
999 */
1000 public int toComparison() {
1001 return comparison;
1002 }
1003
1004 /**
1005 * Returns a negative integer, a positive integer, or zero as
1006 * the <code>builder</code> has judged the "left-hand" side
1007 * as less than, greater than, or equal to the "right-hand"
1008 * side.
1009 *
1010 * @return final comparison result
1011 *
1012 * @since 3.0
1013 */
1014 public Integer build() {
1015 return Integer.valueOf(toComparison());
1016 }
1017 }
1018
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.lang.reflect.AccessibleObject;
19 import java.lang.reflect.Field;
20 import java.lang.reflect.Modifier;
21 import java.util.Collection;
22 import java.util.HashSet;
23 import java.util.Set;
24
25 import org.apache.commons.lang3.ArrayUtils;
26 import org.apache.commons.lang3.tuple.Pair;
27
28 /**
29 * <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
30 *
31 * <p> This class provides methods to build a good equals method for any
32 * class. It follows rules laid out in
33 * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
34 * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
35 * <code>floats</code>, and arrays can be tricky. Also, making sure that
36 * <code>equals()</code> and <code>hashCode()</code> are consistent can be
37 * difficult.</p>
38 *
39 * <p>Two Objects that compare as equals must generate the same hash code,
40 * but two Objects with the same hash code do not have to be equal.</p>
41 *
42 * <p>All relevant fields should be included in the calculation of equals.
43 * Derived fields may be ignored. In particular, any field used in
44 * generating a hash code must be used in the equals method, and vice
45 * versa.</p>
46 *
47 * <p>Typical use for the code is as follows:</p>
48 * <pre>
49 * public boolean equals(Object obj) {
50 * if (obj == null) { return false; }
51 * if (obj == this) { return true; }
52 * if (obj.getClass() != getClass()) {
53 * return false;
54 * }
55 * MyClass rhs = (MyClass) obj;
56 * return new EqualsBuilder()
57 * .appendSuper(super.equals(obj))
58 * .append(field1, rhs.field1)
59 * .append(field2, rhs.field2)
60 * .append(field3, rhs.field3)
61 * .isEquals();
62 * }
63 * </pre>
64 *
65 * <p> Alternatively, there is a method that uses reflection to determine
66 * the fields to test. Because these fields are usually private, the method,
67 * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
68 * change the visibility of the fields. This will fail under a security
69 * manager, unless the appropriate permissions are set up correctly. It is
70 * also slower than testing explicitly.</p>
71 *
72 * <p> A typical invocation for this method would look like:</p>
73 * <pre>
74 * public boolean equals(Object obj) {
75 * return EqualsBuilder.reflectionEquals(this, obj);
76 * }
77 * </pre>
78 *
79 * @since 1.0
80 * @version $Id: EqualsBuilder.java 1091531 2011-04-12 18:29:49Z ggregory $
81 */
82 public class EqualsBuilder implements Builder<Boolean> {
83
84 /**
85 * <p>
86 * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
87 * </p>
88 *
89 * @since 3.0
90 */
91 private static final ThreadLocal<Set<Pair<IDKey, IDKey>>> REGISTRY = new ThreadLocal<Set<Pair<IDKey, IDKey>>>();
92
93 /*
94 * NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode()
95 * we are in the process of calculating.
96 *
97 * So we generate a one-to-one mapping from the original object to a new object.
98 *
99 * Now HashSet uses equals() to determine if two elements with the same hashcode really
100 * are equal, so we also need to ensure that the replacement objects are only equal
101 * if the original objects are identical.
102 *
103 * The original implementation (2.4 and before) used the System.indentityHashCode()
104 * method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
105 *
106 * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
107 * to disambiguate the duplicate ids.
108 */
109
110 /**
111 * <p>
112 * Returns the registry of object pairs being traversed by the reflection
113 * methods in the current thread.
114 * </p>
115 *
116 * @return Set the registry of objects being traversed
117 * @since 3.0
118 */
119 static Set<Pair<IDKey, IDKey>> getRegistry() {
120 return REGISTRY.get();
121 }
122
123 /**
124 * <p>
125 * Converters value pair into a register pair.
126 * </p>
127 *
128 * @param lhs <code>this</code> object
129 * @param rhs the other object
130 *
131 * @return the pair
132 */
133 static Pair<IDKey, IDKey> getRegisterPair(Object lhs, Object rhs) {
134 IDKey left = new IDKey(lhs);
135 IDKey right = new IDKey(rhs);
136 return Pair.of(left, right);
137 }
138
139 /**
140 * <p>
141 * Returns <code>true</code> if the registry contains the given object pair.
142 * Used by the reflection methods to avoid infinite loops.
143 * Objects might be swapped therefore a check is needed if the object pair
144 * is registered in given or swapped order.
145 * </p>
146 *
147 * @param lhs <code>this</code> object to lookup in registry
148 * @param rhs the other object to lookup on registry
149 * @return boolean <code>true</code> if the registry contains the given object.
150 * @since 3.0
151 */
152 static boolean isRegistered(Object lhs, Object rhs) {
153 Set<Pair<IDKey, IDKey>> registry = getRegistry();
154 Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
155 Pair<IDKey, IDKey> swappedPair = Pair.of(pair.getLeft(), pair.getRight());
156
157 return registry != null
158 && (registry.contains(pair) || registry.contains(swappedPair));
159 }
160
161 /**
162 * <p>
163 * Registers the given object pair.
164 * Used by the reflection methods to avoid infinite loops.
165 * </p>
166 *
167 * @param lhs <code>this</code> object to register
168 * @param rhs the other object to register
169 */
170 static void register(Object lhs, Object rhs) {
171 synchronized (EqualsBuilder.class) {
172 if (getRegistry() == null) {
173 REGISTRY.set(new HashSet<Pair<IDKey, IDKey>>());
174 }
175 }
176
177 Set<Pair<IDKey, IDKey>> registry = getRegistry();
178 Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
179 registry.add(pair);
180 }
181
182 /**
183 * <p>
184 * Unregisters the given object pair.
185 * </p>
186 *
187 * <p>
188 * Used by the reflection methods to avoid infinite loops.
189 *
190 * @param lhs <code>this</code> object to unregister
191 * @param rhs the other object to unregister
192 * @since 3.0
193 */
194 static void unregister(Object lhs, Object rhs) {
195 Set<Pair<IDKey, IDKey>> registry = getRegistry();
196 if (registry != null) {
197 Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
198 registry.remove(pair);
199 synchronized (EqualsBuilder.class) {
200 //read again
201 registry = getRegistry();
202 if (registry != null && registry.isEmpty()) {
203 REGISTRY.remove();
204 }
205 }
206 }
207 }
208
209 /**
210 * If the fields tested are equals.
211 * The default value is <code>true</code>.
212 */
213 private boolean isEquals = true;
214
215 /**
216 * <p>Constructor for EqualsBuilder.</p>
217 *
218 * <p>Starts off assuming that equals is <code>true</code>.</p>
219 * @see Object#equals(Object)
220 */
221 public EqualsBuilder() {
222 // do nothing for now.
223 }
224
225 //-------------------------------------------------------------------------
226
227 /**
228 * <p>This method uses reflection to determine if the two <code>Object</code>s
229 * are equal.</p>
230 *
231 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
232 * fields. This means that it will throw a security exception if run under
233 * a security manager, if the permissions are not set up correctly. It is also
234 * not as efficient as testing explicitly.</p>
235 *
236 * <p>Transient members will be not be tested, as they are likely derived
237 * fields, and not part of the value of the Object.</p>
238 *
239 * <p>Static fields will not be tested. Superclass fields will be included.</p>
240 *
241 * @param lhs <code>this</code> object
242 * @param rhs the other object
243 * @param excludeFields Collection of String field names to exclude from testing
244 * @return <code>true</code> if the two Objects have tested equals.
245 */
246 public static boolean reflectionEquals(Object lhs, Object rhs, Collection<String> excludeFields) {
247 return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
248 }
249
250 /**
251 * <p>This method uses reflection to determine if the two <code>Object</code>s
252 * are equal.</p>
253 *
254 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
255 * fields. This means that it will throw a security exception if run under
256 * a security manager, if the permissions are not set up correctly. It is also
257 * not as efficient as testing explicitly.</p>
258 *
259 * <p>Transient members will be not be tested, as they are likely derived
260 * fields, and not part of the value of the Object.</p>
261 *
262 * <p>Static fields will not be tested. Superclass fields will be included.</p>
263 *
264 * @param lhs <code>this</code> object
265 * @param rhs the other object
266 * @param excludeFields array of field names to exclude from testing
267 * @return <code>true</code> if the two Objects have tested equals.
268 */
269 public static boolean reflectionEquals(Object lhs, Object rhs, String... excludeFields) {
270 return reflectionEquals(lhs, rhs, false, null, excludeFields);
271 }
272
273 /**
274 * <p>This method uses reflection to determine if the two <code>Object</code>s
275 * are equal.</p>
276 *
277 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
278 * fields. This means that it will throw a security exception if run under
279 * a security manager, if the permissions are not set up correctly. It is also
280 * not as efficient as testing explicitly.</p>
281 *
282 * <p>If the TestTransients parameter is set to <code>true</code>, transient
283 * members will be tested, otherwise they are ignored, as they are likely
284 * derived fields, and not part of the value of the <code>Object</code>.</p>
285 *
286 * <p>Static fields will not be tested. Superclass fields will be included.</p>
287 *
288 * @param lhs <code>this</code> object
289 * @param rhs the other object
290 * @param testTransients whether to include transient fields
291 * @return <code>true</code> if the two Objects have tested equals.
292 */
293 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) {
294 return reflectionEquals(lhs, rhs, testTransients, null);
295 }
296
297 /**
298 * <p>This method uses reflection to determine if the two <code>Object</code>s
299 * are equal.</p>
300 *
301 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
302 * fields. This means that it will throw a security exception if run under
303 * a security manager, if the permissions are not set up correctly. It is also
304 * not as efficient as testing explicitly.</p>
305 *
306 * <p>If the testTransients parameter is set to <code>true</code>, transient
307 * members will be tested, otherwise they are ignored, as they are likely
308 * derived fields, and not part of the value of the <code>Object</code>.</p>
309 *
310 * <p>Static fields will not be included. Superclass fields will be appended
311 * up to and including the specified superclass. A null superclass is treated
312 * as java.lang.Object.</p>
313 *
314 * @param lhs <code>this</code> object
315 * @param rhs the other object
316 * @param testTransients whether to include transient fields
317 * @param reflectUpToClass the superclass to reflect up to (inclusive),
318 * may be <code>null</code>
319 * @param excludeFields array of field names to exclude from testing
320 * @return <code>true</code> if the two Objects have tested equals.
321 * @since 2.0
322 */
323 public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class<?> reflectUpToClass,
324 String... excludeFields) {
325 if (lhs == rhs) {
326 return true;
327 }
328 if (lhs == null || rhs == null) {
329 return false;
330 }
331 // Find the leaf class since there may be transients in the leaf
332 // class or in classes between the leaf and root.
333 // If we are not testing transients or a subclass has no ivars,
334 // then a subclass can test equals to a superclass.
335 Class<?> lhsClass = lhs.getClass();
336 Class<?> rhsClass = rhs.getClass();
337 Class<?> testClass;
338 if (lhsClass.isInstance(rhs)) {
339 testClass = lhsClass;
340 if (!rhsClass.isInstance(lhs)) {
341 // rhsClass is a subclass of lhsClass
342 testClass = rhsClass;
343 }
344 } else if (rhsClass.isInstance(lhs)) {
345 testClass = rhsClass;
346 if (!lhsClass.isInstance(rhs)) {
347 // lhsClass is a subclass of rhsClass
348 testClass = lhsClass;
349 }
350 } else {
351 // The two classes are not related.
352 return false;
353 }
354 EqualsBuilder equalsBuilder = new EqualsBuilder();
355 try {
356 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
357 while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
358 testClass = testClass.getSuperclass();
359 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
360 }
361 } catch (IllegalArgumentException e) {
362 // In this case, we tried to test a subclass vs. a superclass and
363 // the subclass has ivars or the ivars are transient and
364 // we are testing transients.
365 // If a subclass has ivars that we are trying to test them, we get an
366 // exception and we know that the objects are not equal.
367 return false;
368 }
369 return equalsBuilder.isEquals();
370 }
371
372 /**
373 * <p>Appends the fields and values defined by the given object of the
374 * given Class.</p>
375 *
376 * @param lhs the left hand object
377 * @param rhs the right hand object
378 * @param clazz the class to append details of
379 * @param builder the builder to append to
380 * @param useTransients whether to test transient fields
381 * @param excludeFields array of field names to exclude from testing
382 */
383 private static void reflectionAppend(
384 Object lhs,
385 Object rhs,
386 Class<?> clazz,
387 EqualsBuilder builder,
388 boolean useTransients,
389 String[] excludeFields) {
390
391 if (isRegistered(lhs, rhs)) {
392 return;
393 }
394
395 try {
396 register(lhs, rhs);
397 Field[] fields = clazz.getDeclaredFields();
398 AccessibleObject.setAccessible(fields, true);
399 for (int i = 0; i < fields.length && builder.isEquals; i++) {
400 Field f = fields[i];
401 if (!ArrayUtils.contains(excludeFields, f.getName())
402 && (f.getName().indexOf('$') == -1)
403 && (useTransients || !Modifier.isTransient(f.getModifiers()))
404 && (!Modifier.isStatic(f.getModifiers()))) {
405 try {
406 builder.append(f.get(lhs), f.get(rhs));
407 } catch (IllegalAccessException e) {
408 //this can't happen. Would get a Security exception instead
409 //throw a runtime exception in case the impossible happens.
410 throw new InternalError("Unexpected IllegalAccessException");
411 }
412 }
413 }
414 } finally {
415 unregister(lhs, rhs);
416 }
417 }
418
419 //-------------------------------------------------------------------------
420
421 /**
422 * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
423 *
424 * @param superEquals the result of calling <code>super.equals()</code>
425 * @return EqualsBuilder - used to chain calls.
426 * @since 2.0
427 */
428 public EqualsBuilder appendSuper(boolean superEquals) {
429 if (isEquals == false) {
430 return this;
431 }
432 isEquals = superEquals;
433 return this;
434 }
435
436 //-------------------------------------------------------------------------
437
438 /**
439 * <p>Test if two <code>Object</code>s are equal using their
440 * <code>equals</code> method.</p>
441 *
442 * @param lhs the left hand object
443 * @param rhs the right hand object
444 * @return EqualsBuilder - used to chain calls.
445 */
446 public EqualsBuilder append(Object lhs, Object rhs) {
447 if (isEquals == false) {
448 return this;
449 }
450 if (lhs == rhs) {
451 return this;
452 }
453 if (lhs == null || rhs == null) {
454 this.setEquals(false);
455 return this;
456 }
457 Class<?> lhsClass = lhs.getClass();
458 if (!lhsClass.isArray()) {
459 // The simple case, not an array, just test the element
460 isEquals = lhs.equals(rhs);
461 } else if (lhs.getClass() != rhs.getClass()) {
462 // Here when we compare different dimensions, for example: a boolean[][] to a boolean[]
463 this.setEquals(false);
464 }
465 // 'Switch' on type of array, to dispatch to the correct handler
466 // This handles multi dimensional arrays of the same depth
467 else if (lhs instanceof long[]) {
468 append((long[]) lhs, (long[]) rhs);
469 } else if (lhs instanceof int[]) {
470 append((int[]) lhs, (int[]) rhs);
471 } else if (lhs instanceof short[]) {
472 append((short[]) lhs, (short[]) rhs);
473 } else if (lhs instanceof char[]) {
474 append((char[]) lhs, (char[]) rhs);
475 } else if (lhs instanceof byte[]) {
476 append((byte[]) lhs, (byte[]) rhs);
477 } else if (lhs instanceof double[]) {
478 append((double[]) lhs, (double[]) rhs);
479 } else if (lhs instanceof float[]) {
480 append((float[]) lhs, (float[]) rhs);
481 } else if (lhs instanceof boolean[]) {
482 append((boolean[]) lhs, (boolean[]) rhs);
483 } else {
484 // Not an array of primitives
485 append((Object[]) lhs, (Object[]) rhs);
486 }
487 return this;
488 }
489
490 /**
491 * <p>
492 * Test if two <code>long</code> s are equal.
493 * </p>
494 *
495 * @param lhs
496 * the left hand <code>long</code>
497 * @param rhs
498 * the right hand <code>long</code>
499 * @return EqualsBuilder - used to chain calls.
500 */
501 public EqualsBuilder append(long lhs, long rhs) {
502 if (isEquals == false) {
503 return this;
504 }
505 isEquals = (lhs == rhs);
506 return this;
507 }
508
509 /**
510 * <p>Test if two <code>int</code>s are equal.</p>
511 *
512 * @param lhs the left hand <code>int</code>
513 * @param rhs the right hand <code>int</code>
514 * @return EqualsBuilder - used to chain calls.
515 */
516 public EqualsBuilder append(int lhs, int rhs) {
517 if (isEquals == false) {
518 return this;
519 }
520 isEquals = (lhs == rhs);
521 return this;
522 }
523
524 /**
525 * <p>Test if two <code>short</code>s are equal.</p>
526 *
527 * @param lhs the left hand <code>short</code>
528 * @param rhs the right hand <code>short</code>
529 * @return EqualsBuilder - used to chain calls.
530 */
531 public EqualsBuilder append(short lhs, short rhs) {
532 if (isEquals == false) {
533 return this;
534 }
535 isEquals = (lhs == rhs);
536 return this;
537 }
538
539 /**
540 * <p>Test if two <code>char</code>s are equal.</p>
541 *
542 * @param lhs the left hand <code>char</code>
543 * @param rhs the right hand <code>char</code>
544 * @return EqualsBuilder - used to chain calls.
545 */
546 public EqualsBuilder append(char lhs, char rhs) {
547 if (isEquals == false) {
548 return this;
549 }
550 isEquals = (lhs == rhs);
551 return this;
552 }
553
554 /**
555 * <p>Test if two <code>byte</code>s are equal.</p>
556 *
557 * @param lhs the left hand <code>byte</code>
558 * @param rhs the right hand <code>byte</code>
559 * @return EqualsBuilder - used to chain calls.
560 */
561 public EqualsBuilder append(byte lhs, byte rhs) {
562 if (isEquals == false) {
563 return this;
564 }
565 isEquals = (lhs == rhs);
566 return this;
567 }
568
569 /**
570 * <p>Test if two <code>double</code>s are equal by testing that the
571 * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
572 *
573 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
574 *
575 * <p>It is compatible with the hash code generated by
576 * <code>HashCodeBuilder</code>.</p>
577 *
578 * @param lhs the left hand <code>double</code>
579 * @param rhs the right hand <code>double</code>
580 * @return EqualsBuilder - used to chain calls.
581 */
582 public EqualsBuilder append(double lhs, double rhs) {
583 if (isEquals == false) {
584 return this;
585 }
586 return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
587 }
588
589 /**
590 * <p>Test if two <code>float</code>s are equal byt testing that the
591 * pattern of bits returned by doubleToLong are equal.</p>
592 *
593 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
594 *
595 * <p>It is compatible with the hash code generated by
596 * <code>HashCodeBuilder</code>.</p>
597 *
598 * @param lhs the left hand <code>float</code>
599 * @param rhs the right hand <code>float</code>
600 * @return EqualsBuilder - used to chain calls.
601 */
602 public EqualsBuilder append(float lhs, float rhs) {
603 if (isEquals == false) {
604 return this;
605 }
606 return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
607 }
608
609 /**
610 * <p>Test if two <code>booleans</code>s are equal.</p>
611 *
612 * @param lhs the left hand <code>boolean</code>
613 * @param rhs the right hand <code>boolean</code>
614 * @return EqualsBuilder - used to chain calls.
615 */
616 public EqualsBuilder append(boolean lhs, boolean rhs) {
617 if (isEquals == false) {
618 return this;
619 }
620 isEquals = (lhs == rhs);
621 return this;
622 }
623
624 /**
625 * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
626 *
627 * <p>This also will be called for the top level of
628 * multi-dimensional, ragged, and multi-typed arrays.</p>
629 *
630 * @param lhs the left hand <code>Object[]</code>
631 * @param rhs the right hand <code>Object[]</code>
632 * @return EqualsBuilder - used to chain calls.
633 */
634 public EqualsBuilder append(Object[] lhs, Object[] rhs) {
635 if (isEquals == false) {
636 return this;
637 }
638 if (lhs == rhs) {
639 return this;
640 }
641 if (lhs == null || rhs == null) {
642 this.setEquals(false);
643 return this;
644 }
645 if (lhs.length != rhs.length) {
646 this.setEquals(false);
647 return this;
648 }
649 for (int i = 0; i < lhs.length && isEquals; ++i) {
650 append(lhs[i], rhs[i]);
651 }
652 return this;
653 }
654
655 /**
656 * <p>Deep comparison of array of <code>long</code>. Length and all
657 * values are compared.</p>
658 *
659 * <p>The method {@link #append(long, long)} is used.</p>
660 *
661 * @param lhs the left hand <code>long[]</code>
662 * @param rhs the right hand <code>long[]</code>
663 * @return EqualsBuilder - used to chain calls.
664 */
665 public EqualsBuilder append(long[] lhs, long[] rhs) {
666 if (isEquals == false) {
667 return this;
668 }
669 if (lhs == rhs) {
670 return this;
671 }
672 if (lhs == null || rhs == null) {
673 this.setEquals(false);
674 return this;
675 }
676 if (lhs.length != rhs.length) {
677 this.setEquals(false);
678 return this;
679 }
680 for (int i = 0; i < lhs.length && isEquals; ++i) {
681 append(lhs[i], rhs[i]);
682 }
683 return this;
684 }
685
686 /**
687 * <p>Deep comparison of array of <code>int</code>. Length and all
688 * values are compared.</p>
689 *
690 * <p>The method {@link #append(int, int)} is used.</p>
691 *
692 * @param lhs the left hand <code>int[]</code>
693 * @param rhs the right hand <code>int[]</code>
694 * @return EqualsBuilder - used to chain calls.
695 */
696 public EqualsBuilder append(int[] lhs, int[] rhs) {
697 if (isEquals == false) {
698 return this;
699 }
700 if (lhs == rhs) {
701 return this;
702 }
703 if (lhs == null || rhs == null) {
704 this.setEquals(false);
705 return this;
706 }
707 if (lhs.length != rhs.length) {
708 this.setEquals(false);
709 return this;
710 }
711 for (int i = 0; i < lhs.length && isEquals; ++i) {
712 append(lhs[i], rhs[i]);
713 }
714 return this;
715 }
716
717 /**
718 * <p>Deep comparison of array of <code>short</code>. Length and all
719 * values are compared.</p>
720 *
721 * <p>The method {@link #append(short, short)} is used.</p>
722 *
723 * @param lhs the left hand <code>short[]</code>
724 * @param rhs the right hand <code>short[]</code>
725 * @return EqualsBuilder - used to chain calls.
726 */
727 public EqualsBuilder append(short[] lhs, short[] rhs) {
728 if (isEquals == false) {
729 return this;
730 }
731 if (lhs == rhs) {
732 return this;
733 }
734 if (lhs == null || rhs == null) {
735 this.setEquals(false);
736 return this;
737 }
738 if (lhs.length != rhs.length) {
739 this.setEquals(false);
740 return this;
741 }
742 for (int i = 0; i < lhs.length && isEquals; ++i) {
743 append(lhs[i], rhs[i]);
744 }
745 return this;
746 }
747
748 /**
749 * <p>Deep comparison of array of <code>char</code>. Length and all
750 * values are compared.</p>
751 *
752 * <p>The method {@link #append(char, char)} is used.</p>
753 *
754 * @param lhs the left hand <code>char[]</code>
755 * @param rhs the right hand <code>char[]</code>
756 * @return EqualsBuilder - used to chain calls.
757 */
758 public EqualsBuilder append(char[] lhs, char[] rhs) {
759 if (isEquals == false) {
760 return this;
761 }
762 if (lhs == rhs) {
763 return this;
764 }
765 if (lhs == null || rhs == null) {
766 this.setEquals(false);
767 return this;
768 }
769 if (lhs.length != rhs.length) {
770 this.setEquals(false);
771 return this;
772 }
773 for (int i = 0; i < lhs.length && isEquals; ++i) {
774 append(lhs[i], rhs[i]);
775 }
776 return this;
777 }
778
779 /**
780 * <p>Deep comparison of array of <code>byte</code>. Length and all
781 * values are compared.</p>
782 *
783 * <p>The method {@link #append(byte, byte)} is used.</p>
784 *
785 * @param lhs the left hand <code>byte[]</code>
786 * @param rhs the right hand <code>byte[]</code>
787 * @return EqualsBuilder - used to chain calls.
788 */
789 public EqualsBuilder append(byte[] lhs, byte[] rhs) {
790 if (isEquals == false) {
791 return this;
792 }
793 if (lhs == rhs) {
794 return this;
795 }
796 if (lhs == null || rhs == null) {
797 this.setEquals(false);
798 return this;
799 }
800 if (lhs.length != rhs.length) {
801 this.setEquals(false);
802 return this;
803 }
804 for (int i = 0; i < lhs.length && isEquals; ++i) {
805 append(lhs[i], rhs[i]);
806 }
807 return this;
808 }
809
810 /**
811 * <p>Deep comparison of array of <code>double</code>. Length and all
812 * values are compared.</p>
813 *
814 * <p>The method {@link #append(double, double)} is used.</p>
815 *
816 * @param lhs the left hand <code>double[]</code>
817 * @param rhs the right hand <code>double[]</code>
818 * @return EqualsBuilder - used to chain calls.
819 */
820 public EqualsBuilder append(double[] lhs, double[] rhs) {
821 if (isEquals == false) {
822 return this;
823 }
824 if (lhs == rhs) {
825 return this;
826 }
827 if (lhs == null || rhs == null) {
828 this.setEquals(false);
829 return this;
830 }
831 if (lhs.length != rhs.length) {
832 this.setEquals(false);
833 return this;
834 }
835 for (int i = 0; i < lhs.length && isEquals; ++i) {
836 append(lhs[i], rhs[i]);
837 }
838 return this;
839 }
840
841 /**
842 * <p>Deep comparison of array of <code>float</code>. Length and all
843 * values are compared.</p>
844 *
845 * <p>The method {@link #append(float, float)} is used.</p>
846 *
847 * @param lhs the left hand <code>float[]</code>
848 * @param rhs the right hand <code>float[]</code>
849 * @return EqualsBuilder - used to chain calls.
850 */
851 public EqualsBuilder append(float[] lhs, float[] rhs) {
852 if (isEquals == false) {
853 return this;
854 }
855 if (lhs == rhs) {
856 return this;
857 }
858 if (lhs == null || rhs == null) {
859 this.setEquals(false);
860 return this;
861 }
862 if (lhs.length != rhs.length) {
863 this.setEquals(false);
864 return this;
865 }
866 for (int i = 0; i < lhs.length && isEquals; ++i) {
867 append(lhs[i], rhs[i]);
868 }
869 return this;
870 }
871
872 /**
873 * <p>Deep comparison of array of <code>boolean</code>. Length and all
874 * values are compared.</p>
875 *
876 * <p>The method {@link #append(boolean, boolean)} is used.</p>
877 *
878 * @param lhs the left hand <code>boolean[]</code>
879 * @param rhs the right hand <code>boolean[]</code>
880 * @return EqualsBuilder - used to chain calls.
881 */
882 public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
883 if (isEquals == false) {
884 return this;
885 }
886 if (lhs == rhs) {
887 return this;
888 }
889 if (lhs == null || rhs == null) {
890 this.setEquals(false);
891 return this;
892 }
893 if (lhs.length != rhs.length) {
894 this.setEquals(false);
895 return this;
896 }
897 for (int i = 0; i < lhs.length && isEquals; ++i) {
898 append(lhs[i], rhs[i]);
899 }
900 return this;
901 }
902
903 /**
904 * <p>Returns <code>true</code> if the fields that have been checked
905 * are all equal.</p>
906 *
907 * @return boolean
908 */
909 public boolean isEquals() {
910 return this.isEquals;
911 }
912
913 /**
914 * <p>Returns <code>true</code> if the fields that have been checked
915 * are all equal.</p>
916 *
917 * @return <code>true</code> if all of the fields that have been checked
918 * are equal, <code>false</code> otherwise.
919 *
920 * @since 3.0
921 */
922 public Boolean build() {
923 return Boolean.valueOf(isEquals());
924 }
925
926 /**
927 * Sets the <code>isEquals</code> value.
928 *
929 * @param isEquals The value to set.
930 * @since 2.1
931 */
932 protected void setEquals(boolean isEquals) {
933 this.isEquals = isEquals;
934 }
935
936 /**
937 * Reset the EqualsBuilder so you can use the same object again
938 * @since 2.5
939 */
940 public void reset() {
941 this.isEquals = true;
942 }
943 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.builder;
18
19 import java.lang.reflect.AccessibleObject;
20 import java.lang.reflect.Field;
21 import java.lang.reflect.Modifier;
22 import java.util.Collection;
23 import java.util.HashSet;
24 import java.util.Set;
25
26 import org.apache.commons.lang3.ArrayUtils;
27
28 /**
29 * <p>
30 * Assists in implementing {@link Object#hashCode()} methods.
31 * </p>
32 *
33 * <p>
34 * This class enables a good <code>hashCode</code> method to be built for any class. It follows the rules laid out in
35 * the book <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a> by Joshua Bloch. Writing a
36 * good <code>hashCode</code> method is actually quite difficult. This class aims to simplify the process.
37 * </p>
38 *
39 * <p>
40 * The following is the approach taken. When appending a data field, the current total is multiplied by the
41 * multiplier then a relevant value
42 * for that data type is added. For example, if the current hashCode is 17, and the multiplier is 37, then
43 * appending the integer 45 will create a hashcode of 674, namely 17 * 37 + 45.
44 * </p>
45 *
46 * <p>
47 * All relevant fields from the object should be included in the <code>hashCode</code> method. Derived fields may be
48 * excluded. In general, any field used in the <code>equals</code> method must be used in the <code>hashCode</code>
49 * method.
50 * </p>
51 *
52 * <p>
53 * To use this class write code as follows:
54 * </p>
55 *
56 * <pre>
57 * public class Person {
58 * String name;
59 * int age;
60 * boolean smoker;
61 * ...
62 *
63 * public int hashCode() {
64 * // you pick a hard-coded, randomly chosen, non-zero, odd number
65 * // ideally different for each class
66 * return new HashCodeBuilder(17, 37).
67 * append(name).
68 * append(age).
69 * append(smoker).
70 * toHashCode();
71 * }
72 * }
73 * </pre>
74 *
75 * <p>
76 * If required, the superclass <code>hashCode()</code> can be added using {@link #appendSuper}.
77 * </p>
78 *
79 * <p>
80 * Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are
81 * usually private, the method, <code>reflectionHashCode</code>, uses <code>AccessibleObject.setAccessible</code>
82 * to change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions
83 * are set up correctly. It is also slower than testing explicitly.
84 * </p>
85 *
86 * <p>
87 * A typical invocation for this method would look like:
88 * </p>
89 *
90 * <pre>
91 * public int hashCode() {
92 * return HashCodeBuilder.reflectionHashCode(this);
93 * }
94 * </pre>
95 *
96 * @since 1.0
97 * @version $Id: HashCodeBuilder.java 1144929 2011-07-10 18:26:16Z ggregory $
98 */
99 public class HashCodeBuilder implements Builder<Integer> {
100 /**
101 * <p>
102 * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
103 * </p>
104 *
105 * @since 2.3
106 */
107 private static final ThreadLocal<Set<IDKey>> REGISTRY = new ThreadLocal<Set<IDKey>>();
108
109 /*
110 * NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode()
111 * we are in the process of calculating.
112 *
113 * So we generate a one-to-one mapping from the original object to a new object.
114 *
115 * Now HashSet uses equals() to determine if two elements with the same hashcode really
116 * are equal, so we also need to ensure that the replacement objects are only equal
117 * if the original objects are identical.
118 *
119 * The original implementation (2.4 and before) used the System.indentityHashCode()
120 * method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
121 *
122 * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
123 * to disambiguate the duplicate ids.
124 */
125
126 /**
127 * <p>
128 * Returns the registry of objects being traversed by the reflection methods in the current thread.
129 * </p>
130 *
131 * @return Set the registry of objects being traversed
132 * @since 2.3
133 */
134 static Set<IDKey> getRegistry() {
135 return REGISTRY.get();
136 }
137
138 /**
139 * <p>
140 * Returns <code>true</code> if the registry contains the given object. Used by the reflection methods to avoid
141 * infinite loops.
142 * </p>
143 *
144 * @param value
145 * The object to lookup in the registry.
146 * @return boolean <code>true</code> if the registry contains the given object.
147 * @since 2.3
148 */
149 static boolean isRegistered(Object value) {
150 Set<IDKey> registry = getRegistry();
151 return registry != null && registry.contains(new IDKey(value));
152 }
153
154 /**
155 * <p>
156 * Appends the fields and values defined by the given object of the given <code>Class</code>.
157 * </p>
158 *
159 * @param object
160 * the object to append details of
161 * @param clazz
162 * the class to append details of
163 * @param builder
164 * the builder to append to
165 * @param useTransients
166 * whether to use transient fields
167 * @param excludeFields
168 * Collection of String field names to exclude from use in calculation of hash code
169 */
170 private static void reflectionAppend(Object object, Class<?> clazz, HashCodeBuilder builder, boolean useTransients,
171 String[] excludeFields) {
172 if (isRegistered(object)) {
173 return;
174 }
175 try {
176 register(object);
177 Field[] fields = clazz.getDeclaredFields();
178 AccessibleObject.setAccessible(fields, true);
179 for (Field field : fields) {
180 if (!ArrayUtils.contains(excludeFields, field.getName())
181 && (field.getName().indexOf('$') == -1)
182 && (useTransients || !Modifier.isTransient(field.getModifiers()))
183 && (!Modifier.isStatic(field.getModifiers()))) {
184 try {
185 Object fieldValue = field.get(object);
186 builder.append(fieldValue);
187 } catch (IllegalAccessException e) {
188 // this can't happen. Would get a Security exception instead
189 // throw a runtime exception in case the impossible happens.
190 throw new InternalError("Unexpected IllegalAccessException");
191 }
192 }
193 }
194 } finally {
195 unregister(object);
196 }
197 }
198
199 /**
200 * <p>
201 * This method uses reflection to build a valid hash code.
202 * </p>
203 *
204 * <p>
205 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
206 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
207 * also not as efficient as testing explicitly.
208 * </p>
209 *
210 * <p>
211 * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
212 * <code>Object</code>.
213 * </p>
214 *
215 * <p>
216 * Static fields will not be tested. Superclass fields will be included.
217 * </p>
218 *
219 * <p>
220 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
221 * however this is not vital. Prime numbers are preferred, especially for the multiplier.
222 * </p>
223 *
224 * @param initialNonZeroOddNumber
225 * a non-zero, odd number used as the initial value
226 * @param multiplierNonZeroOddNumber
227 * a non-zero, odd number used as the multiplier
228 * @param object
229 * the Object to create a <code>hashCode</code> for
230 * @return int hash code
231 * @throws IllegalArgumentException
232 * if the Object is <code>null</code>
233 * @throws IllegalArgumentException
234 * if the number is zero or even
235 */
236 public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object) {
237 return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null);
238 }
239
240 /**
241 * <p>
242 * This method uses reflection to build a valid hash code.
243 * </p>
244 *
245 * <p>
246 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
247 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
248 * also not as efficient as testing explicitly.
249 * </p>
250 *
251 * <p>
252 * If the TestTransients parameter is set to <code>true</code>, transient members will be tested, otherwise they
253 * are ignored, as they are likely derived fields, and not part of the value of the <code>Object</code>.
254 * </p>
255 *
256 * <p>
257 * Static fields will not be tested. Superclass fields will be included.
258 * </p>
259 *
260 * <p>
261 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
262 * however this is not vital. Prime numbers are preferred, especially for the multiplier.
263 * </p>
264 *
265 * @param initialNonZeroOddNumber
266 * a non-zero, odd number used as the initial value
267 * @param multiplierNonZeroOddNumber
268 * a non-zero, odd number used as the multiplier
269 * @param object
270 * the Object to create a <code>hashCode</code> for
271 * @param testTransients
272 * whether to include transient fields
273 * @return int hash code
274 * @throws IllegalArgumentException
275 * if the Object is <code>null</code>
276 * @throws IllegalArgumentException
277 * if the number is zero or even
278 */
279 public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object,
280 boolean testTransients) {
281 return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null);
282 }
283
284 /**
285 * <p>
286 * This method uses reflection to build a valid hash code.
287 * </p>
288 *
289 * <p>
290 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
291 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
292 * also not as efficient as testing explicitly.
293 * </p>
294 *
295 * <p>
296 * If the TestTransients parameter is set to <code>true</code>, transient members will be tested, otherwise they
297 * are ignored, as they are likely derived fields, and not part of the value of the <code>Object</code>.
298 * </p>
299 *
300 * <p>
301 * Static fields will not be included. Superclass fields will be included up to and including the specified
302 * superclass. A null superclass is treated as java.lang.Object.
303 * </p>
304 *
305 * <p>
306 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
307 * however this is not vital. Prime numbers are preferred, especially for the multiplier.
308 * </p>
309 *
310 * @param <T>
311 * the type of the object involved
312 * @param initialNonZeroOddNumber
313 * a non-zero, odd number used as the initial value
314 * @param multiplierNonZeroOddNumber
315 * a non-zero, odd number used as the multiplier
316 * @param object
317 * the Object to create a <code>hashCode</code> for
318 * @param testTransients
319 * whether to include transient fields
320 * @param reflectUpToClass
321 * the superclass to reflect up to (inclusive), may be <code>null</code>
322 * @param excludeFields
323 * array of field names to exclude from use in calculation of hash code
324 * @return int hash code
325 * @throws IllegalArgumentException
326 * if the Object is <code>null</code>
327 * @throws IllegalArgumentException
328 * if the number is zero or even
329 * @since 2.0
330 */
331 public static <T> int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, T object,
332 boolean testTransients, Class<? super T> reflectUpToClass, String... excludeFields) {
333
334 if (object == null) {
335 throw new IllegalArgumentException("The object to build a hash code for must not be null");
336 }
337 HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber);
338 Class<?> clazz = object.getClass();
339 reflectionAppend(object, clazz, builder, testTransients, excludeFields);
340 while (clazz.getSuperclass() != null && clazz != reflectUpToClass) {
341 clazz = clazz.getSuperclass();
342 reflectionAppend(object, clazz, builder, testTransients, excludeFields);
343 }
344 return builder.toHashCode();
345 }
346
347 /**
348 * <p>
349 * This method uses reflection to build a valid hash code.
350 * </p>
351 *
352 * <p>
353 * This constructor uses two hard coded choices for the constants needed to build a hash code.
354 * </p>
355 *
356 * <p>
357 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
358 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
359 * also not as efficient as testing explicitly.
360 * </p>
361 *
362 * <P>
363 * If the TestTransients parameter is set to <code>true</code>, transient members will be tested, otherwise they
364 * are ignored, as they are likely derived fields, and not part of the value of the <code>Object</code>.
365 * </p>
366 *
367 * <p>
368 * Static fields will not be tested. Superclass fields will be included.
369 * </p>
370 *
371 * @param object
372 * the Object to create a <code>hashCode</code> for
373 * @param testTransients
374 * whether to include transient fields
375 * @return int hash code
376 * @throws IllegalArgumentException
377 * if the object is <code>null</code>
378 */
379 public static int reflectionHashCode(Object object, boolean testTransients) {
380 return reflectionHashCode(17, 37, object, testTransients, null);
381 }
382
383 /**
384 * <p>
385 * This method uses reflection to build a valid hash code.
386 * </p>
387 *
388 * <p>
389 * This constructor uses two hard coded choices for the constants needed to build a hash code.
390 * </p>
391 *
392 * <p>
393 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
394 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
395 * also not as efficient as testing explicitly.
396 * </p>
397 *
398 * <p>
399 * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
400 * <code>Object</code>.
401 * </p>
402 *
403 * <p>
404 * Static fields will not be tested. Superclass fields will be included.
405 * </p>
406 *
407 * @param object
408 * the Object to create a <code>hashCode</code> for
409 * @param excludeFields
410 * Collection of String field names to exclude from use in calculation of hash code
411 * @return int hash code
412 * @throws IllegalArgumentException
413 * if the object is <code>null</code>
414 */
415 public static int reflectionHashCode(Object object, Collection<String> excludeFields) {
416 return reflectionHashCode(object, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
417 }
418
419 // -------------------------------------------------------------------------
420
421 /**
422 * <p>
423 * This method uses reflection to build a valid hash code.
424 * </p>
425 *
426 * <p>
427 * This constructor uses two hard coded choices for the constants needed to build a hash code.
428 * </p>
429 *
430 * <p>
431 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
432 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
433 * also not as efficient as testing explicitly.
434 * </p>
435 *
436 * <p>
437 * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
438 * <code>Object</code>.
439 * </p>
440 *
441 * <p>
442 * Static fields will not be tested. Superclass fields will be included.
443 * </p>
444 *
445 * @param object
446 * the Object to create a <code>hashCode</code> for
447 * @param excludeFields
448 * array of field names to exclude from use in calculation of hash code
449 * @return int hash code
450 * @throws IllegalArgumentException
451 * if the object is <code>null</code>
452 */
453 public static int reflectionHashCode(Object object, String... excludeFields) {
454 return reflectionHashCode(17, 37, object, false, null, excludeFields);
455 }
456
457 /**
458 * <p>
459 * Registers the given object. Used by the reflection methods to avoid infinite loops.
460 * </p>
461 *
462 * @param value
463 * The object to register.
464 */
465 static void register(Object value) {
466 synchronized (HashCodeBuilder.class) {
467 if (getRegistry() == null) {
468 REGISTRY.set(new HashSet<IDKey>());
469 }
470 }
471 getRegistry().add(new IDKey(value));
472 }
473
474 /**
475 * <p>
476 * Unregisters the given object.
477 * </p>
478 *
479 * <p>
480 * Used by the reflection methods to avoid infinite loops.
481 *
482 * @param value
483 * The object to unregister.
484 * @since 2.3
485 */
486 static void unregister(Object value) {
487 Set<IDKey> registry = getRegistry();
488 if (registry != null) {
489 registry.remove(new IDKey(value));
490 synchronized (HashCodeBuilder.class) {
491 //read again
492 registry = getRegistry();
493 if (registry != null && registry.isEmpty()) {
494 REGISTRY.remove();
495 }
496 }
497 }
498 }
499
500 /**
501 * Constant to use in building the hashCode.
502 */
503 private final int iConstant;
504
505 /**
506 * Running total of the hashCode.
507 */
508 private int iTotal = 0;
509
510 /**
511 * <p>
512 * Uses two hard coded choices for the constants needed to build a <code>hashCode</code>.
513 * </p>
514 */
515 public HashCodeBuilder() {
516 iConstant = 37;
517 iTotal = 17;
518 }
519
520 /**
521 * <p>
522 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
523 * however this is not vital.
524 * </p>
525 *
526 * <p>
527 * Prime numbers are preferred, especially for the multiplier.
528 * </p>
529 *
530 * @param initialNonZeroOddNumber
531 * a non-zero, odd number used as the initial value
532 * @param multiplierNonZeroOddNumber
533 * a non-zero, odd number used as the multiplier
534 * @throws IllegalArgumentException
535 * if the number is zero or even
536 */
537 public HashCodeBuilder(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber) {
538 if (initialNonZeroOddNumber == 0) {
539 throw new IllegalArgumentException("HashCodeBuilder requires a non zero initial value");
540 }
541 if (initialNonZeroOddNumber % 2 == 0) {
542 throw new IllegalArgumentException("HashCodeBuilder requires an odd initial value");
543 }
544 if (multiplierNonZeroOddNumber == 0) {
545 throw new IllegalArgumentException("HashCodeBuilder requires a non zero multiplier");
546 }
547 if (multiplierNonZeroOddNumber % 2 == 0) {
548 throw new IllegalArgumentException("HashCodeBuilder requires an odd multiplier");
549 }
550 iConstant = multiplierNonZeroOddNumber;
551 iTotal = initialNonZeroOddNumber;
552 }
553
554 /**
555 * <p>
556 * Append a <code>hashCode</code> for a <code>boolean</code>.
557 * </p>
558 * <p>
559 * This adds <code>1</code> when true, and <code>0</code> when false to the <code>hashCode</code>.
560 * </p>
561 * <p>
562 * This is in contrast to the standard <code>java.lang.Boolean.hashCode</code> handling, which computes
563 * a <code>hashCode</code> value of <code>1231</code> for <code>java.lang.Boolean</code> instances
564 * that represent <code>true</code> or <code>1237</code> for <code>java.lang.Boolean</code> instances
565 * that represent <code>false</code>.
566 * </p>
567 * <p>
568 * This is in accordance with the <quote>Effective Java</quote> design.
569 * </p>
570 *
571 * @param value
572 * the boolean to add to the <code>hashCode</code>
573 * @return this
574 */
575 public HashCodeBuilder append(boolean value) {
576 iTotal = iTotal * iConstant + (value ? 0 : 1);
577 return this;
578 }
579
580 /**
581 * <p>
582 * Append a <code>hashCode</code> for a <code>boolean</code> array.
583 * </p>
584 *
585 * @param array
586 * the array to add to the <code>hashCode</code>
587 * @return this
588 */
589 public HashCodeBuilder append(boolean[] array) {
590 if (array == null) {
591 iTotal = iTotal * iConstant;
592 } else {
593 for (boolean element : array) {
594 append(element);
595 }
596 }
597 return this;
598 }
599
600 // -------------------------------------------------------------------------
601
602 /**
603 * <p>
604 * Append a <code>hashCode</code> for a <code>byte</code>.
605 * </p>
606 *
607 * @param value
608 * the byte to add to the <code>hashCode</code>
609 * @return this
610 */
611 public HashCodeBuilder append(byte value) {
612 iTotal = iTotal * iConstant + value;
613 return this;
614 }
615
616 // -------------------------------------------------------------------------
617
618 /**
619 * <p>
620 * Append a <code>hashCode</code> for a <code>byte</code> array.
621 * </p>
622 *
623 * @param array
624 * the array to add to the <code>hashCode</code>
625 * @return this
626 */
627 public HashCodeBuilder append(byte[] array) {
628 if (array == null) {
629 iTotal = iTotal * iConstant;
630 } else {
631 for (byte element : array) {
632 append(element);
633 }
634 }
635 return this;
636 }
637
638 /**
639 * <p>
640 * Append a <code>hashCode</code> for a <code>char</code>.
641 * </p>
642 *
643 * @param value
644 * the char to add to the <code>hashCode</code>
645 * @return this
646 */
647 public HashCodeBuilder append(char value) {
648 iTotal = iTotal * iConstant + value;
649 return this;
650 }
651
652 /**
653 * <p>
654 * Append a <code>hashCode</code> for a <code>char</code> array.
655 * </p>
656 *
657 * @param array
658 * the array to add to the <code>hashCode</code>
659 * @return this
660 */
661 public HashCodeBuilder append(char[] array) {
662 if (array == null) {
663 iTotal = iTotal * iConstant;
664 } else {
665 for (char element : array) {
666 append(element);
667 }
668 }
669 return this;
670 }
671
672 /**
673 * <p>
674 * Append a <code>hashCode</code> for a <code>double</code>.
675 * </p>
676 *
677 * @param value
678 * the double to add to the <code>hashCode</code>
679 * @return this
680 */
681 public HashCodeBuilder append(double value) {
682 return append(Double.doubleToLongBits(value));
683 }
684
685 /**
686 * <p>
687 * Append a <code>hashCode</code> for a <code>double</code> array.
688 * </p>
689 *
690 * @param array
691 * the array to add to the <code>hashCode</code>
692 * @return this
693 */
694 public HashCodeBuilder append(double[] array) {
695 if (array == null) {
696 iTotal = iTotal * iConstant;
697 } else {
698 for (double element : array) {
699 append(element);
700 }
701 }
702 return this;
703 }
704
705 /**
706 * <p>
707 * Append a <code>hashCode</code> for a <code>float</code>.
708 * </p>
709 *
710 * @param value
711 * the float to add to the <code>hashCode</code>
712 * @return this
713 */
714 public HashCodeBuilder append(float value) {
715 iTotal = iTotal * iConstant + Float.floatToIntBits(value);
716 return this;
717 }
718
719 /**
720 * <p>
721 * Append a <code>hashCode</code> for a <code>float</code> array.
722 * </p>
723 *
724 * @param array
725 * the array to add to the <code>hashCode</code>
726 * @return this
727 */
728 public HashCodeBuilder append(float[] array) {
729 if (array == null) {
730 iTotal = iTotal * iConstant;
731 } else {
732 for (float element : array) {
733 append(element);
734 }
735 }
736 return this;
737 }
738
739 /**
740 * <p>
741 * Append a <code>hashCode</code> for an <code>int</code>.
742 * </p>
743 *
744 * @param value
745 * the int to add to the <code>hashCode</code>
746 * @return this
747 */
748 public HashCodeBuilder append(int value) {
749 iTotal = iTotal * iConstant + value;
750 return this;
751 }
752
753 /**
754 * <p>
755 * Append a <code>hashCode</code> for an <code>int</code> array.
756 * </p>
757 *
758 * @param array
759 * the array to add to the <code>hashCode</code>
760 * @return this
761 */
762 public HashCodeBuilder append(int[] array) {
763 if (array == null) {
764 iTotal = iTotal * iConstant;
765 } else {
766 for (int element : array) {
767 append(element);
768 }
769 }
770 return this;
771 }
772
773 /**
774 * <p>
775 * Append a <code>hashCode</code> for a <code>long</code>.
776 * </p>
777 *
778 * @param value
779 * the long to add to the <code>hashCode</code>
780 * @return this
781 */
782 // NOTE: This method uses >> and not >>> as Effective Java and
783 // Long.hashCode do. Ideally we should switch to >>> at
784 // some stage. There are backwards compat issues, so
785 // that will have to wait for the time being. cf LANG-342.
786 public HashCodeBuilder append(long value) {
787 iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32)));
788 return this;
789 }
790
791 /**
792 * <p>
793 * Append a <code>hashCode</code> for a <code>long</code> array.
794 * </p>
795 *
796 * @param array
797 * the array to add to the <code>hashCode</code>
798 * @return this
799 */
800 public HashCodeBuilder append(long[] array) {
801 if (array == null) {
802 iTotal = iTotal * iConstant;
803 } else {
804 for (long element : array) {
805 append(element);
806 }
807 }
808 return this;
809 }
810
811 /**
812 * <p>
813 * Append a <code>hashCode</code> for an <code>Object</code>.
814 * </p>
815 *
816 * @param object
817 * the Object to add to the <code>hashCode</code>
818 * @return this
819 */
820 public HashCodeBuilder append(Object object) {
821 if (object == null) {
822 iTotal = iTotal * iConstant;
823
824 } else {
825 if(object.getClass().isArray()) {
826 // 'Switch' on type of array, to dispatch to the correct handler
827 // This handles multi dimensional arrays
828 if (object instanceof long[]) {
829 append((long[]) object);
830 } else if (object instanceof int[]) {
831 append((int[]) object);
832 } else if (object instanceof short[]) {
833 append((short[]) object);
834 } else if (object instanceof char[]) {
835 append((char[]) object);
836 } else if (object instanceof byte[]) {
837 append((byte[]) object);
838 } else if (object instanceof double[]) {
839 append((double[]) object);
840 } else if (object instanceof float[]) {
841 append((float[]) object);
842 } else if (object instanceof boolean[]) {
843 append((boolean[]) object);
844 } else {
845 // Not an array of primitives
846 append((Object[]) object);
847 }
848 } else {
849 iTotal = iTotal * iConstant + object.hashCode();
850 }
851 }
852 return this;
853 }
854
855 /**
856 * <p>
857 * Append a <code>hashCode</code> for an <code>Object</code> array.
858 * </p>
859 *
860 * @param array
861 * the array to add to the <code>hashCode</code>
862 * @return this
863 */
864 public HashCodeBuilder append(Object[] array) {
865 if (array == null) {
866 iTotal = iTotal * iConstant;
867 } else {
868 for (Object element : array) {
869 append(element);
870 }
871 }
872 return this;
873 }
874
875 /**
876 * <p>
877 * Append a <code>hashCode</code> for a <code>short</code>.
878 * </p>
879 *
880 * @param value
881 * the short to add to the <code>hashCode</code>
882 * @return this
883 */
884 public HashCodeBuilder append(short value) {
885 iTotal = iTotal * iConstant + value;
886 return this;
887 }
888
889 /**
890 * <p>
891 * Append a <code>hashCode</code> for a <code>short</code> array.
892 * </p>
893 *
894 * @param array
895 * the array to add to the <code>hashCode</code>
896 * @return this
897 */
898 public HashCodeBuilder append(short[] array) {
899 if (array == null) {
900 iTotal = iTotal * iConstant;
901 } else {
902 for (short element : array) {
903 append(element);
904 }
905 }
906 return this;
907 }
908
909 /**
910 * <p>
911 * Adds the result of super.hashCode() to this builder.
912 * </p>
913 *
914 * @param superHashCode
915 * the result of calling <code>super.hashCode()</code>
916 * @return this HashCodeBuilder, used to chain calls.
917 * @since 2.0
918 */
919 public HashCodeBuilder appendSuper(int superHashCode) {
920 iTotal = iTotal * iConstant + superHashCode;
921 return this;
922 }
923
924 /**
925 * <p>
926 * Return the computed <code>hashCode</code>.
927 * </p>
928 *
929 * @return <code>hashCode</code> based on the fields appended
930 */
931 public int toHashCode() {
932 return iTotal;
933 }
934
935 /**
936 * Returns the computed <code>hashCode</code>.
937 *
938 * @return <code>hashCode</code> based on the fields appended
939 *
940 * @since 3.0
941 */
942 public Integer build() {
943 return Integer.valueOf(toHashCode());
944 }
945
946 /**
947 * <p>
948 * The computed <code>hashCode</code> from toHashCode() is returned due to the likelihood
949 * of bugs in mis-calling toHashCode() and the unlikeliness of it mattering what the hashCode for
950 * HashCodeBuilder itself is.</p>
951 *
952 * @return <code>hashCode</code> based on the fields appended
953 * @since 2.5
954 */
955 @Override
956 public int hashCode() {
957 return toHashCode();
958 }
959
960 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 package org.apache.commons.lang3.builder;
19
20 // adapted from org.apache.axis.utils.IDKey
21
22 /**
23 * Wrap an identity key (System.identityHashCode())
24 * so that an object can only be equal() to itself.
25 *
26 * This is necessary to disambiguate the occasional duplicate
27 * identityHashCodes that can occur.
28 *
29 */
30 final class IDKey {
31 private final Object value;
32 private final int id;
33
34 /**
35 * Constructor for IDKey
36 * @param _value The value
37 */
38 public IDKey(Object _value) {
39 // This is the Object hashcode
40 id = System.identityHashCode(_value);
41 // There have been some cases (LANG-459) that return the
42 // same identity hash code for different objects. So
43 // the value is also added to disambiguate these cases.
44 value = _value;
45 }
46
47 /**
48 * returns hashcode - i.e. the system identity hashcode.
49 * @return the hashcode
50 */
51 @Override
52 public int hashCode() {
53 return id;
54 }
55
56 /**
57 * checks if instances are equal
58 * @param other The other object to compare to
59 * @return if the instances are for the same object
60 */
61 @Override
62 public boolean equals(Object other) {
63 if (!(other instanceof IDKey)) {
64 return false;
65 }
66 IDKey idKey = (IDKey) other;
67 if (id != idKey.id) {
68 return false;
69 }
70 // Note that identity equals is used.
71 return value == idKey.value;
72 }
73 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.builder;
18
19 import java.lang.reflect.AccessibleObject;
20 import java.lang.reflect.Field;
21 import java.lang.reflect.Modifier;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.List;
26
27 import org.apache.commons.lang3.ArrayUtils;
28 import org.apache.commons.lang3.ClassUtils;
29
30 /**
31 * <p>
32 * Assists in implementing {@link Object#toString()} methods using reflection.
33 * </p>
34 *
35 * <p>
36 * This class uses reflection to determine the fields to append. Because these fields are usually private, the class
37 * uses {@link java.lang.reflect.AccessibleObject#setAccessible(java.lang.reflect.AccessibleObject[], boolean)} to
38 * change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions are
39 * set up correctly.
40 * </p>
41 *
42 * <p>
43 * A typical invocation for this method would look like:
44 * </p>
45 *
46 * <pre>
47 * public String toString() {
48 * return ReflectionToStringBuilder.toString(this);
49 * }</pre>
50 *
51 *
52 *
53 * <p>
54 * You can also use the builder to debug 3rd party objects:
55 * </p>
56 *
57 * <pre>
58 * System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject));</pre>
59 *
60 *
61 *
62 * <p>
63 * A subclass can control field output by overriding the methods:
64 * <ul>
65 * <li>{@link #accept(java.lang.reflect.Field)}</li>
66 * <li>{@link #getValue(java.lang.reflect.Field)}</li>
67 * </ul>
68 * </p>
69 * <p>
70 * For example, this method does <i>not</i> include the <code>password</code> field in the returned
71 * <code>String</code>:
72 * </p>
73 *
74 * <pre>
75 * public String toString() {
76 * return (new ReflectionToStringBuilder(this) {
77 * protected boolean accept(Field f) {
78 * return super.accept(f) && !f.getName().equals("password");
79 * }
80 * }).toString();
81 * }</pre>
82 *
83 *
84 *
85 * <p>
86 * The exact format of the <code>toString</code> is determined by the {@link ToStringStyle} passed into the
87 * constructor.
88 * </p>
89 *
90 * @since 2.0
91 * @version $Id: ReflectionToStringBuilder.java 1090821 2011-04-10 15:59:07Z mbenson $
92 */
93 public class ReflectionToStringBuilder extends ToStringBuilder {
94
95 /**
96 * <p>
97 * Builds a <code>toString</code> value using the default <code>ToStringStyle</code> through reflection.
98 * </p>
99 *
100 * <p>
101 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
102 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
103 * also not as efficient as testing explicitly.
104 * </p>
105 *
106 * <p>
107 * Transient members will be not be included, as they are likely derived. Static fields will not be included.
108 * Superclass fields will be appended.
109 * </p>
110 *
111 * @param object
112 * the Object to be output
113 * @return the String result
114 * @throws IllegalArgumentException
115 * if the Object is <code>null</code>
116 */
117 public static String toString(Object object) {
118 return toString(object, null, false, false, null);
119 }
120
121 /**
122 * <p>
123 * Builds a <code>toString</code> value through reflection.
124 * </p>
125 *
126 * <p>
127 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
128 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
129 * also not as efficient as testing explicitly.
130 * </p>
131 *
132 * <p>
133 * Transient members will be not be included, as they are likely derived. Static fields will not be included.
134 * Superclass fields will be appended.
135 * </p>
136 *
137 * <p>
138 * If the style is <code>null</code>, the default <code>ToStringStyle</code> is used.
139 * </p>
140 *
141 * @param object
142 * the Object to be output
143 * @param style
144 * the style of the <code>toString</code> to create, may be <code>null</code>
145 * @return the String result
146 * @throws IllegalArgumentException
147 * if the Object or <code>ToStringStyle</code> is <code>null</code>
148 */
149 public static String toString(Object object, ToStringStyle style) {
150 return toString(object, style, false, false, null);
151 }
152
153 /**
154 * <p>
155 * Builds a <code>toString</code> value through reflection.
156 * </p>
157 *
158 * <p>
159 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
160 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
161 * also not as efficient as testing explicitly.
162 * </p>
163 *
164 * <p>
165 * If the <code>outputTransients</code> is <code>true</code>, transient members will be output, otherwise they
166 * are ignored, as they are likely derived fields, and not part of the value of the Object.
167 * </p>
168 *
169 * <p>
170 * Static fields will not be included. Superclass fields will be appended.
171 * </p>
172 *
173 * <p>
174 * If the style is <code>null</code>, the default <code>ToStringStyle</code> is used.
175 * </p>
176 *
177 * @param object
178 * the Object to be output
179 * @param style
180 * the style of the <code>toString</code> to create, may be <code>null</code>
181 * @param outputTransients
182 * whether to include transient fields
183 * @return the String result
184 * @throws IllegalArgumentException
185 * if the Object is <code>null</code>
186 */
187 public static String toString(Object object, ToStringStyle style, boolean outputTransients) {
188 return toString(object, style, outputTransients, false, null);
189 }
190
191 /**
192 * <p>
193 * Builds a <code>toString</code> value through reflection.
194 * </p>
195 *
196 * <p>
197 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
198 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
199 * also not as efficient as testing explicitly.
200 * </p>
201 *
202 * <p>
203 * If the <code>outputTransients</code> is <code>true</code>, transient fields will be output, otherwise they
204 * are ignored, as they are likely derived fields, and not part of the value of the Object.
205 * </p>
206 *
207 * <p>
208 * If the <code>outputStatics</code> is <code>true</code>, static fields will be output, otherwise they are
209 * ignored.
210 * </p>
211 *
212 * <p>
213 * Static fields will not be included. Superclass fields will be appended.
214 * </p>
215 *
216 * <p>
217 * If the style is <code>null</code>, the default <code>ToStringStyle</code> is used.
218 * </p>
219 *
220 * @param object
221 * the Object to be output
222 * @param style
223 * the style of the <code>toString</code> to create, may be <code>null</code>
224 * @param outputTransients
225 * whether to include transient fields
226 * @param outputStatics
227 * whether to include transient fields
228 * @return the String result
229 * @throws IllegalArgumentException
230 * if the Object is <code>null</code>
231 * @since 2.1
232 */
233 public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics) {
234 return toString(object, style, outputTransients, outputStatics, null);
235 }
236
237 /**
238 * <p>
239 * Builds a <code>toString</code> value through reflection.
240 * </p>
241 *
242 * <p>
243 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
244 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
245 * also not as efficient as testing explicitly.
246 * </p>
247 *
248 * <p>
249 * If the <code>outputTransients</code> is <code>true</code>, transient fields will be output, otherwise they
250 * are ignored, as they are likely derived fields, and not part of the value of the Object.
251 * </p>
252 *
253 * <p>
254 * If the <code>outputStatics</code> is <code>true</code>, static fields will be output, otherwise they are
255 * ignored.
256 * </p>
257 *
258 * <p>
259 * Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as
260 * <code>java.lang.Object</code>.
261 * </p>
262 *
263 * <p>
264 * If the style is <code>null</code>, the default <code>ToStringStyle</code> is used.
265 * </p>
266 *
267 * @param <T>
268 * the type of the object
269 * @param object
270 * the Object to be output
271 * @param style
272 * the style of the <code>toString</code> to create, may be <code>null</code>
273 * @param outputTransients
274 * whether to include transient fields
275 * @param outputStatics
276 * whether to include static fields
277 * @param reflectUpToClass
278 * the superclass to reflect up to (inclusive), may be <code>null</code>
279 * @return the String result
280 * @throws IllegalArgumentException
281 * if the Object is <code>null</code>
282 * @since 2.1
283 */
284 public static <T> String toString(
285 T object, ToStringStyle style, boolean outputTransients,
286 boolean outputStatics, Class<? super T> reflectUpToClass) {
287 return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics)
288 .toString();
289 }
290
291 /**
292 * Builds a String for a toString method excluding the given field names.
293 *
294 * @param object
295 * The object to "toString".
296 * @param excludeFieldNames
297 * The field names to exclude. Null excludes nothing.
298 * @return The toString value.
299 */
300 public static String toStringExclude(Object object, Collection<String> excludeFieldNames) {
301 return toStringExclude(object, toNoNullStringArray(excludeFieldNames));
302 }
303
304 /**
305 * Converts the given Collection into an array of Strings. The returned array does not contain <code>null</code>
306 * entries. Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} if an array element
307 * is <code>null</code>.
308 *
309 * @param collection
310 * The collection to convert
311 * @return A new array of Strings.
312 */
313 static String[] toNoNullStringArray(Collection<String> collection) {
314 if (collection == null) {
315 return ArrayUtils.EMPTY_STRING_ARRAY;
316 }
317 return toNoNullStringArray(collection.toArray());
318 }
319
320 /**
321 * Returns a new array of Strings without null elements. Internal method used to normalize exclude lists
322 * (arrays and collections). Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException}
323 * if an array element is <code>null</code>.
324 *
325 * @param array
326 * The array to check
327 * @return The given array or a new array without null.
328 */
329 static String[] toNoNullStringArray(Object[] array) {
330 List<String> list = new ArrayList<String>(array.length);
331 for (Object e : array) {
332 if (e != null) {
333 list.add(e.toString());
334 }
335 }
336 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
337 }
338
339
340 /**
341 * Builds a String for a toString method excluding the given field names.
342 *
343 * @param object
344 * The object to "toString".
345 * @param excludeFieldNames
346 * The field names to exclude
347 * @return The toString value.
348 */
349 public static String toStringExclude(Object object, String... excludeFieldNames) {
350 return new ReflectionToStringBuilder(object).setExcludeFieldNames(excludeFieldNames).toString();
351 }
352
353 /**
354 * Whether or not to append static fields.
355 */
356 private boolean appendStatics = false;
357
358 /**
359 * Whether or not to append transient fields.
360 */
361 private boolean appendTransients = false;
362
363 /**
364 * Which field names to exclude from output. Intended for fields like <code>"password"</code>.
365 *
366 * @since 3.0 this is protected instead of private
367 */
368 protected String[] excludeFieldNames;
369
370 /**
371 * The last super class to stop appending fields for.
372 */
373 private Class<?> upToClass = null;
374
375 /**
376 * <p>
377 * Constructor.
378 * </p>
379 *
380 * <p>
381 * This constructor outputs using the default style set with <code>setDefaultStyle</code>.
382 * </p>
383 *
384 * @param object
385 * the Object to build a <code>toString</code> for, must not be <code>null</code>
386 * @throws IllegalArgumentException
387 * if the Object passed in is <code>null</code>
388 */
389 public ReflectionToStringBuilder(Object object) {
390 super(object);
391 }
392
393 /**
394 * <p>
395 * Constructor.
396 * </p>
397 *
398 * <p>
399 * If the style is <code>null</code>, the default style is used.
400 * </p>
401 *
402 * @param object
403 * the Object to build a <code>toString</code> for, must not be <code>null</code>
404 * @param style
405 * the style of the <code>toString</code> to create, may be <code>null</code>
406 * @throws IllegalArgumentException
407 * if the Object passed in is <code>null</code>
408 */
409 public ReflectionToStringBuilder(Object object, ToStringStyle style) {
410 super(object, style);
411 }
412
413 /**
414 * <p>
415 * Constructor.
416 * </p>
417 *
418 * <p>
419 * If the style is <code>null</code>, the default style is used.
420 * </p>
421 *
422 * <p>
423 * If the buffer is <code>null</code>, a new one is created.
424 * </p>
425 *
426 * @param object
427 * the Object to build a <code>toString</code> for
428 * @param style
429 * the style of the <code>toString</code> to create, may be <code>null</code>
430 * @param buffer
431 * the <code>StringBuffer</code> to populate, may be <code>null</code>
432 * @throws IllegalArgumentException
433 * if the Object passed in is <code>null</code>
434 */
435 public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
436 super(object, style, buffer);
437 }
438
439 /**
440 * Constructor.
441 *
442 * @param <T>
443 * the type of the object
444 * @param object
445 * the Object to build a <code>toString</code> for
446 * @param style
447 * the style of the <code>toString</code> to create, may be <code>null</code>
448 * @param buffer
449 * the <code>StringBuffer</code> to populate, may be <code>null</code>
450 * @param reflectUpToClass
451 * the superclass to reflect up to (inclusive), may be <code>null</code>
452 * @param outputTransients
453 * whether to include transient fields
454 * @param outputStatics
455 * whether to include static fields
456 * @since 2.1
457 */
458 public <T> ReflectionToStringBuilder(
459 T object, ToStringStyle style, StringBuffer buffer,
460 Class<? super T> reflectUpToClass, boolean outputTransients, boolean outputStatics) {
461 super(object, style, buffer);
462 this.setUpToClass(reflectUpToClass);
463 this.setAppendTransients(outputTransients);
464 this.setAppendStatics(outputStatics);
465 }
466
467 /**
468 * Returns whether or not to append the given <code>Field</code>.
469 * <ul>
470 * <li>Transient fields are appended only if {@link #isAppendTransients()} returns <code>true</code>.
471 * <li>Static fields are appended only if {@link #isAppendStatics()} returns <code>true</code>.
472 * <li>Inner class fields are not appened.</li>
473 * </ul>
474 *
475 * @param field
476 * The Field to test.
477 * @return Whether or not to append the given <code>Field</code>.
478 */
479 protected boolean accept(Field field) {
480 if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) {
481 // Reject field from inner class.
482 return false;
483 }
484 if (Modifier.isTransient(field.getModifiers()) && !this.isAppendTransients()) {
485 // Reject transient fields.
486 return false;
487 }
488 if (Modifier.isStatic(field.getModifiers()) && !this.isAppendStatics()) {
489 // Reject static fields.
490 return false;
491 }
492 if (this.excludeFieldNames != null
493 && Arrays.binarySearch(this.excludeFieldNames, field.getName()) >= 0) {
494 // Reject fields from the getExcludeFieldNames list.
495 return false;
496 }
497 return true;
498 }
499
500 /**
501 * <p>
502 * Appends the fields and values defined by the given object of the given Class.
503 * </p>
504 *
505 * <p>
506 * If a cycle is detected as an object is &quot;toString()'ed&quot;, such an object is rendered as if
507 * <code>Object.toString()</code> had been called and not implemented by the object.
508 * </p>
509 *
510 * @param clazz
511 * The class of object parameter
512 */
513 protected void appendFieldsIn(Class<?> clazz) {
514 if (clazz.isArray()) {
515 this.reflectionAppendArray(this.getObject());
516 return;
517 }
518 Field[] fields = clazz.getDeclaredFields();
519 AccessibleObject.setAccessible(fields, true);
520 for (Field field : fields) {
521 String fieldName = field.getName();
522 if (this.accept(field)) {
523 try {
524 // Warning: Field.get(Object) creates wrappers objects
525 // for primitive types.
526 Object fieldValue = this.getValue(field);
527 this.append(fieldName, fieldValue);
528 } catch (IllegalAccessException ex) {
529 //this can't happen. Would get a Security exception
530 // instead
531 //throw a runtime exception in case the impossible
532 // happens.
533 throw new InternalError("Unexpected IllegalAccessException: " + ex.getMessage());
534 }
535 }
536 }
537 }
538
539 /**
540 * @return Returns the excludeFieldNames.
541 */
542 public String[] getExcludeFieldNames() {
543 return this.excludeFieldNames.clone();
544 }
545
546 /**
547 * <p>
548 * Gets the last super class to stop appending fields for.
549 * </p>
550 *
551 * @return The last super class to stop appending fields for.
552 */
553 public Class<?> getUpToClass() {
554 return this.upToClass;
555 }
556
557 /**
558 * <p>
559 * Calls <code>java.lang.reflect.Field.get(Object)</code>.
560 * </p>
561 *
562 * @param field
563 * The Field to query.
564 * @return The Object from the given Field.
565 *
566 * @throws IllegalArgumentException
567 * see {@link java.lang.reflect.Field#get(Object)}
568 * @throws IllegalAccessException
569 * see {@link java.lang.reflect.Field#get(Object)}
570 *
571 * @see java.lang.reflect.Field#get(Object)
572 */
573 protected Object getValue(Field field) throws IllegalArgumentException, IllegalAccessException {
574 return field.get(this.getObject());
575 }
576
577 /**
578 * <p>
579 * Gets whether or not to append static fields.
580 * </p>
581 *
582 * @return Whether or not to append static fields.
583 * @since 2.1
584 */
585 public boolean isAppendStatics() {
586 return this.appendStatics;
587 }
588
589 /**
590 * <p>
591 * Gets whether or not to append transient fields.
592 * </p>
593 *
594 * @return Whether or not to append transient fields.
595 */
596 public boolean isAppendTransients() {
597 return this.appendTransients;
598 }
599
600 /**
601 * <p>
602 * Append to the <code>toString</code> an <code>Object</code> array.
603 * </p>
604 *
605 * @param array
606 * the array to add to the <code>toString</code>
607 * @return this
608 */
609 public ReflectionToStringBuilder reflectionAppendArray(Object array) {
610 this.getStyle().reflectionAppendArrayDetail(this.getStringBuffer(), null, array);
611 return this;
612 }
613
614 /**
615 * <p>
616 * Sets whether or not to append static fields.
617 * </p>
618 *
619 * @param appendStatics
620 * Whether or not to append static fields.
621 * @since 2.1
622 */
623 public void setAppendStatics(boolean appendStatics) {
624 this.appendStatics = appendStatics;
625 }
626
627 /**
628 * <p>
629 * Sets whether or not to append transient fields.
630 * </p>
631 *
632 * @param appendTransients
633 * Whether or not to append transient fields.
634 */
635 public void setAppendTransients(boolean appendTransients) {
636 this.appendTransients = appendTransients;
637 }
638
639 /**
640 * Sets the field names to exclude.
641 *
642 * @param excludeFieldNamesParam
643 * The excludeFieldNames to excluding from toString or <code>null</code>.
644 * @return <code>this</code>
645 */
646 public ReflectionToStringBuilder setExcludeFieldNames(String... excludeFieldNamesParam) {
647 if (excludeFieldNamesParam == null) {
648 this.excludeFieldNames = null;
649 } else {
650 //clone and remove nulls
651 this.excludeFieldNames = toNoNullStringArray(excludeFieldNamesParam);
652 Arrays.sort(this.excludeFieldNames);
653 }
654 return this;
655 }
656
657 /**
658 * <p>
659 * Sets the last super class to stop appending fields for.
660 * </p>
661 *
662 * @param clazz
663 * The last super class to stop appending fields for.
664 */
665 public void setUpToClass(Class<?> clazz) {
666 if (clazz != null) {
667 Object object = getObject();
668 if (object != null && clazz.isInstance(object) == false) {
669 throw new IllegalArgumentException("Specified class is not a superclass of the object");
670 }
671 }
672 this.upToClass = clazz;
673 }
674
675 /**
676 * <p>
677 * Gets the String built by this builder.
678 * </p>
679 *
680 * @return the built string
681 */
682 @Override
683 public String toString() {
684 if (this.getObject() == null) {
685 return this.getStyle().getNullText();
686 }
687 Class<?> clazz = this.getObject().getClass();
688 this.appendFieldsIn(clazz);
689 while (clazz.getSuperclass() != null && clazz != this.getUpToClass()) {
690 clazz = clazz.getSuperclass();
691 this.appendFieldsIn(clazz);
692 }
693 return super.toString();
694 }
695
696 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 /**
19 * <p>Works with {@link ToStringBuilder} to create a <code>toString</code>.</p>
20 *
21 * <p>This class is intended to be used as a singleton.
22 * There is no need to instantiate a new style each time.
23 * Simply instantiate the class once, customize the values as required, and
24 * store the result in a public static final variable for the rest of the
25 * program to access.</p>
26 *
27 * @since 1.0
28 * @version $Id: StandardToStringStyle.java 1089740 2011-04-07 05:01:54Z bayard $
29 */
30 public class StandardToStringStyle extends ToStringStyle {
31
32 /**
33 * Required for serialization support.
34 *
35 * @see java.io.Serializable
36 */
37 private static final long serialVersionUID = 1L;
38
39 /**
40 * <p>Constructor.</p>
41 */
42 public StandardToStringStyle() {
43 super();
44 }
45
46 //---------------------------------------------------------------------
47
48 /**
49 * <p>Gets whether to use the class name.</p>
50 *
51 * @return the current useClassName flag
52 */
53 @Override
54 public boolean isUseClassName() { // NOPMD as this is implementing the abstract class
55 return super.isUseClassName();
56 }
57
58 /**
59 * <p>Sets whether to use the class name.</p>
60 *
61 * @param useClassName the new useClassName flag
62 */
63 @Override
64 public void setUseClassName(boolean useClassName) { // NOPMD as this is implementing the abstract class
65 super.setUseClassName(useClassName);
66 }
67
68 //---------------------------------------------------------------------
69
70 /**
71 * <p>Gets whether to output short or long class names.</p>
72 *
73 * @return the current useShortClassName flag
74 * @since 2.0
75 */
76 @Override
77 public boolean isUseShortClassName() { // NOPMD as this is implementing the abstract class
78 return super.isUseShortClassName();
79 }
80
81 /**
82 * <p>Sets whether to output short or long class names.</p>
83 *
84 * @param useShortClassName the new useShortClassName flag
85 * @since 2.0
86 */
87 @Override
88 public void setUseShortClassName(boolean useShortClassName) { // NOPMD as this is implementing the abstract class
89 super.setUseShortClassName(useShortClassName);
90 }
91
92 //---------------------------------------------------------------------
93
94 /**
95 * <p>Gets whether to use the identity hash code.</p>
96 * @return the current useIdentityHashCode flag
97 */
98 @Override
99 public boolean isUseIdentityHashCode() { // NOPMD as this is implementing the abstract class
100 return super.isUseIdentityHashCode();
101 }
102
103 /**
104 * <p>Sets whether to use the identity hash code.</p>
105 *
106 * @param useIdentityHashCode the new useIdentityHashCode flag
107 */
108 @Override
109 public void setUseIdentityHashCode(boolean useIdentityHashCode) { // NOPMD as this is implementing the abstract class
110 super.setUseIdentityHashCode(useIdentityHashCode);
111 }
112
113 //---------------------------------------------------------------------
114
115 /**
116 * <p>Gets whether to use the field names passed in.</p>
117 *
118 * @return the current useFieldNames flag
119 */
120 @Override
121 public boolean isUseFieldNames() { // NOPMD as this is implementing the abstract class
122 return super.isUseFieldNames();
123 }
124
125 /**
126 * <p>Sets whether to use the field names passed in.</p>
127 *
128 * @param useFieldNames the new useFieldNames flag
129 */
130 @Override
131 public void setUseFieldNames(boolean useFieldNames) { // NOPMD as this is implementing the abstract class
132 super.setUseFieldNames(useFieldNames);
133 }
134
135 //---------------------------------------------------------------------
136
137 /**
138 * <p>Gets whether to use full detail when the caller doesn't
139 * specify.</p>
140 *
141 * @return the current defaultFullDetail flag
142 */
143 @Override
144 public boolean isDefaultFullDetail() { // NOPMD as this is implementing the abstract class
145 return super.isDefaultFullDetail();
146 }
147
148 /**
149 * <p>Sets whether to use full detail when the caller doesn't
150 * specify.</p>
151 *
152 * @param defaultFullDetail the new defaultFullDetail flag
153 */
154 @Override
155 public void setDefaultFullDetail(boolean defaultFullDetail) { // NOPMD as this is implementing the abstract class
156 super.setDefaultFullDetail(defaultFullDetail);
157 }
158
159 //---------------------------------------------------------------------
160
161 /**
162 * <p>Gets whether to output array content detail.</p>
163 *
164 * @return the current array content detail setting
165 */
166 @Override
167 public boolean isArrayContentDetail() { // NOPMD as this is implementing the abstract class
168 return super.isArrayContentDetail();
169 }
170
171 /**
172 * <p>Sets whether to output array content detail.</p>
173 *
174 * @param arrayContentDetail the new arrayContentDetail flag
175 */
176 @Override
177 public void setArrayContentDetail(boolean arrayContentDetail) { // NOPMD as this is implementing the abstract class
178 super.setArrayContentDetail(arrayContentDetail);
179 }
180
181 //---------------------------------------------------------------------
182
183 /**
184 * <p>Gets the array start text.</p>
185 *
186 * @return the current array start text
187 */
188 @Override
189 public String getArrayStart() { // NOPMD as this is implementing the abstract class
190 return super.getArrayStart();
191 }
192
193 /**
194 * <p>Sets the array start text.</p>
195 *
196 * <p><code>null</code> is accepted, but will be converted
197 * to an empty String.</p>
198 *
199 * @param arrayStart the new array start text
200 */
201 @Override
202 public void setArrayStart(String arrayStart) { // NOPMD as this is implementing the abstract class
203 super.setArrayStart(arrayStart);
204 }
205
206 //---------------------------------------------------------------------
207
208 /**
209 * <p>Gets the array end text.</p>
210 *
211 * @return the current array end text
212 */
213 @Override
214 public String getArrayEnd() { // NOPMD as this is implementing the abstract class
215 return super.getArrayEnd();
216 }
217
218 /**
219 * <p>Sets the array end text.</p>
220 *
221 * <p><code>null</code> is accepted, but will be converted
222 * to an empty String.</p>
223 *
224 * @param arrayEnd the new array end text
225 */
226 @Override
227 public void setArrayEnd(String arrayEnd) { // NOPMD as this is implementing the abstract class
228 super.setArrayEnd(arrayEnd);
229 }
230
231 //---------------------------------------------------------------------
232
233 /**
234 * <p>Gets the array separator text.</p>
235 *
236 * @return the current array separator text
237 */
238 @Override
239 public String getArraySeparator() { // NOPMD as this is implementing the abstract class
240 return super.getArraySeparator();
241 }
242
243 /**
244 * <p>Sets the array separator text.</p>
245 *
246 * <p><code>null</code> is accepted, but will be converted
247 * to an empty String.</p>
248 *
249 * @param arraySeparator the new array separator text
250 */
251 @Override
252 public void setArraySeparator(String arraySeparator) { // NOPMD as this is implementing the abstract class
253 super.setArraySeparator(arraySeparator);
254 }
255
256 //---------------------------------------------------------------------
257
258 /**
259 * <p>Gets the content start text.</p>
260 *
261 * @return the current content start text
262 */
263 @Override
264 public String getContentStart() { // NOPMD as this is implementing the abstract class
265 return super.getContentStart();
266 }
267
268 /**
269 * <p>Sets the content start text.</p>
270 *
271 * <p><code>null</code> is accepted, but will be converted
272 * to an empty String.</p>
273 *
274 * @param contentStart the new content start text
275 */
276 @Override
277 public void setContentStart(String contentStart) { // NOPMD as this is implementing the abstract class
278 super.setContentStart(contentStart);
279 }
280
281 //---------------------------------------------------------------------
282
283 /**
284 * <p>Gets the content end text.</p>
285 *
286 * @return the current content end text
287 */
288 @Override
289 public String getContentEnd() { // NOPMD as this is implementing the abstract class
290 return super.getContentEnd();
291 }
292
293 /**
294 * <p>Sets the content end text.</p>
295 *
296 * <p><code>null</code> is accepted, but will be converted
297 * to an empty String.</p>
298 *
299 * @param contentEnd the new content end text
300 */
301 @Override
302 public void setContentEnd(String contentEnd) { // NOPMD as this is implementing the abstract class
303 super.setContentEnd(contentEnd);
304 }
305
306 //---------------------------------------------------------------------
307
308 /**
309 * <p>Gets the field name value separator text.</p>
310 *
311 * @return the current field name value separator text
312 */
313 @Override
314 public String getFieldNameValueSeparator() { // NOPMD as this is implementing the abstract class
315 return super.getFieldNameValueSeparator();
316 }
317
318 /**
319 * <p>Sets the field name value separator text.</p>
320 *
321 * <p><code>null</code> is accepted, but will be converted
322 * to an empty String.</p>
323 *
324 * @param fieldNameValueSeparator the new field name value separator text
325 */
326 @Override
327 public void setFieldNameValueSeparator(String fieldNameValueSeparator) { // NOPMD as this is implementing the abstract class
328 super.setFieldNameValueSeparator(fieldNameValueSeparator);
329 }
330
331 //---------------------------------------------------------------------
332
333 /**
334 * <p>Gets the field separator text.</p>
335 *
336 * @return the current field separator text
337 */
338 @Override
339 public String getFieldSeparator() { // NOPMD as this is implementing the abstract class
340 return super.getFieldSeparator();
341 }
342
343 /**
344 * <p>Sets the field separator text.</p>
345 *
346 * <p><code>null</code> is accepted, but will be converted
347 * to an empty String.</p>
348 *
349 * @param fieldSeparator the new field separator text
350 */
351 @Override
352 public void setFieldSeparator(String fieldSeparator) { // NOPMD as this is implementing the abstract class
353 super.setFieldSeparator(fieldSeparator);
354 }
355
356 //---------------------------------------------------------------------
357
358 /**
359 * <p>Gets whether the field separator should be added at the start
360 * of each buffer.</p>
361 *
362 * @return the fieldSeparatorAtStart flag
363 * @since 2.0
364 */
365 @Override
366 public boolean isFieldSeparatorAtStart() { // NOPMD as this is implementing the abstract class
367 return super.isFieldSeparatorAtStart();
368 }
369
370 /**
371 * <p>Sets whether the field separator should be added at the start
372 * of each buffer.</p>
373 *
374 * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag
375 * @since 2.0
376 */
377 @Override
378 public void setFieldSeparatorAtStart(boolean fieldSeparatorAtStart) { // NOPMD as this is implementing the abstract class
379 super.setFieldSeparatorAtStart(fieldSeparatorAtStart);
380 }
381
382 //---------------------------------------------------------------------
383
384 /**
385 * <p>Gets whether the field separator should be added at the end
386 * of each buffer.</p>
387 *
388 * @return fieldSeparatorAtEnd flag
389 * @since 2.0
390 */
391 @Override
392 public boolean isFieldSeparatorAtEnd() { // NOPMD as this is implementing the abstract class
393 return super.isFieldSeparatorAtEnd();
394 }
395
396 /**
397 * <p>Sets whether the field separator should be added at the end
398 * of each buffer.</p>
399 *
400 * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag
401 * @since 2.0
402 */
403 @Override
404 public void setFieldSeparatorAtEnd(boolean fieldSeparatorAtEnd) { // NOPMD as this is implementing the abstract class
405 super.setFieldSeparatorAtEnd(fieldSeparatorAtEnd);
406 }
407
408 //---------------------------------------------------------------------
409
410 /**
411 * <p>Gets the text to output when <code>null</code> found.</p>
412 *
413 * @return the current text to output when <code>null</code> found
414 */
415 @Override
416 public String getNullText() { // NOPMD as this is implementing the abstract class
417 return super.getNullText();
418 }
419
420 /**
421 * <p>Sets the text to output when <code>null</code> found.</p>
422 *
423 * <p><code>null</code> is accepted, but will be converted
424 * to an empty String.</p>
425 *
426 * @param nullText the new text to output when <code>null</code> found
427 */
428 @Override
429 public void setNullText(String nullText) { // NOPMD as this is implementing the abstract class
430 super.setNullText(nullText);
431 }
432
433 //---------------------------------------------------------------------
434
435 /**
436 * <p>Gets the text to output when a <code>Collection</code>,
437 * <code>Map</code> or <code>Array</code> size is output.</p>
438 *
439 * <p>This is output before the size value.</p>
440 *
441 * @return the current start of size text
442 */
443 @Override
444 public String getSizeStartText() { // NOPMD as this is implementing the abstract class
445 return super.getSizeStartText();
446 }
447
448 /**
449 * <p>Sets the start text to output when a <code>Collection</code>,
450 * <code>Map</code> or <code>Array</code> size is output.</p>
451 *
452 * <p>This is output before the size value.</p>
453 *
454 * <p><code>null</code> is accepted, but will be converted to
455 * an empty String.</p>
456 *
457 * @param sizeStartText the new start of size text
458 */
459 @Override
460 public void setSizeStartText(String sizeStartText) { // NOPMD as this is implementing the abstract class
461 super.setSizeStartText(sizeStartText);
462 }
463
464 //---------------------------------------------------------------------
465
466 /**
467 * Gets the end text to output when a <code>Collection</code>,
468 * <code>Map</code> or <code>Array</code> size is output.</p>
469 *
470 * <p>This is output after the size value.</p>
471 *
472 * @return the current end of size text
473 */
474 @Override
475 public String getSizeEndText() { // NOPMD as this is implementing the abstract class
476 return super.getSizeEndText();
477 }
478
479 /**
480 * <p>Sets the end text to output when a <code>Collection</code>,
481 * <code>Map</code> or <code>Array</code> size is output.</p>
482 *
483 * <p>This is output after the size value.</p>
484 *
485 * <p><code>null</code> is accepted, but will be converted
486 * to an empty String.</p>
487 *
488 * @param sizeEndText the new end of size text
489 */
490 @Override
491 public void setSizeEndText(String sizeEndText) { // NOPMD as this is implementing the abstract class
492 super.setSizeEndText(sizeEndText);
493 }
494
495 //---------------------------------------------------------------------
496
497 /**
498 * <p>Gets the start text to output when an <code>Object</code> is
499 * output in summary mode.</p>
500 *
501 * <P>This is output before the size value.</p>
502 *
503 * @return the current start of summary text
504 */
505 @Override
506 public String getSummaryObjectStartText() { // NOPMD as this is implementing the abstract class
507 return super.getSummaryObjectStartText();
508 }
509
510 /**
511 * <p>Sets the start text to output when an <code>Object</code> is
512 * output in summary mode.</p>
513 *
514 * <p>This is output before the size value.</p>
515 *
516 * <p><code>null</code> is accepted, but will be converted to
517 * an empty String.</p>
518 *
519 * @param summaryObjectStartText the new start of summary text
520 */
521 @Override
522 public void setSummaryObjectStartText(String summaryObjectStartText) { // NOPMD as this is implementing the abstract class
523 super.setSummaryObjectStartText(summaryObjectStartText);
524 }
525
526 //---------------------------------------------------------------------
527
528 /**
529 * <p>Gets the end text to output when an <code>Object</code> is
530 * output in summary mode.</p>
531 *
532 * <p>This is output after the size value.</p>
533 *
534 * @return the current end of summary text
535 */
536 @Override
537 public String getSummaryObjectEndText() { // NOPMD as this is implementing the abstract class
538 return super.getSummaryObjectEndText();
539 }
540
541 /**
542 * <p>Sets the end text to output when an <code>Object</code> is
543 * output in summary mode.</p>
544 *
545 * <p>This is output after the size value.</p>
546 *
547 * <p><code>null</code> is accepted, but will be converted to
548 * an empty String.</p>
549 *
550 * @param summaryObjectEndText the new end of summary text
551 */
552 @Override
553 public void setSummaryObjectEndText(String summaryObjectEndText) { // NOPMD as this is implementing the abstract class
554 super.setSummaryObjectEndText(summaryObjectEndText);
555 }
556
557 //---------------------------------------------------------------------
558
559 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import org.apache.commons.lang3.ObjectUtils;
19
20 /**
21 * <p>Assists in implementing {@link Object#toString()} methods.</p>
22 *
23 * <p>This class enables a good and consistent <code>toString()</code> to be built for any
24 * class or object. This class aims to simplify the process by:</p>
25 * <ul>
26 * <li>allowing field names</li>
27 * <li>handling all types consistently</li>
28 * <li>handling nulls consistently</li>
29 * <li>outputting arrays and multi-dimensional arrays</li>
30 * <li>enabling the detail level to be controlled for Objects and Collections</li>
31 * <li>handling class hierarchies</li>
32 * </ul>
33 *
34 * <p>To use this class write code as follows:</p>
35 *
36 * <pre>
37 * public class Person {
38 * String name;
39 * int age;
40 * boolean smoker;
41 *
42 * ...
43 *
44 * public String toString() {
45 * return new ToStringBuilder(this).
46 * append("name", name).
47 * append("age", age).
48 * append("smoker", smoker).
49 * toString();
50 * }
51 * }
52 * </pre>
53 *
54 * <p>This will produce a toString of the format:
55 * <code>Person@7f54[name=Stephen,age=29,smoker=false]</code></p>
56 *
57 * <p>To add the superclass <code>toString</code>, use {@link #appendSuper}.
58 * To append the <code>toString</code> from an object that is delegated
59 * to (or any other object), use {@link #appendToString}.</p>
60 *
61 * <p>Alternatively, there is a method that uses reflection to determine
62 * the fields to test. Because these fields are usually private, the method,
63 * <code>reflectionToString</code>, uses <code>AccessibleObject.setAccessible</code> to
64 * change the visibility of the fields. This will fail under a security manager,
65 * unless the appropriate permissions are set up correctly. It is also
66 * slower than testing explicitly.</p>
67 *
68 * <p>A typical invocation for this method would look like:</p>
69 *
70 * <pre>
71 * public String toString() {
72 * return ToStringBuilder.reflectionToString(this);
73 * }
74 * </pre>
75 *
76 * <p>You can also use the builder to debug 3rd party objects:</p>
77 *
78 * <pre>
79 * System.out.println("An object: " + ToStringBuilder.reflectionToString(anObject));
80 * </pre>
81 *
82 * <p>The exact format of the <code>toString</code> is determined by
83 * the {@link ToStringStyle} passed into the constructor.</p>
84 *
85 * @since 1.0
86 * @version $Id: ToStringBuilder.java 1088899 2011-04-05 05:31:27Z bayard $
87 */
88 public class ToStringBuilder implements Builder<String> {
89
90 /**
91 * The default style of output to use, not null.
92 */
93 private static volatile ToStringStyle defaultStyle = ToStringStyle.DEFAULT_STYLE;
94
95 //----------------------------------------------------------------------------
96
97 /**
98 * <p>Gets the default <code>ToStringStyle</code> to use.</p>
99 *
100 * <p>This method gets a singleton default value, typically for the whole JVM.
101 * Changing this default should generally only be done during application startup.
102 * It is recommended to pass a <code>ToStringStyle</code> to the constructor instead
103 * of using this global default.</p>
104 *
105 * <p>This method can be used from multiple threads.
106 * Internally, a <code>volatile</code> variable is used to provide the guarantee
107 * that the latest value set using {@link #setDefaultStyle} is the value returned.
108 * It is strongly recommended that the default style is only changed during application startup.</p>
109 *
110 * <p>One reason for changing the default could be to have a verbose style during
111 * development and a compact style in production.</p>
112 *
113 * @return the default <code>ToStringStyle</code>, never null
114 */
115 public static ToStringStyle getDefaultStyle() {
116 return defaultStyle;
117 }
118
119 /**
120 * <p>Sets the default <code>ToStringStyle</code> to use.</p>
121 *
122 * <p>This method sets a singleton default value, typically for the whole JVM.
123 * Changing this default should generally only be done during application startup.
124 * It is recommended to pass a <code>ToStringStyle</code> to the constructor instead
125 * of changing this global default.</p>
126 *
127 * <p>This method is not intended for use from multiple threads.
128 * Internally, a <code>volatile</code> variable is used to provide the guarantee
129 * that the latest value set is the value returned from {@link #getDefaultStyle}.</p>
130 *
131 * @param style the default <code>ToStringStyle</code>
132 * @throws IllegalArgumentException if the style is <code>null</code>
133 */
134 public static void setDefaultStyle(ToStringStyle style) {
135 if (style == null) {
136 throw new IllegalArgumentException("The style must not be null");
137 }
138 defaultStyle = style;
139 }
140
141 //----------------------------------------------------------------------------
142 /**
143 * <p>Uses <code>ReflectionToStringBuilder</code> to generate a
144 * <code>toString</code> for the specified object.</p>
145 *
146 * @param object the Object to be output
147 * @return the String result
148 * @see ReflectionToStringBuilder#toString(Object)
149 */
150 public static String reflectionToString(Object object) {
151 return ReflectionToStringBuilder.toString(object);
152 }
153
154 /**
155 * <p>Uses <code>ReflectionToStringBuilder</code> to generate a
156 * <code>toString</code> for the specified object.</p>
157 *
158 * @param object the Object to be output
159 * @param style the style of the <code>toString</code> to create, may be <code>null</code>
160 * @return the String result
161 * @see ReflectionToStringBuilder#toString(Object,ToStringStyle)
162 */
163 public static String reflectionToString(Object object, ToStringStyle style) {
164 return ReflectionToStringBuilder.toString(object, style);
165 }
166
167 /**
168 * <p>Uses <code>ReflectionToStringBuilder</code> to generate a
169 * <code>toString</code> for the specified object.</p>
170 *
171 * @param object the Object to be output
172 * @param style the style of the <code>toString</code> to create, may be <code>null</code>
173 * @param outputTransients whether to include transient fields
174 * @return the String result
175 * @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean)
176 */
177 public static String reflectionToString(Object object, ToStringStyle style, boolean outputTransients) {
178 return ReflectionToStringBuilder.toString(object, style, outputTransients, false, null);
179 }
180
181 /**
182 * <p>Uses <code>ReflectionToStringBuilder</code> to generate a
183 * <code>toString</code> for the specified object.</p>
184 *
185 * @param <T> the type of the object
186 * @param object the Object to be output
187 * @param style the style of the <code>toString</code> to create, may be <code>null</code>
188 * @param outputTransients whether to include transient fields
189 * @param reflectUpToClass the superclass to reflect up to (inclusive), may be <code>null</code>
190 * @return the String result
191 * @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean,boolean,Class)
192 * @since 2.0
193 */
194 public static <T> String reflectionToString(
195 T object,
196 ToStringStyle style,
197 boolean outputTransients,
198 Class<? super T> reflectUpToClass) {
199 return ReflectionToStringBuilder.toString(object, style, outputTransients, false, reflectUpToClass);
200 }
201
202 //----------------------------------------------------------------------------
203
204 /**
205 * Current toString buffer, not null.
206 */
207 private final StringBuffer buffer;
208 /**
209 * The object being output, may be null.
210 */
211 private final Object object;
212 /**
213 * The style of output to use, not null.
214 */
215 private final ToStringStyle style;
216
217 /**
218 * <p>Constructs a builder for the specified object using the default output style.</p>
219 *
220 * <p>This default style is obtained from {@link #getDefaultStyle()}.</p>
221 *
222 * @param object the Object to build a <code>toString</code> for, not recommended to be null
223 */
224 public ToStringBuilder(Object object) {
225 this(object, null, null);
226 }
227
228 /**
229 * <p>Constructs a builder for the specified object using the a defined output style.</p>
230 *
231 * <p>If the style is <code>null</code>, the default style is used.</p>
232 *
233 * @param object the Object to build a <code>toString</code> for, not recommended to be null
234 * @param style the style of the <code>toString</code> to create, null uses the default style
235 */
236 public ToStringBuilder(Object object, ToStringStyle style) {
237 this(object, style, null);
238 }
239
240 /**
241 * <p>Constructs a builder for the specified object.</p>
242 *
243 * <p>If the style is <code>null</code>, the default style is used.</p>
244 *
245 * <p>If the buffer is <code>null</code>, a new one is created.</p>
246 *
247 * @param object the Object to build a <code>toString</code> for, not recommended to be null
248 * @param style the style of the <code>toString</code> to create, null uses the default style
249 * @param buffer the <code>StringBuffer</code> to populate, may be null
250 */
251 public ToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
252 if (style == null) {
253 style = getDefaultStyle();
254 }
255 if (buffer == null) {
256 buffer = new StringBuffer(512);
257 }
258 this.buffer = buffer;
259 this.style = style;
260 this.object = object;
261
262 style.appendStart(buffer, object);
263 }
264
265 //----------------------------------------------------------------------------
266
267 /**
268 * <p>Append to the <code>toString</code> a <code>boolean</code>
269 * value.</p>
270 *
271 * @param value the value to add to the <code>toString</code>
272 * @return this
273 */
274 public ToStringBuilder append(boolean value) {
275 style.append(buffer, null, value);
276 return this;
277 }
278
279 //----------------------------------------------------------------------------
280
281 /**
282 * <p>Append to the <code>toString</code> a <code>boolean</code>
283 * array.</p>
284 *
285 * @param array the array to add to the <code>toString</code>
286 * @return this
287 */
288 public ToStringBuilder append(boolean[] array) {
289 style.append(buffer, null, array, null);
290 return this;
291 }
292
293 //----------------------------------------------------------------------------
294
295 /**
296 * <p>Append to the <code>toString</code> a <code>byte</code>
297 * value.</p>
298 *
299 * @param value the value to add to the <code>toString</code>
300 * @return this
301 */
302 public ToStringBuilder append(byte value) {
303 style.append(buffer, null, value);
304 return this;
305 }
306
307 //----------------------------------------------------------------------------
308
309 /**
310 * <p>Append to the <code>toString</code> a <code>byte</code>
311 * array.</p>
312 *
313 * @param array the array to add to the <code>toString</code>
314 * @return this
315 */
316 public ToStringBuilder append(byte[] array) {
317 style.append(buffer, null, array, null);
318 return this;
319 }
320
321 //----------------------------------------------------------------------------
322
323 /**
324 * <p>Append to the <code>toString</code> a <code>char</code>
325 * value.</p>
326 *
327 * @param value the value to add to the <code>toString</code>
328 * @return this
329 */
330 public ToStringBuilder append(char value) {
331 style.append(buffer, null, value);
332 return this;
333 }
334
335 //----------------------------------------------------------------------------
336
337 /**
338 * <p>Append to the <code>toString</code> a <code>char</code>
339 * array.</p>
340 *
341 * @param array the array to add to the <code>toString</code>
342 * @return this
343 */
344 public ToStringBuilder append(char[] array) {
345 style.append(buffer, null, array, null);
346 return this;
347 }
348
349 //----------------------------------------------------------------------------
350
351 /**
352 * <p>Append to the <code>toString</code> a <code>double</code>
353 * value.</p>
354 *
355 * @param value the value to add to the <code>toString</code>
356 * @return this
357 */
358 public ToStringBuilder append(double value) {
359 style.append(buffer, null, value);
360 return this;
361 }
362
363 //----------------------------------------------------------------------------
364
365 /**
366 * <p>Append to the <code>toString</code> a <code>double</code>
367 * array.</p>
368 *
369 * @param array the array to add to the <code>toString</code>
370 * @return this
371 */
372 public ToStringBuilder append(double[] array) {
373 style.append(buffer, null, array, null);
374 return this;
375 }
376
377 //----------------------------------------------------------------------------
378
379 /**
380 * <p>Append to the <code>toString</code> a <code>float</code>
381 * value.</p>
382 *
383 * @param value the value to add to the <code>toString</code>
384 * @return this
385 */
386 public ToStringBuilder append(float value) {
387 style.append(buffer, null, value);
388 return this;
389 }
390
391 //----------------------------------------------------------------------------
392
393 /**
394 * <p>Append to the <code>toString</code> a <code>float</code>
395 * array.</p>
396 *
397 * @param array the array to add to the <code>toString</code>
398 * @return this
399 */
400 public ToStringBuilder append(float[] array) {
401 style.append(buffer, null, array, null);
402 return this;
403 }
404
405 //----------------------------------------------------------------------------
406
407 /**
408 * <p>Append to the <code>toString</code> an <code>int</code>
409 * value.</p>
410 *
411 * @param value the value to add to the <code>toString</code>
412 * @return this
413 */
414 public ToStringBuilder append(int value) {
415 style.append(buffer, null, value);
416 return this;
417 }
418
419 //----------------------------------------------------------------------------
420
421 /**
422 * <p>Append to the <code>toString</code> an <code>int</code>
423 * array.</p>
424 *
425 * @param array the array to add to the <code>toString</code>
426 * @return this
427 */
428 public ToStringBuilder append(int[] array) {
429 style.append(buffer, null, array, null);
430 return this;
431 }
432
433 //----------------------------------------------------------------------------
434
435 /**
436 * <p>Append to the <code>toString</code> a <code>long</code>
437 * value.</p>
438 *
439 * @param value the value to add to the <code>toString</code>
440 * @return this
441 */
442 public ToStringBuilder append(long value) {
443 style.append(buffer, null, value);
444 return this;
445 }
446
447 //----------------------------------------------------------------------------
448
449 /**
450 * <p>Append to the <code>toString</code> a <code>long</code>
451 * array.</p>
452 *
453 * @param array the array to add to the <code>toString</code>
454 * @return this
455 */
456 public ToStringBuilder append(long[] array) {
457 style.append(buffer, null, array, null);
458 return this;
459 }
460
461 //----------------------------------------------------------------------------
462
463 /**
464 * <p>Append to the <code>toString</code> an <code>Object</code>
465 * value.</p>
466 *
467 * @param obj the value to add to the <code>toString</code>
468 * @return this
469 */
470 public ToStringBuilder append(Object obj) {
471 style.append(buffer, null, obj, null);
472 return this;
473 }
474
475 //----------------------------------------------------------------------------
476
477 /**
478 * <p>Append to the <code>toString</code> an <code>Object</code>
479 * array.</p>
480 *
481 * @param array the array to add to the <code>toString</code>
482 * @return this
483 */
484 public ToStringBuilder append(Object[] array) {
485 style.append(buffer, null, array, null);
486 return this;
487 }
488
489 //----------------------------------------------------------------------------
490
491 /**
492 * <p>Append to the <code>toString</code> a <code>short</code>
493 * value.</p>
494 *
495 * @param value the value to add to the <code>toString</code>
496 * @return this
497 */
498 public ToStringBuilder append(short value) {
499 style.append(buffer, null, value);
500 return this;
501 }
502
503 //----------------------------------------------------------------------------
504
505 /**
506 * <p>Append to the <code>toString</code> a <code>short</code>
507 * array.</p>
508 *
509 * @param array the array to add to the <code>toString</code>
510 * @return this
511 */
512 public ToStringBuilder append(short[] array) {
513 style.append(buffer, null, array, null);
514 return this;
515 }
516
517 /**
518 * <p>Append to the <code>toString</code> a <code>boolean</code>
519 * value.</p>
520 *
521 * @param fieldName the field name
522 * @param value the value to add to the <code>toString</code>
523 * @return this
524 */
525 public ToStringBuilder append(String fieldName, boolean value) {
526 style.append(buffer, fieldName, value);
527 return this;
528 }
529
530 /**
531 * <p>Append to the <code>toString</code> a <code>boolean</code>
532 * array.</p>
533 *
534 * @param fieldName the field name
535 * @param array the array to add to the <code>hashCode</code>
536 * @return this
537 */
538 public ToStringBuilder append(String fieldName, boolean[] array) {
539 style.append(buffer, fieldName, array, null);
540 return this;
541 }
542
543 /**
544 * <p>Append to the <code>toString</code> a <code>boolean</code>
545 * array.</p>
546 *
547 * <p>A boolean parameter controls the level of detail to show.
548 * Setting <code>true</code> will output the array in full. Setting
549 * <code>false</code> will output a summary, typically the size of
550 * the array.</p>
551 *
552 * @param fieldName the field name
553 * @param array the array to add to the <code>toString</code>
554 * @param fullDetail <code>true</code> for detail, <code>false</code>
555 * for summary info
556 * @return this
557 */
558 public ToStringBuilder append(String fieldName, boolean[] array, boolean fullDetail) {
559 style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
560 return this;
561 }
562
563 /**
564 * <p>Append to the <code>toString</code> an <code>byte</code>
565 * value.</p>
566 *
567 * @param fieldName the field name
568 * @param value the value to add to the <code>toString</code>
569 * @return this
570 */
571 public ToStringBuilder append(String fieldName, byte value) {
572 style.append(buffer, fieldName, value);
573 return this;
574 }
575
576 /**
577 * <p>Append to the <code>toString</code> a <code>byte</code> array.</p>
578 *
579 * @param fieldName the field name
580 * @param array the array to add to the <code>toString</code>
581 * @return this
582 */
583 public ToStringBuilder append(String fieldName, byte[] array) {
584 style.append(buffer, fieldName, array, null);
585 return this;
586 }
587
588 /**
589 * <p>Append to the <code>toString</code> a <code>byte</code>
590 * array.</p>
591 *
592 * <p>A boolean parameter controls the level of detail to show.
593 * Setting <code>true</code> will output the array in full. Setting
594 * <code>false</code> will output a summary, typically the size of
595 * the array.
596 *
597 * @param fieldName the field name
598 * @param array the array to add to the <code>toString</code>
599 * @param fullDetail <code>true</code> for detail, <code>false</code>
600 * for summary info
601 * @return this
602 */
603 public ToStringBuilder append(String fieldName, byte[] array, boolean fullDetail) {
604 style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
605 return this;
606 }
607
608 /**
609 * <p>Append to the <code>toString</code> a <code>char</code>
610 * value.</p>
611 *
612 * @param fieldName the field name
613 * @param value the value to add to the <code>toString</code>
614 * @return this
615 */
616 public ToStringBuilder append(String fieldName, char value) {
617 style.append(buffer, fieldName, value);
618 return this;
619 }
620
621 /**
622 * <p>Append to the <code>toString</code> a <code>char</code>
623 * array.</p>
624 *
625 * @param fieldName the field name
626 * @param array the array to add to the <code>toString</code>
627 * @return this
628 */
629 public ToStringBuilder append(String fieldName, char[] array) {
630 style.append(buffer, fieldName, array, null);
631 return this;
632 }
633
634 /**
635 * <p>Append to the <code>toString</code> a <code>char</code>
636 * array.</p>
637 *
638 * <p>A boolean parameter controls the level of detail to show.
639 * Setting <code>true</code> will output the array in full. Setting
640 * <code>false</code> will output a summary, typically the size of
641 * the array.</p>
642 *
643 * @param fieldName the field name
644 * @param array the array to add to the <code>toString</code>
645 * @param fullDetail <code>true</code> for detail, <code>false</code>
646 * for summary info
647 * @return this
648 */
649 public ToStringBuilder append(String fieldName, char[] array, boolean fullDetail) {
650 style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
651 return this;
652 }
653
654 /**
655 * <p>Append to the <code>toString</code> a <code>double</code>
656 * value.</p>
657 *
658 * @param fieldName the field name
659 * @param value the value to add to the <code>toString</code>
660 * @return this
661 */
662 public ToStringBuilder append(String fieldName, double value) {
663 style.append(buffer, fieldName, value);
664 return this;
665 }
666
667 /**
668 * <p>Append to the <code>toString</code> a <code>double</code>
669 * array.</p>
670 *
671 * @param fieldName the field name
672 * @param array the array to add to the <code>toString</code>
673 * @return this
674 */
675 public ToStringBuilder append(String fieldName, double[] array) {
676 style.append(buffer, fieldName, array, null);
677 return this;
678 }
679
680 /**
681 * <p>Append to the <code>toString</code> a <code>double</code>
682 * array.</p>
683 *
684 * <p>A boolean parameter controls the level of detail to show.
685 * Setting <code>true</code> will output the array in full. Setting
686 * <code>false</code> will output a summary, typically the size of
687 * the array.</p>
688 *
689 * @param fieldName the field name
690 * @param array the array to add to the <code>toString</code>
691 * @param fullDetail <code>true</code> for detail, <code>false</code>
692 * for summary info
693 * @return this
694 */
695 public ToStringBuilder append(String fieldName, double[] array, boolean fullDetail) {
696 style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
697 return this;
698 }
699
700 /**
701 * <p>Append to the <code>toString</code> an <code>float</code>
702 * value.</p>
703 *
704 * @param fieldName the field name
705 * @param value the value to add to the <code>toString</code>
706 * @return this
707 */
708 public ToStringBuilder append(String fieldName, float value) {
709 style.append(buffer, fieldName, value);
710 return this;
711 }
712
713 /**
714 * <p>Append to the <code>toString</code> a <code>float</code>
715 * array.</p>
716 *
717 * @param fieldName the field name
718 * @param array the array to add to the <code>toString</code>
719 * @return this
720 */
721 public ToStringBuilder append(String fieldName, float[] array) {
722 style.append(buffer, fieldName, array, null);
723 return this;
724 }
725
726 /**
727 * <p>Append to the <code>toString</code> a <code>float</code>
728 * array.</p>
729 *
730 * <p>A boolean parameter controls the level of detail to show.
731 * Setting <code>true</code> will output the array in full. Setting
732 * <code>false</code> will output a summary, typically the size of
733 * the array.</p>
734 *
735 * @param fieldName the field name
736 * @param array the array to add to the <code>toString</code>
737 * @param fullDetail <code>true</code> for detail, <code>false</code>
738 * for summary info
739 * @return this
740 */
741 public ToStringBuilder append(String fieldName, float[] array, boolean fullDetail) {
742 style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
743 return this;
744 }
745
746 /**
747 * <p>Append to the <code>toString</code> an <code>int</code>
748 * value.</p>
749 *
750 * @param fieldName the field name
751 * @param value the value to add to the <code>toString</code>
752 * @return this
753 */
754 public ToStringBuilder append(String fieldName, int value) {
755 style.append(buffer, fieldName, value);
756 return this;
757 }
758
759 /**
760 * <p>Append to the <code>toString</code> an <code>int</code>
761 * array.</p>
762 *
763 * @param fieldName the field name
764 * @param array the array to add to the <code>toString</code>
765 * @return this
766 */
767 public ToStringBuilder append(String fieldName, int[] array) {
768 style.append(buffer, fieldName, array, null);
769 return this;
770 }
771
772 /**
773 * <p>Append to the <code>toString</code> an <code>int</code>
774 * array.</p>
775 *
776 * <p>A boolean parameter controls the level of detail to show.
777 * Setting <code>true</code> will output the array in full. Setting
778 * <code>false</code> will output a summary, typically the size of
779 * the array.</p>
780 *
781 * @param fieldName the field name
782 * @param array the array to add to the <code>toString</code>
783 * @param fullDetail <code>true</code> for detail, <code>false</code>
784 * for summary info
785 * @return this
786 */
787 public ToStringBuilder append(String fieldName, int[] array, boolean fullDetail) {
788 style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
789 return this;
790 }
791
792 /**
793 * <p>Append to the <code>toString</code> a <code>long</code>
794 * value.</p>
795 *
796 * @param fieldName the field name
797 * @param value the value to add to the <code>toString</code>
798 * @return this
799 */
800 public ToStringBuilder append(String fieldName, long value) {
801 style.append(buffer, fieldName, value);
802 return this;
803 }
804
805 /**
806 * <p>Append to the <code>toString</code> a <code>long</code>
807 * array.</p>
808 *
809 * @param fieldName the field name
810 * @param array the array to add to the <code>toString</code>
811 * @return this
812 */
813 public ToStringBuilder append(String fieldName, long[] array) {
814 style.append(buffer, fieldName, array, null);
815 return this;
816 }
817
818 /**
819 * <p>Append to the <code>toString</code> a <code>long</code>
820 * array.</p>
821 *
822 * <p>A boolean parameter controls the level of detail to show.
823 * Setting <code>true</code> will output the array in full. Setting
824 * <code>false</code> will output a summary, typically the size of
825 * the array.</p>
826 *
827 * @param fieldName the field name
828 * @param array the array to add to the <code>toString</code>
829 * @param fullDetail <code>true</code> for detail, <code>false</code>
830 * for summary info
831 * @return this
832 */
833 public ToStringBuilder append(String fieldName, long[] array, boolean fullDetail) {
834 style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
835 return this;
836 }
837
838 /**
839 * <p>Append to the <code>toString</code> an <code>Object</code>
840 * value.</p>
841 *
842 * @param fieldName the field name
843 * @param obj the value to add to the <code>toString</code>
844 * @return this
845 */
846 public ToStringBuilder append(String fieldName, Object obj) {
847 style.append(buffer, fieldName, obj, null);
848 return this;
849 }
850
851 /**
852 * <p>Append to the <code>toString</code> an <code>Object</code>
853 * value.</p>
854 *
855 * @param fieldName the field name
856 * @param obj the value to add to the <code>toString</code>
857 * @param fullDetail <code>true</code> for detail,
858 * <code>false</code> for summary info
859 * @return this
860 */
861 public ToStringBuilder append(String fieldName, Object obj, boolean fullDetail) {
862 style.append(buffer, fieldName, obj, Boolean.valueOf(fullDetail));
863 return this;
864 }
865
866 /**
867 * <p>Append to the <code>toString</code> an <code>Object</code>
868 * array.</p>
869 *
870 * @param fieldName the field name
871 * @param array the array to add to the <code>toString</code>
872 * @return this
873 */
874 public ToStringBuilder append(String fieldName, Object[] array) {
875 style.append(buffer, fieldName, array, null);
876 return this;
877 }
878
879 /**
880 * <p>Append to the <code>toString</code> an <code>Object</code>
881 * array.</p>
882 *
883 * <p>A boolean parameter controls the level of detail to show.
884 * Setting <code>true</code> will output the array in full. Setting
885 * <code>false</code> will output a summary, typically the size of
886 * the array.</p>
887 *
888 * @param fieldName the field name
889 * @param array the array to add to the <code>toString</code>
890 * @param fullDetail <code>true</code> for detail, <code>false</code>
891 * for summary info
892 * @return this
893 */
894 public ToStringBuilder append(String fieldName, Object[] array, boolean fullDetail) {
895 style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
896 return this;
897 }
898
899 /**
900 * <p>Append to the <code>toString</code> an <code>short</code>
901 * value.</p>
902 *
903 * @param fieldName the field name
904 * @param value the value to add to the <code>toString</code>
905 * @return this
906 */
907 public ToStringBuilder append(String fieldName, short value) {
908 style.append(buffer, fieldName, value);
909 return this;
910 }
911
912 /**
913 * <p>Append to the <code>toString</code> a <code>short</code>
914 * array.</p>
915 *
916 * @param fieldName the field name
917 * @param array the array to add to the <code>toString</code>
918 * @return this
919 */
920 public ToStringBuilder append(String fieldName, short[] array) {
921 style.append(buffer, fieldName, array, null);
922 return this;
923 }
924
925 /**
926 * <p>Append to the <code>toString</code> a <code>short</code>
927 * array.</p>
928 *
929 * <p>A boolean parameter controls the level of detail to show.
930 * Setting <code>true</code> will output the array in full. Setting
931 * <code>false</code> will output a summary, typically the size of
932 * the array.
933 *
934 * @param fieldName the field name
935 * @param array the array to add to the <code>toString</code>
936 * @param fullDetail <code>true</code> for detail, <code>false</code>
937 * for summary info
938 * @return this
939 */
940 public ToStringBuilder append(String fieldName, short[] array, boolean fullDetail) {
941 style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
942 return this;
943 }
944
945 /**
946 * <p>Appends with the same format as the default <code>Object toString()
947 * </code> method. Appends the class name followed by
948 * {@link System#identityHashCode(java.lang.Object)}.</p>
949 *
950 * @param object the <code>Object</code> whose class name and id to output
951 * @return this
952 * @since 2.0
953 */
954 public ToStringBuilder appendAsObjectToString(Object object) {
955 ObjectUtils.identityToString(this.getStringBuffer(), object);
956 return this;
957 }
958
959 //----------------------------------------------------------------------------
960
961 /**
962 * <p>Append the <code>toString</code> from the superclass.</p>
963 *
964 * <p>This method assumes that the superclass uses the same <code>ToStringStyle</code>
965 * as this one.</p>
966 *
967 * <p>If <code>superToString</code> is <code>null</code>, no change is made.</p>
968 *
969 * @param superToString the result of <code>super.toString()</code>
970 * @return this
971 * @since 2.0
972 */
973 public ToStringBuilder appendSuper(String superToString) {
974 if (superToString != null) {
975 style.appendSuper(buffer, superToString);
976 }
977 return this;
978 }
979
980 /**
981 * <p>Append the <code>toString</code> from another object.</p>
982 *
983 * <p>This method is useful where a class delegates most of the implementation of
984 * its properties to another class. You can then call <code>toString()</code> on
985 * the other class and pass the result into this method.</p>
986 *
987 * <pre>
988 * private AnotherObject delegate;
989 * private String fieldInThisClass;
990 *
991 * public String toString() {
992 * return new ToStringBuilder(this).
993 * appendToString(delegate.toString()).
994 * append(fieldInThisClass).
995 * toString();
996 * }</pre>
997 *
998 * <p>This method assumes that the other object uses the same <code>ToStringStyle</code>
999 * as this one.</p>
1000 *
1001 * <p>If the <code>toString</code> is <code>null</code>, no change is made.</p>
1002 *
1003 * @param toString the result of <code>toString()</code> on another object
1004 * @return this
1005 * @since 2.0
1006 */
1007 public ToStringBuilder appendToString(String toString) {
1008 if (toString != null) {
1009 style.appendToString(buffer, toString);
1010 }
1011 return this;
1012 }
1013
1014 /**
1015 * <p>Returns the <code>Object</code> being output.</p>
1016 *
1017 * @return The object being output.
1018 * @since 2.0
1019 */
1020 public Object getObject() {
1021 return object;
1022 }
1023
1024 /**
1025 * <p>Gets the <code>StringBuffer</code> being populated.</p>
1026 *
1027 * @return the <code>StringBuffer</code> being populated
1028 */
1029 public StringBuffer getStringBuffer() {
1030 return buffer;
1031 }
1032
1033 //----------------------------------------------------------------------------
1034
1035 /**
1036 * <p>Gets the <code>ToStringStyle</code> being used.</p>
1037 *
1038 * @return the <code>ToStringStyle</code> being used
1039 * @since 2.0
1040 */
1041 public ToStringStyle getStyle() {
1042 return style;
1043 }
1044
1045 /**
1046 * <p>Returns the built <code>toString</code>.</p>
1047 *
1048 * <p>This method appends the end of data indicator, and can only be called once.
1049 * Use {@link #getStringBuffer} to get the current string state.</p>
1050 *
1051 * <p>If the object is <code>null</code>, return the style's <code>nullText</code></p>
1052 *
1053 * @return the String <code>toString</code>
1054 */
1055 @Override
1056 public String toString() {
1057 if (this.getObject() == null) {
1058 this.getStringBuffer().append(this.getStyle().getNullText());
1059 } else {
1060 style.appendEnd(this.getStringBuffer(), this.getObject());
1061 }
1062 return this.getStringBuffer().toString();
1063 }
1064
1065 /**
1066 * Returns the String that was build as an object representation. The
1067 * default implementation utilizes the {@link #toString()} implementation.
1068 *
1069 * @return the String <code>toString</code>
1070 *
1071 * @see #toString()
1072 *
1073 * @since 3.0
1074 */
1075 public String build() {
1076 return toString();
1077 }
1078 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.io.Serializable;
19 import java.lang.reflect.Array;
20 import java.util.Collection;
21 import java.util.Map;
22 import java.util.WeakHashMap;
23
24 import org.apache.commons.lang3.ClassUtils;
25 import org.apache.commons.lang3.ObjectUtils;
26 import org.apache.commons.lang3.SystemUtils;
27
28 /**
29 * <p>Controls <code>String</code> formatting for {@link ToStringBuilder}.
30 * The main public interface is always via <code>ToStringBuilder</code>.</p>
31 *
32 * <p>These classes are intended to be used as <code>Singletons</code>.
33 * There is no need to instantiate a new style each time. A program
34 * will generally use one of the predefined constants on this class.
35 * Alternatively, the {@link StandardToStringStyle} class can be used
36 * to set the individual settings. Thus most styles can be achieved
37 * without subclassing.</p>
38 *
39 * <p>If required, a subclass can override as many or as few of the
40 * methods as it requires. Each object type (from <code>boolean</code>
41 * to <code>long</code> to <code>Object</code> to <code>int[]</code>) has
42 * its own methods to output it. Most have two versions, detail and summary.
43 *
44 * <p>For example, the detail version of the array based methods will
45 * output the whole array, whereas the summary method will just output
46 * the array length.</p>
47 *
48 * <p>If you want to format the output of certain objects, such as dates, you
49 * must create a subclass and override a method.
50 * <pre>
51 * public class MyStyle extends ToStringStyle {
52 * protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
53 * if (value instanceof Date) {
54 * value = new SimpleDateFormat("yyyy-MM-dd").format(value);
55 * }
56 * buffer.append(value);
57 * }
58 * }
59 * </pre>
60 * </p>
61 *
62 * @since 1.0
63 * @version $Id: ToStringStyle.java 1091066 2011-04-11 13:30:11Z mbenson $
64 */
65 public abstract class ToStringStyle implements Serializable {
66
67 /**
68 * Serialization version ID.
69 */
70 private static final long serialVersionUID = -2587890625525655916L;
71
72 /**
73 * The default toString style. Using the Using the <code>Person</code>
74 * example from {@link ToStringBuilder}, the output would look like this:
75 *
76 * <pre>
77 * Person@182f0db[name=John Doe,age=33,smoker=false]
78 * </pre>
79 */
80 public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle();
81
82 /**
83 * The multi line toString style. Using the Using the <code>Person</code>
84 * example from {@link ToStringBuilder}, the output would look like this:
85 *
86 * <pre>
87 * Person@182f0db[
88 * name=John Doe
89 * age=33
90 * smoker=false
91 * ]
92 * </pre>
93 */
94 public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle();
95
96 /**
97 * The no field names toString style. Using the Using the
98 * <code>Person</code> example from {@link ToStringBuilder}, the output
99 * would look like this:
100 *
101 * <pre>
102 * Person@182f0db[John Doe,33,false]
103 * </pre>
104 */
105 public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle();
106
107 /**
108 * The short prefix toString style. Using the <code>Person</code> example
109 * from {@link ToStringBuilder}, the output would look like this:
110 *
111 * <pre>
112 * Person[name=John Doe,age=33,smoker=false]
113 * </pre>
114 *
115 * @since 2.1
116 */
117 public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle();
118
119 /**
120 * The simple toString style. Using the Using the <code>Person</code>
121 * example from {@link ToStringBuilder}, the output would look like this:
122 *
123 * <pre>
124 * John Doe,33,false
125 * </pre>
126 */
127 public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle();
128
129 /**
130 * <p>
131 * A registry of objects used by <code>reflectionToString</code> methods
132 * to detect cyclical object references and avoid infinite loops.
133 * </p>
134 */
135 private static final ThreadLocal<WeakHashMap<Object, Object>> REGISTRY =
136 new ThreadLocal<WeakHashMap<Object,Object>>();
137
138 /**
139 * <p>
140 * Returns the registry of objects being traversed by the <code>reflectionToString</code>
141 * methods in the current thread.
142 * </p>
143 *
144 * @return Set the registry of objects being traversed
145 */
146 static Map<Object, Object> getRegistry() {
147 return REGISTRY.get();
148 }
149
150 /**
151 * <p>
152 * Returns <code>true</code> if the registry contains the given object.
153 * Used by the reflection methods to avoid infinite loops.
154 * </p>
155 *
156 * @param value
157 * The object to lookup in the registry.
158 * @return boolean <code>true</code> if the registry contains the given
159 * object.
160 */
161 static boolean isRegistered(Object value) {
162 Map<Object, Object> m = getRegistry();
163 return m != null && m.containsKey(value);
164 }
165
166 /**
167 * <p>
168 * Registers the given object. Used by the reflection methods to avoid
169 * infinite loops.
170 * </p>
171 *
172 * @param value
173 * The object to register.
174 */
175 static void register(Object value) {
176 if (value != null) {
177 Map<Object, Object> m = getRegistry();
178 if (m == null) {
179 REGISTRY.set(new WeakHashMap<Object, Object>());
180 }
181 getRegistry().put(value, null);
182 }
183 }
184
185 /**
186 * <p>
187 * Unregisters the given object.
188 * </p>
189 *
190 * <p>
191 * Used by the reflection methods to avoid infinite loops.
192 * </p>
193 *
194 * @param value
195 * The object to unregister.
196 */
197 static void unregister(Object value) {
198 if (value != null) {
199 Map<Object, Object> m = getRegistry();
200 if (m != null) {
201 m.remove(value);
202 if (m.isEmpty()) {
203 REGISTRY.remove();
204 }
205 }
206 }
207 }
208
209 /**
210 * Whether to use the field names, the default is <code>true</code>.
211 */
212 private boolean useFieldNames = true;
213
214 /**
215 * Whether to use the class name, the default is <code>true</code>.
216 */
217 private boolean useClassName = true;
218
219 /**
220 * Whether to use short class names, the default is <code>false</code>.
221 */
222 private boolean useShortClassName = false;
223
224 /**
225 * Whether to use the identity hash code, the default is <code>true</code>.
226 */
227 private boolean useIdentityHashCode = true;
228
229 /**
230 * The content start <code>'['</code>.
231 */
232 private String contentStart = "[";
233
234 /**
235 * The content end <code>']'</code>.
236 */
237 private String contentEnd = "]";
238
239 /**
240 * The field name value separator <code>'='</code>.
241 */
242 private String fieldNameValueSeparator = "=";
243
244 /**
245 * Whether the field separator should be added before any other fields.
246 */
247 private boolean fieldSeparatorAtStart = false;
248
249 /**
250 * Whether the field separator should be added after any other fields.
251 */
252 private boolean fieldSeparatorAtEnd = false;
253
254 /**
255 * The field separator <code>','</code>.
256 */
257 private String fieldSeparator = ",";
258
259 /**
260 * The array start <code>'{'</code>.
261 */
262 private String arrayStart = "{";
263
264 /**
265 * The array separator <code>','</code>.
266 */
267 private String arraySeparator = ",";
268
269 /**
270 * The detail for array content.
271 */
272 private boolean arrayContentDetail = true;
273
274 /**
275 * The array end <code>'}'</code>.
276 */
277 private String arrayEnd = "}";
278
279 /**
280 * The value to use when fullDetail is <code>null</code>,
281 * the default value is <code>true</code>.
282 */
283 private boolean defaultFullDetail = true;
284
285 /**
286 * The <code>null</code> text <code>'&lt;null&gt;'</code>.
287 */
288 private String nullText = "<null>";
289
290 /**
291 * The summary size text start <code>'<size'</code>.
292 */
293 private String sizeStartText = "<size=";
294
295 /**
296 * The summary size text start <code>'&gt;'</code>.
297 */
298 private String sizeEndText = ">";
299
300 /**
301 * The summary object text start <code>'&lt;'</code>.
302 */
303 private String summaryObjectStartText = "<";
304
305 /**
306 * The summary object text start <code>'&gt;'</code>.
307 */
308 private String summaryObjectEndText = ">";
309
310 //----------------------------------------------------------------------------
311
312 /**
313 * <p>Constructor.</p>
314 */
315 protected ToStringStyle() {
316 super();
317 }
318
319 //----------------------------------------------------------------------------
320
321 /**
322 * <p>Append to the <code>toString</code> the superclass toString.</p>
323 * <p>NOTE: It assumes that the toString has been created from the same ToStringStyle. </p>
324 *
325 * <p>A <code>null</code> <code>superToString</code> is ignored.</p>
326 *
327 * @param buffer the <code>StringBuffer</code> to populate
328 * @param superToString the <code>super.toString()</code>
329 * @since 2.0
330 */
331 public void appendSuper(StringBuffer buffer, String superToString) {
332 appendToString(buffer, superToString);
333 }
334
335 /**
336 * <p>Append to the <code>toString</code> another toString.</p>
337 * <p>NOTE: It assumes that the toString has been created from the same ToStringStyle. </p>
338 *
339 * <p>A <code>null</code> <code>toString</code> is ignored.</p>
340 *
341 * @param buffer the <code>StringBuffer</code> to populate
342 * @param toString the additional <code>toString</code>
343 * @since 2.0
344 */
345 public void appendToString(StringBuffer buffer, String toString) {
346 if (toString != null) {
347 int pos1 = toString.indexOf(contentStart) + contentStart.length();
348 int pos2 = toString.lastIndexOf(contentEnd);
349 if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) {
350 String data = toString.substring(pos1, pos2);
351 if (fieldSeparatorAtStart) {
352 removeLastFieldSeparator(buffer);
353 }
354 buffer.append(data);
355 appendFieldSeparator(buffer);
356 }
357 }
358 }
359
360 /**
361 * <p>Append to the <code>toString</code> the start of data indicator.</p>
362 *
363 * @param buffer the <code>StringBuffer</code> to populate
364 * @param object the <code>Object</code> to build a <code>toString</code> for
365 */
366 public void appendStart(StringBuffer buffer, Object object) {
367 if (object != null) {
368 appendClassName(buffer, object);
369 appendIdentityHashCode(buffer, object);
370 appendContentStart(buffer);
371 if (fieldSeparatorAtStart) {
372 appendFieldSeparator(buffer);
373 }
374 }
375 }
376
377 /**
378 * <p>Append to the <code>toString</code> the end of data indicator.</p>
379 *
380 * @param buffer the <code>StringBuffer</code> to populate
381 * @param object the <code>Object</code> to build a
382 * <code>toString</code> for.
383 */
384 public void appendEnd(StringBuffer buffer, Object object) {
385 if (this.fieldSeparatorAtEnd == false) {
386 removeLastFieldSeparator(buffer);
387 }
388 appendContentEnd(buffer);
389 unregister(object);
390 }
391
392 /**
393 * <p>Remove the last field separator from the buffer.</p>
394 *
395 * @param buffer the <code>StringBuffer</code> to populate
396 * @since 2.0
397 */
398 protected void removeLastFieldSeparator(StringBuffer buffer) {
399 int len = buffer.length();
400 int sepLen = fieldSeparator.length();
401 if (len > 0 && sepLen > 0 && len >= sepLen) {
402 boolean match = true;
403 for (int i = 0; i < sepLen; i++) {
404 if (buffer.charAt(len - 1 - i) != fieldSeparator.charAt(sepLen - 1 - i)) {
405 match = false;
406 break;
407 }
408 }
409 if (match) {
410 buffer.setLength(len - sepLen);
411 }
412 }
413 }
414
415 //----------------------------------------------------------------------------
416
417 /**
418 * <p>Append to the <code>toString</code> an <code>Object</code>
419 * value, printing the full <code>toString</code> of the
420 * <code>Object</code> passed in.</p>
421 *
422 * @param buffer the <code>StringBuffer</code> to populate
423 * @param fieldName the field name
424 * @param value the value to add to the <code>toString</code>
425 * @param fullDetail <code>true</code> for detail, <code>false</code>
426 * for summary info, <code>null</code> for style decides
427 */
428 public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
429 appendFieldStart(buffer, fieldName);
430
431 if (value == null) {
432 appendNullText(buffer, fieldName);
433
434 } else {
435 appendInternal(buffer, fieldName, value, isFullDetail(fullDetail));
436 }
437
438 appendFieldEnd(buffer, fieldName);
439 }
440
441 /**
442 * <p>Append to the <code>toString</code> an <code>Object</code>,
443 * correctly interpreting its type.</p>
444 *
445 * <p>This method performs the main lookup by Class type to correctly
446 * route arrays, <code>Collections</code>, <code>Maps</code> and
447 * <code>Objects</code> to the appropriate method.</p>
448 *
449 * <p>Either detail or summary views can be specified.</p>
450 *
451 * <p>If a cycle is detected, an object will be appended with the
452 * <code>Object.toString()</code> format.</p>
453 *
454 * @param buffer the <code>StringBuffer</code> to populate
455 * @param fieldName the field name, typically not used as already appended
456 * @param value the value to add to the <code>toString</code>,
457 * not <code>null</code>
458 * @param detail output detail or not
459 */
460 protected void appendInternal(StringBuffer buffer, String fieldName, Object value, boolean detail) {
461 if (isRegistered(value)
462 && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) {
463 appendCyclicObject(buffer, fieldName, value);
464 return;
465 }
466
467 register(value);
468
469 try {
470 if (value instanceof Collection<?>) {
471 if (detail) {
472 appendDetail(buffer, fieldName, (Collection<?>) value);
473 } else {
474 appendSummarySize(buffer, fieldName, ((Collection<?>) value).size());
475 }
476
477 } else if (value instanceof Map<?, ?>) {
478 if (detail) {
479 appendDetail(buffer, fieldName, (Map<?, ?>) value);
480 } else {
481 appendSummarySize(buffer, fieldName, ((Map<?, ?>) value).size());
482 }
483
484 } else if (value instanceof long[]) {
485 if (detail) {
486 appendDetail(buffer, fieldName, (long[]) value);
487 } else {
488 appendSummary(buffer, fieldName, (long[]) value);
489 }
490
491 } else if (value instanceof int[]) {
492 if (detail) {
493 appendDetail(buffer, fieldName, (int[]) value);
494 } else {
495 appendSummary(buffer, fieldName, (int[]) value);
496 }
497
498 } else if (value instanceof short[]) {
499 if (detail) {
500 appendDetail(buffer, fieldName, (short[]) value);
501 } else {
502 appendSummary(buffer, fieldName, (short[]) value);
503 }
504
505 } else if (value instanceof byte[]) {
506 if (detail) {
507 appendDetail(buffer, fieldName, (byte[]) value);
508 } else {
509 appendSummary(buffer, fieldName, (byte[]) value);
510 }
511
512 } else if (value instanceof char[]) {
513 if (detail) {
514 appendDetail(buffer, fieldName, (char[]) value);
515 } else {
516 appendSummary(buffer, fieldName, (char[]) value);
517 }
518
519 } else if (value instanceof double[]) {
520 if (detail) {
521 appendDetail(buffer, fieldName, (double[]) value);
522 } else {
523 appendSummary(buffer, fieldName, (double[]) value);
524 }
525
526 } else if (value instanceof float[]) {
527 if (detail) {
528 appendDetail(buffer, fieldName, (float[]) value);
529 } else {
530 appendSummary(buffer, fieldName, (float[]) value);
531 }
532
533 } else if (value instanceof boolean[]) {
534 if (detail) {
535 appendDetail(buffer, fieldName, (boolean[]) value);
536 } else {
537 appendSummary(buffer, fieldName, (boolean[]) value);
538 }
539
540 } else if (value.getClass().isArray()) {
541 if (detail) {
542 appendDetail(buffer, fieldName, (Object[]) value);
543 } else {
544 appendSummary(buffer, fieldName, (Object[]) value);
545 }
546
547 } else {
548 if (detail) {
549 appendDetail(buffer, fieldName, value);
550 } else {
551 appendSummary(buffer, fieldName, value);
552 }
553 }
554 } finally {
555 unregister(value);
556 }
557 }
558
559 /**
560 * <p>Append to the <code>toString</code> an <code>Object</code>
561 * value that has been detected to participate in a cycle. This
562 * implementation will print the standard string value of the value.</p>
563 *
564 * @param buffer the <code>StringBuffer</code> to populate
565 * @param fieldName the field name, typically not used as already appended
566 * @param value the value to add to the <code>toString</code>,
567 * not <code>null</code>
568 *
569 * @since 2.2
570 */
571 protected void appendCyclicObject(StringBuffer buffer, String fieldName, Object value) {
572 ObjectUtils.identityToString(buffer, value);
573 }
574
575 /**
576 * <p>Append to the <code>toString</code> an <code>Object</code>
577 * value, printing the full detail of the <code>Object</code>.</p>
578 *
579 * @param buffer the <code>StringBuffer</code> to populate
580 * @param fieldName the field name, typically not used as already appended
581 * @param value the value to add to the <code>toString</code>,
582 * not <code>null</code>
583 */
584 protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
585 buffer.append(value);
586 }
587
588 /**
589 * <p>Append to the <code>toString</code> a <code>Collection</code>.</p>
590 *
591 * @param buffer the <code>StringBuffer</code> to populate
592 * @param fieldName the field name, typically not used as already appended
593 * @param coll the <code>Collection</code> to add to the
594 * <code>toString</code>, not <code>null</code>
595 */
596 protected void appendDetail(StringBuffer buffer, String fieldName, Collection<?> coll) {
597 buffer.append(coll);
598 }
599
600 /**
601 * <p>Append to the <code>toString</code> a <code>Map<code>.</p>
602 *
603 * @param buffer the <code>StringBuffer</code> to populate
604 * @param fieldName the field name, typically not used as already appended
605 * @param map the <code>Map</code> to add to the <code>toString</code>,
606 * not <code>null</code>
607 */
608 protected void appendDetail(StringBuffer buffer, String fieldName, Map<?, ?> map) {
609 buffer.append(map);
610 }
611
612 /**
613 * <p>Append to the <code>toString</code> an <code>Object</code>
614 * value, printing a summary of the <code>Object</code>.</P>
615 *
616 * @param buffer the <code>StringBuffer</code> to populate
617 * @param fieldName the field name, typically not used as already appended
618 * @param value the value to add to the <code>toString</code>,
619 * not <code>null</code>
620 */
621 protected void appendSummary(StringBuffer buffer, String fieldName, Object value) {
622 buffer.append(summaryObjectStartText);
623 buffer.append(getShortClassName(value.getClass()));
624 buffer.append(summaryObjectEndText);
625 }
626
627 //----------------------------------------------------------------------------
628
629 /**
630 * <p>Append to the <code>toString</code> a <code>long</code>
631 * value.</p>
632 *
633 * @param buffer the <code>StringBuffer</code> to populate
634 * @param fieldName the field name
635 * @param value the value to add to the <code>toString</code>
636 */
637 public void append(StringBuffer buffer, String fieldName, long value) {
638 appendFieldStart(buffer, fieldName);
639 appendDetail(buffer, fieldName, value);
640 appendFieldEnd(buffer, fieldName);
641 }
642
643 /**
644 * <p>Append to the <code>toString</code> a <code>long</code>
645 * value.</p>
646 *
647 * @param buffer the <code>StringBuffer</code> to populate
648 * @param fieldName the field name, typically not used as already appended
649 * @param value the value to add to the <code>toString</code>
650 */
651 protected void appendDetail(StringBuffer buffer, String fieldName, long value) {
652 buffer.append(value);
653 }
654
655 //----------------------------------------------------------------------------
656
657 /**
658 * <p>Append to the <code>toString</code> an <code>int</code>
659 * value.</p>
660 *
661 * @param buffer the <code>StringBuffer</code> to populate
662 * @param fieldName the field name
663 * @param value the value to add to the <code>toString</code>
664 */
665 public void append(StringBuffer buffer, String fieldName, int value) {
666 appendFieldStart(buffer, fieldName);
667 appendDetail(buffer, fieldName, value);
668 appendFieldEnd(buffer, fieldName);
669 }
670
671 /**
672 * <p>Append to the <code>toString</code> an <code>int</code>
673 * value.</p>
674 *
675 * @param buffer the <code>StringBuffer</code> to populate
676 * @param fieldName the field name, typically not used as already appended
677 * @param value the value to add to the <code>toString</code>
678 */
679 protected void appendDetail(StringBuffer buffer, String fieldName, int value) {
680 buffer.append(value);
681 }
682
683 //----------------------------------------------------------------------------
684
685 /**
686 * <p>Append to the <code>toString</code> a <code>short</code>
687 * value.</p>
688 *
689 * @param buffer the <code>StringBuffer</code> to populate
690 * @param fieldName the field name
691 * @param value the value to add to the <code>toString</code>
692 */
693 public void append(StringBuffer buffer, String fieldName, short value) {
694 appendFieldStart(buffer, fieldName);
695 appendDetail(buffer, fieldName, value);
696 appendFieldEnd(buffer, fieldName);
697 }
698
699 /**
700 * <p>Append to the <code>toString</code> a <code>short</code>
701 * value.</p>
702 *
703 * @param buffer the <code>StringBuffer</code> to populate
704 * @param fieldName the field name, typically not used as already appended
705 * @param value the value to add to the <code>toString</code>
706 */
707 protected void appendDetail(StringBuffer buffer, String fieldName, short value) {
708 buffer.append(value);
709 }
710
711 //----------------------------------------------------------------------------
712
713 /**
714 * <p>Append to the <code>toString</code> a <code>byte</code>
715 * value.</p>
716 *
717 * @param buffer the <code>StringBuffer</code> to populate
718 * @param fieldName the field name
719 * @param value the value to add to the <code>toString</code>
720 */
721 public void append(StringBuffer buffer, String fieldName, byte value) {
722 appendFieldStart(buffer, fieldName);
723 appendDetail(buffer, fieldName, value);
724 appendFieldEnd(buffer, fieldName);
725 }
726
727 /**
728 * <p>Append to the <code>toString</code> a <code>byte</code>
729 * value.</p>
730 *
731 * @param buffer the <code>StringBuffer</code> to populate
732 * @param fieldName the field name, typically not used as already appended
733 * @param value the value to add to the <code>toString</code>
734 */
735 protected void appendDetail(StringBuffer buffer, String fieldName, byte value) {
736 buffer.append(value);
737 }
738
739 //----------------------------------------------------------------------------
740
741 /**
742 * <p>Append to the <code>toString</code> a <code>char</code>
743 * value.</p>
744 *
745 * @param buffer the <code>StringBuffer</code> to populate
746 * @param fieldName the field name
747 * @param value the value to add to the <code>toString</code>
748 */
749 public void append(StringBuffer buffer, String fieldName, char value) {
750 appendFieldStart(buffer, fieldName);
751 appendDetail(buffer, fieldName, value);
752 appendFieldEnd(buffer, fieldName);
753 }
754
755 /**
756 * <p>Append to the <code>toString</code> a <code>char</code>
757 * value.</p>
758 *
759 * @param buffer the <code>StringBuffer</code> to populate
760 * @param fieldName the field name, typically not used as already appended
761 * @param value the value to add to the <code>toString</code>
762 */
763 protected void appendDetail(StringBuffer buffer, String fieldName, char value) {
764 buffer.append(value);
765 }
766
767 //----------------------------------------------------------------------------
768
769 /**
770 * <p>Append to the <code>toString</code> a <code>double</code>
771 * value.</p>
772 *
773 * @param buffer the <code>StringBuffer</code> to populate
774 * @param fieldName the field name
775 * @param value the value to add to the <code>toString</code>
776 */
777 public void append(StringBuffer buffer, String fieldName, double value) {
778 appendFieldStart(buffer, fieldName);
779 appendDetail(buffer, fieldName, value);
780 appendFieldEnd(buffer, fieldName);
781 }
782
783 /**
784 * <p>Append to the <code>toString</code> a <code>double</code>
785 * value.</p>
786 *
787 * @param buffer the <code>StringBuffer</code> to populate
788 * @param fieldName the field name, typically not used as already appended
789 * @param value the value to add to the <code>toString</code>
790 */
791 protected void appendDetail(StringBuffer buffer, String fieldName, double value) {
792 buffer.append(value);
793 }
794
795 //----------------------------------------------------------------------------
796
797 /**
798 * <p>Append to the <code>toString</code> a <code>float</code>
799 * value.</p>
800 *
801 * @param buffer the <code>StringBuffer</code> to populate
802 * @param fieldName the field name
803 * @param value the value to add to the <code>toString</code>
804 */
805 public void append(StringBuffer buffer, String fieldName, float value) {
806 appendFieldStart(buffer, fieldName);
807 appendDetail(buffer, fieldName, value);
808 appendFieldEnd(buffer, fieldName);
809 }
810
811 /**
812 * <p>Append to the <code>toString</code> a <code>float</code>
813 * value.</p>
814 *
815 * @param buffer the <code>StringBuffer</code> to populate
816 * @param fieldName the field name, typically not used as already appended
817 * @param value the value to add to the <code>toString</code>
818 */
819 protected void appendDetail(StringBuffer buffer, String fieldName, float value) {
820 buffer.append(value);
821 }
822
823 //----------------------------------------------------------------------------
824
825 /**
826 * <p>Append to the <code>toString</code> a <code>boolean</code>
827 * value.</p>
828 *
829 * @param buffer the <code>StringBuffer</code> to populate
830 * @param fieldName the field name
831 * @param value the value to add to the <code>toString</code>
832 */
833 public void append(StringBuffer buffer, String fieldName, boolean value) {
834 appendFieldStart(buffer, fieldName);
835 appendDetail(buffer, fieldName, value);
836 appendFieldEnd(buffer, fieldName);
837 }
838
839 /**
840 * <p>Append to the <code>toString</code> a <code>boolean</code>
841 * value.</p>
842 *
843 * @param buffer the <code>StringBuffer</code> to populate
844 * @param fieldName the field name, typically not used as already appended
845 * @param value the value to add to the <code>toString</code>
846 */
847 protected void appendDetail(StringBuffer buffer, String fieldName, boolean value) {
848 buffer.append(value);
849 }
850
851 /**
852 * <p>Append to the <code>toString</code> an <code>Object</code>
853 * array.</p>
854 *
855 * @param buffer the <code>StringBuffer</code> to populate
856 * @param fieldName the field name
857 * @param array the array to add to the toString
858 * @param fullDetail <code>true</code> for detail, <code>false</code>
859 * for summary info, <code>null</code> for style decides
860 */
861 public void append(StringBuffer buffer, String fieldName, Object[] array, Boolean fullDetail) {
862 appendFieldStart(buffer, fieldName);
863
864 if (array == null) {
865 appendNullText(buffer, fieldName);
866
867 } else if (isFullDetail(fullDetail)) {
868 appendDetail(buffer, fieldName, array);
869
870 } else {
871 appendSummary(buffer, fieldName, array);
872 }
873
874 appendFieldEnd(buffer, fieldName);
875 }
876
877 //----------------------------------------------------------------------------
878
879 /**
880 * <p>Append to the <code>toString</code> the detail of an
881 * <code>Object</code> array.</p>
882 *
883 * @param buffer the <code>StringBuffer</code> to populate
884 * @param fieldName the field name, typically not used as already appended
885 * @param array the array to add to the <code>toString</code>,
886 * not <code>null</code>
887 */
888 protected void appendDetail(StringBuffer buffer, String fieldName, Object[] array) {
889 buffer.append(arrayStart);
890 for (int i = 0; i < array.length; i++) {
891 Object item = array[i];
892 if (i > 0) {
893 buffer.append(arraySeparator);
894 }
895 if (item == null) {
896 appendNullText(buffer, fieldName);
897
898 } else {
899 appendInternal(buffer, fieldName, item, arrayContentDetail);
900 }
901 }
902 buffer.append(arrayEnd);
903 }
904
905 /**
906 * <p>Append to the <code>toString</code> the detail of an array type.</p>
907 *
908 * @param buffer the <code>StringBuffer</code> to populate
909 * @param fieldName the field name, typically not used as already appended
910 * @param array the array to add to the <code>toString</code>,
911 * not <code>null</code>
912 * @since 2.0
913 */
914 protected void reflectionAppendArrayDetail(StringBuffer buffer, String fieldName, Object array) {
915 buffer.append(arrayStart);
916 int length = Array.getLength(array);
917 for (int i = 0; i < length; i++) {
918 Object item = Array.get(array, i);
919 if (i > 0) {
920 buffer.append(arraySeparator);
921 }
922 if (item == null) {
923 appendNullText(buffer, fieldName);
924
925 } else {
926 appendInternal(buffer, fieldName, item, arrayContentDetail);
927 }
928 }
929 buffer.append(arrayEnd);
930 }
931
932 /**
933 * <p>Append to the <code>toString</code> a summary of an
934 * <code>Object</code> array.</p>
935 *
936 * @param buffer the <code>StringBuffer</code> to populate
937 * @param fieldName the field name, typically not used as already appended
938 * @param array the array to add to the <code>toString</code>,
939 * not <code>null</code>
940 */
941 protected void appendSummary(StringBuffer buffer, String fieldName, Object[] array) {
942 appendSummarySize(buffer, fieldName, array.length);
943 }
944
945 //----------------------------------------------------------------------------
946
947 /**
948 * <p>Append to the <code>toString</code> a <code>long</code>
949 * array.</p>
950 *
951 * @param buffer the <code>StringBuffer</code> to populate
952 * @param fieldName the field name
953 * @param array the array to add to the <code>toString</code>
954 * @param fullDetail <code>true</code> for detail, <code>false</code>
955 * for summary info, <code>null</code> for style decides
956 */
957 public void append(StringBuffer buffer, String fieldName, long[] array, Boolean fullDetail) {
958 appendFieldStart(buffer, fieldName);
959
960 if (array == null) {
961 appendNullText(buffer, fieldName);
962
963 } else if (isFullDetail(fullDetail)) {
964 appendDetail(buffer, fieldName, array);
965
966 } else {
967 appendSummary(buffer, fieldName, array);
968 }
969
970 appendFieldEnd(buffer, fieldName);
971 }
972
973 /**
974 * <p>Append to the <code>toString</code> the detail of a
975 * <code>long</code> array.</p>
976 *
977 * @param buffer the <code>StringBuffer</code> to populate
978 * @param fieldName the field name, typically not used as already appended
979 * @param array the array to add to the <code>toString</code>,
980 * not <code>null</code>
981 */
982 protected void appendDetail(StringBuffer buffer, String fieldName, long[] array) {
983 buffer.append(arrayStart);
984 for (int i = 0; i < array.length; i++) {
985 if (i > 0) {
986 buffer.append(arraySeparator);
987 }
988 appendDetail(buffer, fieldName, array[i]);
989 }
990 buffer.append(arrayEnd);
991 }
992
993 /**
994 * <p>Append to the <code>toString</code> a summary of a
995 * <code>long</code> array.</p>
996 *
997 * @param buffer the <code>StringBuffer</code> to populate
998 * @param fieldName the field name, typically not used as already appended
999 * @param array the array to add to the <code>toString</code>,
1000 * not <code>null</code>
1001 */
1002 protected void appendSummary(StringBuffer buffer, String fieldName, long[] array) {
1003 appendSummarySize(buffer, fieldName, array.length);
1004 }
1005
1006 //----------------------------------------------------------------------------
1007
1008 /**
1009 * <p>Append to the <code>toString</code> an <code>int</code>
1010 * array.</p>
1011 *
1012 * @param buffer the <code>StringBuffer</code> to populate
1013 * @param fieldName the field name
1014 * @param array the array to add to the <code>toString</code>
1015 * @param fullDetail <code>true</code> for detail, <code>false</code>
1016 * for summary info, <code>null</code> for style decides
1017 */
1018 public void append(StringBuffer buffer, String fieldName, int[] array, Boolean fullDetail) {
1019 appendFieldStart(buffer, fieldName);
1020
1021 if (array == null) {
1022 appendNullText(buffer, fieldName);
1023
1024 } else if (isFullDetail(fullDetail)) {
1025 appendDetail(buffer, fieldName, array);
1026
1027 } else {
1028 appendSummary(buffer, fieldName, array);
1029 }
1030
1031 appendFieldEnd(buffer, fieldName);
1032 }
1033
1034 /**
1035 * <p>Append to the <code>toString</code> the detail of an
1036 * <code>int</code> array.</p>
1037 *
1038 * @param buffer the <code>StringBuffer</code> to populate
1039 * @param fieldName the field name, typically not used as already appended
1040 * @param array the array to add to the <code>toString</code>,
1041 * not <code>null</code>
1042 */
1043 protected void appendDetail(StringBuffer buffer, String fieldName, int[] array) {
1044 buffer.append(arrayStart);
1045 for (int i = 0; i < array.length; i++) {
1046 if (i > 0) {
1047 buffer.append(arraySeparator);
1048 }
1049 appendDetail(buffer, fieldName, array[i]);
1050 }
1051 buffer.append(arrayEnd);
1052 }
1053
1054 /**
1055 * <p>Append to the <code>toString</code> a summary of an
1056 * <code>int</code> array.</p>
1057 *
1058 * @param buffer the <code>StringBuffer</code> to populate
1059 * @param fieldName the field name, typically not used as already appended
1060 * @param array the array to add to the <code>toString</code>,
1061 * not <code>null</code>
1062 */
1063 protected void appendSummary(StringBuffer buffer, String fieldName, int[] array) {
1064 appendSummarySize(buffer, fieldName, array.length);
1065 }
1066
1067 //----------------------------------------------------------------------------
1068
1069 /**
1070 * <p>Append to the <code>toString</code> a <code>short</code>
1071 * array.</p>
1072 *
1073 * @param buffer the <code>StringBuffer</code> to populate
1074 * @param fieldName the field name
1075 * @param array the array to add to the <code>toString</code>
1076 * @param fullDetail <code>true</code> for detail, <code>false</code>
1077 * for summary info, <code>null</code> for style decides
1078 */
1079 public void append(StringBuffer buffer, String fieldName, short[] array, Boolean fullDetail) {
1080 appendFieldStart(buffer, fieldName);
1081
1082 if (array == null) {
1083 appendNullText(buffer, fieldName);
1084
1085 } else if (isFullDetail(fullDetail)) {
1086 appendDetail(buffer, fieldName, array);
1087
1088 } else {
1089 appendSummary(buffer, fieldName, array);
1090 }
1091
1092 appendFieldEnd(buffer, fieldName);
1093 }
1094
1095 /**
1096 * <p>Append to the <code>toString</code> the detail of a
1097 * <code>short</code> array.</p>
1098 *
1099 * @param buffer the <code>StringBuffer</code> to populate
1100 * @param fieldName the field name, typically not used as already appended
1101 * @param array the array to add to the <code>toString</code>,
1102 * not <code>null</code>
1103 */
1104 protected void appendDetail(StringBuffer buffer, String fieldName, short[] array) {
1105 buffer.append(arrayStart);
1106 for (int i = 0; i < array.length; i++) {
1107 if (i > 0) {
1108 buffer.append(arraySeparator);
1109 }
1110 appendDetail(buffer, fieldName, array[i]);
1111 }
1112 buffer.append(arrayEnd);
1113 }
1114
1115 /**
1116 * <p>Append to the <code>toString</code> a summary of a
1117 * <code>short</code> array.</p>
1118 *
1119 * @param buffer the <code>StringBuffer</code> to populate
1120 * @param fieldName the field name, typically not used as already appended
1121 * @param array the array to add to the <code>toString</code>,
1122 * not <code>null</code>
1123 */
1124 protected void appendSummary(StringBuffer buffer, String fieldName, short[] array) {
1125 appendSummarySize(buffer, fieldName, array.length);
1126 }
1127
1128 //----------------------------------------------------------------------------
1129
1130 /**
1131 * <p>Append to the <code>toString</code> a <code>byte</code>
1132 * array.</p>
1133 *
1134 * @param buffer the <code>StringBuffer</code> to populate
1135 * @param fieldName the field name
1136 * @param array the array to add to the <code>toString</code>
1137 * @param fullDetail <code>true</code> for detail, <code>false</code>
1138 * for summary info, <code>null</code> for style decides
1139 */
1140 public void append(StringBuffer buffer, String fieldName, byte[] array, Boolean fullDetail) {
1141 appendFieldStart(buffer, fieldName);
1142
1143 if (array == null) {
1144 appendNullText(buffer, fieldName);
1145
1146 } else if (isFullDetail(fullDetail)) {
1147 appendDetail(buffer, fieldName, array);
1148
1149 } else {
1150 appendSummary(buffer, fieldName, array);
1151 }
1152
1153 appendFieldEnd(buffer, fieldName);
1154 }
1155
1156 /**
1157 * <p>Append to the <code>toString</code> the detail of a
1158 * <code>byte</code> array.</p>
1159 *
1160 * @param buffer the <code>StringBuffer</code> to populate
1161 * @param fieldName the field name, typically not used as already appended
1162 * @param array the array to add to the <code>toString</code>,
1163 * not <code>null</code>
1164 */
1165 protected void appendDetail(StringBuffer buffer, String fieldName, byte[] array) {
1166 buffer.append(arrayStart);
1167 for (int i = 0; i < array.length; i++) {
1168 if (i > 0) {
1169 buffer.append(arraySeparator);
1170 }
1171 appendDetail(buffer, fieldName, array[i]);
1172 }
1173 buffer.append(arrayEnd);
1174 }
1175
1176 /**
1177 * <p>Append to the <code>toString</code> a summary of a
1178 * <code>byte</code> array.</p>
1179 *
1180 * @param buffer the <code>StringBuffer</code> to populate
1181 * @param fieldName the field name, typically not used as already appended
1182 * @param array the array to add to the <code>toString</code>,
1183 * not <code>null</code>
1184 */
1185 protected void appendSummary(StringBuffer buffer, String fieldName, byte[] array) {
1186 appendSummarySize(buffer, fieldName, array.length);
1187 }
1188
1189 //----------------------------------------------------------------------------
1190
1191 /**
1192 * <p>Append to the <code>toString</code> a <code>char</code>
1193 * array.</p>
1194 *
1195 * @param buffer the <code>StringBuffer</code> to populate
1196 * @param fieldName the field name
1197 * @param array the array to add to the <code>toString</code>
1198 * @param fullDetail <code>true</code> for detail, <code>false</code>
1199 * for summary info, <code>null</code> for style decides
1200 */
1201 public void append(StringBuffer buffer, String fieldName, char[] array, Boolean fullDetail) {
1202 appendFieldStart(buffer, fieldName);
1203
1204 if (array == null) {
1205 appendNullText(buffer, fieldName);
1206
1207 } else if (isFullDetail(fullDetail)) {
1208 appendDetail(buffer, fieldName, array);
1209
1210 } else {
1211 appendSummary(buffer, fieldName, array);
1212 }
1213
1214 appendFieldEnd(buffer, fieldName);
1215 }
1216
1217 /**
1218 * <p>Append to the <code>toString</code> the detail of a
1219 * <code>char</code> array.</p>
1220 *
1221 * @param buffer the <code>StringBuffer</code> to populate
1222 * @param fieldName the field name, typically not used as already appended
1223 * @param array the array to add to the <code>toString</code>,
1224 * not <code>null</code>
1225 */
1226 protected void appendDetail(StringBuffer buffer, String fieldName, char[] array) {
1227 buffer.append(arrayStart);
1228 for (int i = 0; i < array.length; i++) {
1229 if (i > 0) {
1230 buffer.append(arraySeparator);
1231 }
1232 appendDetail(buffer, fieldName, array[i]);
1233 }
1234 buffer.append(arrayEnd);
1235 }
1236
1237 /**
1238 * <p>Append to the <code>toString</code> a summary of a
1239 * <code>char</code> array.</p>
1240 *
1241 * @param buffer the <code>StringBuffer</code> to populate
1242 * @param fieldName the field name, typically not used as already appended
1243 * @param array the array to add to the <code>toString</code>,
1244 * not <code>null</code>
1245 */
1246 protected void appendSummary(StringBuffer buffer, String fieldName, char[] array) {
1247 appendSummarySize(buffer, fieldName, array.length);
1248 }
1249
1250 //----------------------------------------------------------------------------
1251
1252 /**
1253 * <p>Append to the <code>toString</code> a <code>double</code>
1254 * array.</p>
1255 *
1256 * @param buffer the <code>StringBuffer</code> to populate
1257 * @param fieldName the field name
1258 * @param array the array to add to the toString
1259 * @param fullDetail <code>true</code> for detail, <code>false</code>
1260 * for summary info, <code>null</code> for style decides
1261 */
1262 public void append(StringBuffer buffer, String fieldName, double[] array, Boolean fullDetail) {
1263 appendFieldStart(buffer, fieldName);
1264
1265 if (array == null) {
1266 appendNullText(buffer, fieldName);
1267
1268 } else if (isFullDetail(fullDetail)) {
1269 appendDetail(buffer, fieldName, array);
1270
1271 } else {
1272 appendSummary(buffer, fieldName, array);
1273 }
1274
1275 appendFieldEnd(buffer, fieldName);
1276 }
1277
1278 /**
1279 * <p>Append to the <code>toString</code> the detail of a
1280 * <code>double</code> array.</p>
1281 *
1282 * @param buffer the <code>StringBuffer</code> to populate
1283 * @param fieldName the field name, typically not used as already appended
1284 * @param array the array to add to the <code>toString</code>,
1285 * not <code>null</code>
1286 */
1287 protected void appendDetail(StringBuffer buffer, String fieldName, double[] array) {
1288 buffer.append(arrayStart);
1289 for (int i = 0; i < array.length; i++) {
1290 if (i > 0) {
1291 buffer.append(arraySeparator);
1292 }
1293 appendDetail(buffer, fieldName, array[i]);
1294 }
1295 buffer.append(arrayEnd);
1296 }
1297
1298 /**
1299 * <p>Append to the <code>toString</code> a summary of a
1300 * <code>double</code> array.</p>
1301 *
1302 * @param buffer the <code>StringBuffer</code> to populate
1303 * @param fieldName the field name, typically not used as already appended
1304 * @param array the array to add to the <code>toString</code>,
1305 * not <code>null</code>
1306 */
1307 protected void appendSummary(StringBuffer buffer, String fieldName, double[] array) {
1308 appendSummarySize(buffer, fieldName, array.length);
1309 }
1310
1311 //----------------------------------------------------------------------------
1312
1313 /**
1314 * <p>Append to the <code>toString</code> a <code>float</code>
1315 * array.</p>
1316 *
1317 * @param buffer the <code>StringBuffer</code> to populate
1318 * @param fieldName the field name
1319 * @param array the array to add to the toString
1320 * @param fullDetail <code>true</code> for detail, <code>false</code>
1321 * for summary info, <code>null</code> for style decides
1322 */
1323 public void append(StringBuffer buffer, String fieldName, float[] array, Boolean fullDetail) {
1324 appendFieldStart(buffer, fieldName);
1325
1326 if (array == null) {
1327 appendNullText(buffer, fieldName);
1328
1329 } else if (isFullDetail(fullDetail)) {
1330 appendDetail(buffer, fieldName, array);
1331
1332 } else {
1333 appendSummary(buffer, fieldName, array);
1334 }
1335
1336 appendFieldEnd(buffer, fieldName);
1337 }
1338
1339 /**
1340 * <p>Append to the <code>toString</code> the detail of a
1341 * <code>float</code> array.</p>
1342 *
1343 * @param buffer the <code>StringBuffer</code> to populate
1344 * @param fieldName the field name, typically not used as already appended
1345 * @param array the array to add to the <code>toString</code>,
1346 * not <code>null</code>
1347 */
1348 protected void appendDetail(StringBuffer buffer, String fieldName, float[] array) {
1349 buffer.append(arrayStart);
1350 for (int i = 0; i < array.length; i++) {
1351 if (i > 0) {
1352 buffer.append(arraySeparator);
1353 }
1354 appendDetail(buffer, fieldName, array[i]);
1355 }
1356 buffer.append(arrayEnd);
1357 }
1358
1359 /**
1360 * <p>Append to the <code>toString</code> a summary of a
1361 * <code>float</code> array.</p>
1362 *
1363 * @param buffer the <code>StringBuffer</code> to populate
1364 * @param fieldName the field name, typically not used as already appended
1365 * @param array the array to add to the <code>toString</code>,
1366 * not <code>null</code>
1367 */
1368 protected void appendSummary(StringBuffer buffer, String fieldName, float[] array) {
1369 appendSummarySize(buffer, fieldName, array.length);
1370 }
1371
1372 //----------------------------------------------------------------------------
1373
1374 /**
1375 * <p>Append to the <code>toString</code> a <code>boolean</code>
1376 * array.</p>
1377 *
1378 * @param buffer the <code>StringBuffer</code> to populate
1379 * @param fieldName the field name
1380 * @param array the array to add to the toString
1381 * @param fullDetail <code>true</code> for detail, <code>false</code>
1382 * for summary info, <code>null</code> for style decides
1383 */
1384 public void append(StringBuffer buffer, String fieldName, boolean[] array, Boolean fullDetail) {
1385 appendFieldStart(buffer, fieldName);
1386
1387 if (array == null) {
1388 appendNullText(buffer, fieldName);
1389
1390 } else if (isFullDetail(fullDetail)) {
1391 appendDetail(buffer, fieldName, array);
1392
1393 } else {
1394 appendSummary(buffer, fieldName, array);
1395 }
1396
1397 appendFieldEnd(buffer, fieldName);
1398 }
1399
1400 /**
1401 * <p>Append to the <code>toString</code> the detail of a
1402 * <code>boolean</code> array.</p>
1403 *
1404 * @param buffer the <code>StringBuffer</code> to populate
1405 * @param fieldName the field name, typically not used as already appended
1406 * @param array the array to add to the <code>toString</code>,
1407 * not <code>null</code>
1408 */
1409 protected void appendDetail(StringBuffer buffer, String fieldName, boolean[] array) {
1410 buffer.append(arrayStart);
1411 for (int i = 0; i < array.length; i++) {
1412 if (i > 0) {
1413 buffer.append(arraySeparator);
1414 }
1415 appendDetail(buffer, fieldName, array[i]);
1416 }
1417 buffer.append(arrayEnd);
1418 }
1419
1420 /**
1421 * <p>Append to the <code>toString</code> a summary of a
1422 * <code>boolean</code> array.</p>
1423 *
1424 * @param buffer the <code>StringBuffer</code> to populate
1425 * @param fieldName the field name, typically not used as already appended
1426 * @param array the array to add to the <code>toString</code>,
1427 * not <code>null</code>
1428 */
1429 protected void appendSummary(StringBuffer buffer, String fieldName, boolean[] array) {
1430 appendSummarySize(buffer, fieldName, array.length);
1431 }
1432
1433 //----------------------------------------------------------------------------
1434
1435 /**
1436 * <p>Append to the <code>toString</code> the class name.</p>
1437 *
1438 * @param buffer the <code>StringBuffer</code> to populate
1439 * @param object the <code>Object</code> whose name to output
1440 */
1441 protected void appendClassName(StringBuffer buffer, Object object) {
1442 if (useClassName && object != null) {
1443 register(object);
1444 if (useShortClassName) {
1445 buffer.append(getShortClassName(object.getClass()));
1446 } else {
1447 buffer.append(object.getClass().getName());
1448 }
1449 }
1450 }
1451
1452 /**
1453 * <p>Append the {@link System#identityHashCode(java.lang.Object)}.</p>
1454 *
1455 * @param buffer the <code>StringBuffer</code> to populate
1456 * @param object the <code>Object</code> whose id to output
1457 */
1458 protected void appendIdentityHashCode(StringBuffer buffer, Object object) {
1459 if (this.isUseIdentityHashCode() && object!=null) {
1460 register(object);
1461 buffer.append('@');
1462 buffer.append(Integer.toHexString(System.identityHashCode(object)));
1463 }
1464 }
1465
1466 /**
1467 * <p>Append to the <code>toString</code> the content start.</p>
1468 *
1469 * @param buffer the <code>StringBuffer</code> to populate
1470 */
1471 protected void appendContentStart(StringBuffer buffer) {
1472 buffer.append(contentStart);
1473 }
1474
1475 /**
1476 * <p>Append to the <code>toString</code> the content end.</p>
1477 *
1478 * @param buffer the <code>StringBuffer</code> to populate
1479 */
1480 protected void appendContentEnd(StringBuffer buffer) {
1481 buffer.append(contentEnd);
1482 }
1483
1484 /**
1485 * <p>Append to the <code>toString</code> an indicator for <code>null</code>.</p>
1486 *
1487 * <p>The default indicator is <code>'&lt;null&gt;'</code>.</p>
1488 *
1489 * @param buffer the <code>StringBuffer</code> to populate
1490 * @param fieldName the field name, typically not used as already appended
1491 */
1492 protected void appendNullText(StringBuffer buffer, String fieldName) {
1493 buffer.append(nullText);
1494 }
1495
1496 /**
1497 * <p>Append to the <code>toString</code> the field separator.</p>
1498 *
1499 * @param buffer the <code>StringBuffer</code> to populate
1500 */
1501 protected void appendFieldSeparator(StringBuffer buffer) {
1502 buffer.append(fieldSeparator);
1503 }
1504
1505 /**
1506 * <p>Append to the <code>toString</code> the field start.</p>
1507 *
1508 * @param buffer the <code>StringBuffer</code> to populate
1509 * @param fieldName the field name
1510 */
1511 protected void appendFieldStart(StringBuffer buffer, String fieldName) {
1512 if (useFieldNames && fieldName != null) {
1513 buffer.append(fieldName);
1514 buffer.append(fieldNameValueSeparator);
1515 }
1516 }
1517
1518 /**
1519 * <p>Append to the <code>toString<code> the field end.</p>
1520 *
1521 * @param buffer the <code>StringBuffer</code> to populate
1522 * @param fieldName the field name, typically not used as already appended
1523 */
1524 protected void appendFieldEnd(StringBuffer buffer, String fieldName) {
1525 appendFieldSeparator(buffer);
1526 }
1527
1528 /**
1529 * <p>Append to the <code>toString</code> a size summary.</p>
1530 *
1531 * <p>The size summary is used to summarize the contents of
1532 * <code>Collections</code>, <code>Maps</code> and arrays.</p>
1533 *
1534 * <p>The output consists of a prefix, the passed in size
1535 * and a suffix.</p>
1536 *
1537 * <p>The default format is <code>'&lt;size=n&gt;'<code>.</p>
1538 *
1539 * @param buffer the <code>StringBuffer</code> to populate
1540 * @param fieldName the field name, typically not used as already appended
1541 * @param size the size to append
1542 */
1543 protected void appendSummarySize(StringBuffer buffer, String fieldName, int size) {
1544 buffer.append(sizeStartText);
1545 buffer.append(size);
1546 buffer.append(sizeEndText);
1547 }
1548
1549 /**
1550 * <p>Is this field to be output in full detail.</p>
1551 *
1552 * <p>This method converts a detail request into a detail level.
1553 * The calling code may request full detail (<code>true</code>),
1554 * but a subclass might ignore that and always return
1555 * <code>false</code>. The calling code may pass in
1556 * <code>null</code> indicating that it doesn't care about
1557 * the detail level. In this case the default detail level is
1558 * used.</p>
1559 *
1560 * @param fullDetailRequest the detail level requested
1561 * @return whether full detail is to be shown
1562 */
1563 protected boolean isFullDetail(Boolean fullDetailRequest) {
1564 if (fullDetailRequest == null) {
1565 return defaultFullDetail;
1566 }
1567 return fullDetailRequest.booleanValue();
1568 }
1569
1570 /**
1571 * <p>Gets the short class name for a class.</p>
1572 *
1573 * <p>The short class name is the classname excluding
1574 * the package name.</p>
1575 *
1576 * @param cls the <code>Class</code> to get the short name of
1577 * @return the short name
1578 */
1579 protected String getShortClassName(Class<?> cls) {
1580 return ClassUtils.getShortClassName(cls);
1581 }
1582
1583 // Setters and getters for the customizable parts of the style
1584 // These methods are not expected to be overridden, except to make public
1585 // (They are not public so that immutable subclasses can be written)
1586 //---------------------------------------------------------------------
1587
1588 /**
1589 * <p>Gets whether to use the class name.</p>
1590 *
1591 * @return the current useClassName flag
1592 */
1593 protected boolean isUseClassName() {
1594 return useClassName;
1595 }
1596
1597 /**
1598 * <p>Sets whether to use the class name.</p>
1599 *
1600 * @param useClassName the new useClassName flag
1601 */
1602 protected void setUseClassName(boolean useClassName) {
1603 this.useClassName = useClassName;
1604 }
1605
1606 //---------------------------------------------------------------------
1607
1608 /**
1609 * <p>Gets whether to output short or long class names.</p>
1610 *
1611 * @return the current useShortClassName flag
1612 * @since 2.0
1613 */
1614 protected boolean isUseShortClassName() {
1615 return useShortClassName;
1616 }
1617
1618 /**
1619 * <p>Sets whether to output short or long class names.</p>
1620 *
1621 * @param useShortClassName the new useShortClassName flag
1622 * @since 2.0
1623 */
1624 protected void setUseShortClassName(boolean useShortClassName) {
1625 this.useShortClassName = useShortClassName;
1626 }
1627
1628 //---------------------------------------------------------------------
1629
1630 /**
1631 * <p>Gets whether to use the identity hash code.</p>
1632 *
1633 * @return the current useIdentityHashCode flag
1634 */
1635 protected boolean isUseIdentityHashCode() {
1636 return useIdentityHashCode;
1637 }
1638
1639 /**
1640 * <p>Sets whether to use the identity hash code.</p>
1641 *
1642 * @param useIdentityHashCode the new useIdentityHashCode flag
1643 */
1644 protected void setUseIdentityHashCode(boolean useIdentityHashCode) {
1645 this.useIdentityHashCode = useIdentityHashCode;
1646 }
1647
1648 //---------------------------------------------------------------------
1649
1650 /**
1651 * <p>Gets whether to use the field names passed in.</p>
1652 *
1653 * @return the current useFieldNames flag
1654 */
1655 protected boolean isUseFieldNames() {
1656 return useFieldNames;
1657 }
1658
1659 /**
1660 * <p>Sets whether to use the field names passed in.</p>
1661 *
1662 * @param useFieldNames the new useFieldNames flag
1663 */
1664 protected void setUseFieldNames(boolean useFieldNames) {
1665 this.useFieldNames = useFieldNames;
1666 }
1667
1668 //---------------------------------------------------------------------
1669
1670 /**
1671 * <p>Gets whether to use full detail when the caller doesn't
1672 * specify.</p>
1673 *
1674 * @return the current defaultFullDetail flag
1675 */
1676 protected boolean isDefaultFullDetail() {
1677 return defaultFullDetail;
1678 }
1679
1680 /**
1681 * <p>Sets whether to use full detail when the caller doesn't
1682 * specify.</p>
1683 *
1684 * @param defaultFullDetail the new defaultFullDetail flag
1685 */
1686 protected void setDefaultFullDetail(boolean defaultFullDetail) {
1687 this.defaultFullDetail = defaultFullDetail;
1688 }
1689
1690 //---------------------------------------------------------------------
1691
1692 /**
1693 * <p>Gets whether to output array content detail.</p>
1694 *
1695 * @return the current array content detail setting
1696 */
1697 protected boolean isArrayContentDetail() {
1698 return arrayContentDetail;
1699 }
1700
1701 /**
1702 * <p>Sets whether to output array content detail.</p>
1703 *
1704 * @param arrayContentDetail the new arrayContentDetail flag
1705 */
1706 protected void setArrayContentDetail(boolean arrayContentDetail) {
1707 this.arrayContentDetail = arrayContentDetail;
1708 }
1709
1710 //---------------------------------------------------------------------
1711
1712 /**
1713 * <p>Gets the array start text.</p>
1714 *
1715 * @return the current array start text
1716 */
1717 protected String getArrayStart() {
1718 return arrayStart;
1719 }
1720
1721 /**
1722 * <p>Sets the array start text.</p>
1723 *
1724 * <p><code>null</code> is accepted, but will be converted to
1725 * an empty String.</p>
1726 *
1727 * @param arrayStart the new array start text
1728 */
1729 protected void setArrayStart(String arrayStart) {
1730 if (arrayStart == null) {
1731 arrayStart = "";
1732 }
1733 this.arrayStart = arrayStart;
1734 }
1735
1736 //---------------------------------------------------------------------
1737
1738 /**
1739 * <p>Gets the array end text.</p>
1740 *
1741 * @return the current array end text
1742 */
1743 protected String getArrayEnd() {
1744 return arrayEnd;
1745 }
1746
1747 /**
1748 * <p>Sets the array end text.</p>
1749 *
1750 * <p><code>null</code> is accepted, but will be converted to
1751 * an empty String.</p>
1752 *
1753 * @param arrayEnd the new array end text
1754 */
1755 protected void setArrayEnd(String arrayEnd) {
1756 if (arrayEnd == null) {
1757 arrayEnd = "";
1758 }
1759 this.arrayEnd = arrayEnd;
1760 }
1761
1762 //---------------------------------------------------------------------
1763
1764 /**
1765 * <p>Gets the array separator text.</p>
1766 *
1767 * @return the current array separator text
1768 */
1769 protected String getArraySeparator() {
1770 return arraySeparator;
1771 }
1772
1773 /**
1774 * <p>Sets the array separator text.</p>
1775 *
1776 * <p><code>null</code> is accepted, but will be converted to
1777 * an empty String.</p>
1778 *
1779 * @param arraySeparator the new array separator text
1780 */
1781 protected void setArraySeparator(String arraySeparator) {
1782 if (arraySeparator == null) {
1783 arraySeparator = "";
1784 }
1785 this.arraySeparator = arraySeparator;
1786 }
1787
1788 //---------------------------------------------------------------------
1789
1790 /**
1791 * <p>Gets the content start text.</p>
1792 *
1793 * @return the current content start text
1794 */
1795 protected String getContentStart() {
1796 return contentStart;
1797 }
1798
1799 /**
1800 * <p>Sets the content start text.</p>
1801 *
1802 * <p><code>null</code> is accepted, but will be converted to
1803 * an empty String.</p>
1804 *
1805 * @param contentStart the new content start text
1806 */
1807 protected void setContentStart(String contentStart) {
1808 if (contentStart == null) {
1809 contentStart = "";
1810 }
1811 this.contentStart = contentStart;
1812 }
1813
1814 //---------------------------------------------------------------------
1815
1816 /**
1817 * <p>Gets the content end text.</p>
1818 *
1819 * @return the current content end text
1820 */
1821 protected String getContentEnd() {
1822 return contentEnd;
1823 }
1824
1825 /**
1826 * <p>Sets the content end text.</p>
1827 *
1828 * <p><code>null</code> is accepted, but will be converted to
1829 * an empty String.</p>
1830 *
1831 * @param contentEnd the new content end text
1832 */
1833 protected void setContentEnd(String contentEnd) {
1834 if (contentEnd == null) {
1835 contentEnd = "";
1836 }
1837 this.contentEnd = contentEnd;
1838 }
1839
1840 //---------------------------------------------------------------------
1841
1842 /**
1843 * <p>Gets the field name value separator text.</p>
1844 *
1845 * @return the current field name value separator text
1846 */
1847 protected String getFieldNameValueSeparator() {
1848 return fieldNameValueSeparator;
1849 }
1850
1851 /**
1852 * <p>Sets the field name value separator text.</p>
1853 *
1854 * <p><code>null</code> is accepted, but will be converted to
1855 * an empty String.</p>
1856 *
1857 * @param fieldNameValueSeparator the new field name value separator text
1858 */
1859 protected void setFieldNameValueSeparator(String fieldNameValueSeparator) {
1860 if (fieldNameValueSeparator == null) {
1861 fieldNameValueSeparator = "";
1862 }
1863 this.fieldNameValueSeparator = fieldNameValueSeparator;
1864 }
1865
1866 //---------------------------------------------------------------------
1867
1868 /**
1869 * <p>Gets the field separator text.</p>
1870 *
1871 * @return the current field separator text
1872 */
1873 protected String getFieldSeparator() {
1874 return fieldSeparator;
1875 }
1876
1877 /**
1878 * <p>Sets the field separator text.</p>
1879 *
1880 * <p><code>null</code> is accepted, but will be converted to
1881 * an empty String.</p>
1882 *
1883 * @param fieldSeparator the new field separator text
1884 */
1885 protected void setFieldSeparator(String fieldSeparator) {
1886 if (fieldSeparator == null) {
1887 fieldSeparator = "";
1888 }
1889 this.fieldSeparator = fieldSeparator;
1890 }
1891
1892 //---------------------------------------------------------------------
1893
1894 /**
1895 * <p>Gets whether the field separator should be added at the start
1896 * of each buffer.</p>
1897 *
1898 * @return the fieldSeparatorAtStart flag
1899 * @since 2.0
1900 */
1901 protected boolean isFieldSeparatorAtStart() {
1902 return fieldSeparatorAtStart;
1903 }
1904
1905 /**
1906 * <p>Sets whether the field separator should be added at the start
1907 * of each buffer.</p>
1908 *
1909 * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag
1910 * @since 2.0
1911 */
1912 protected void setFieldSeparatorAtStart(boolean fieldSeparatorAtStart) {
1913 this.fieldSeparatorAtStart = fieldSeparatorAtStart;
1914 }
1915
1916 //---------------------------------------------------------------------
1917
1918 /**
1919 * <p>Gets whether the field separator should be added at the end
1920 * of each buffer.</p>
1921 *
1922 * @return fieldSeparatorAtEnd flag
1923 * @since 2.0
1924 */
1925 protected boolean isFieldSeparatorAtEnd() {
1926 return fieldSeparatorAtEnd;
1927 }
1928
1929 /**
1930 * <p>Sets whether the field separator should be added at the end
1931 * of each buffer.</p>
1932 *
1933 * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag
1934 * @since 2.0
1935 */
1936 protected void setFieldSeparatorAtEnd(boolean fieldSeparatorAtEnd) {
1937 this.fieldSeparatorAtEnd = fieldSeparatorAtEnd;
1938 }
1939
1940 //---------------------------------------------------------------------
1941
1942 /**
1943 * <p>Gets the text to output when <code>null</code> found.</p>
1944 *
1945 * @return the current text to output when null found
1946 */
1947 protected String getNullText() {
1948 return nullText;
1949 }
1950
1951 /**
1952 * <p>Sets the text to output when <code>null</code> found.</p>
1953 *
1954 * <p><code>null</code> is accepted, but will be converted to
1955 * an empty String.</p>
1956 *
1957 * @param nullText the new text to output when null found
1958 */
1959 protected void setNullText(String nullText) {
1960 if (nullText == null) {
1961 nullText = "";
1962 }
1963 this.nullText = nullText;
1964 }
1965
1966 //---------------------------------------------------------------------
1967
1968 /**
1969 * <p>Gets the start text to output when a <code>Collection</code>,
1970 * <code>Map</code> or array size is output.</p>
1971 *
1972 * <p>This is output before the size value.</p>
1973 *
1974 * @return the current start of size text
1975 */
1976 protected String getSizeStartText() {
1977 return sizeStartText;
1978 }
1979
1980 /**
1981 * <p>Sets the start text to output when a <code>Collection</code>,
1982 * <code>Map</code> or array size is output.</p>
1983 *
1984 * <p>This is output before the size value.</p>
1985 *
1986 * <p><code>null</code> is accepted, but will be converted to
1987 * an empty String.</p>
1988 *
1989 * @param sizeStartText the new start of size text
1990 */
1991 protected void setSizeStartText(String sizeStartText) {
1992 if (sizeStartText == null) {
1993 sizeStartText = "";
1994 }
1995 this.sizeStartText = sizeStartText;
1996 }
1997
1998 //---------------------------------------------------------------------
1999
2000 /**
2001 * <p>Gets the end text to output when a <code>Collection</code>,
2002 * <code>Map</code> or array size is output.</p>
2003 *
2004 * <p>This is output after the size value.</p>
2005 *
2006 * @return the current end of size text
2007 */
2008 protected String getSizeEndText() {
2009 return sizeEndText;
2010 }
2011
2012 /**
2013 * <p>Sets the end text to output when a <code>Collection</code>,
2014 * <code>Map</code> or array size is output.</p>
2015 *
2016 * <p>This is output after the size value.</p>
2017 *
2018 * <p><code>null</code> is accepted, but will be converted to
2019 * an empty String.</p>
2020 *
2021 * @param sizeEndText the new end of size text
2022 */
2023 protected void setSizeEndText(String sizeEndText) {
2024 if (sizeEndText == null) {
2025 sizeEndText = "";
2026 }
2027 this.sizeEndText = sizeEndText;
2028 }
2029
2030 //---------------------------------------------------------------------
2031
2032 /**
2033 * <p>Gets the start text to output when an <code>Object</code> is
2034 * output in summary mode.</p>
2035 *
2036 * <p>This is output before the size value.</p>
2037 *
2038 * @return the current start of summary text
2039 */
2040 protected String getSummaryObjectStartText() {
2041 return summaryObjectStartText;
2042 }
2043
2044 /**
2045 * <p>Sets the start text to output when an <code>Object</code> is
2046 * output in summary mode.</p>
2047 *
2048 * <p>This is output before the size value.</p>
2049 *
2050 * <p><code>null</code> is accepted, but will be converted to
2051 * an empty String.</p>
2052 *
2053 * @param summaryObjectStartText the new start of summary text
2054 */
2055 protected void setSummaryObjectStartText(String summaryObjectStartText) {
2056 if (summaryObjectStartText == null) {
2057 summaryObjectStartText = "";
2058 }
2059 this.summaryObjectStartText = summaryObjectStartText;
2060 }
2061
2062 //---------------------------------------------------------------------
2063
2064 /**
2065 * <p>Gets the end text to output when an <code>Object</code> is
2066 * output in summary mode.</p>
2067 *
2068 * <p>This is output after the size value.</p>
2069 *
2070 * @return the current end of summary text
2071 */
2072 protected String getSummaryObjectEndText() {
2073 return summaryObjectEndText;
2074 }
2075
2076 /**
2077 * <p>Sets the end text to output when an <code>Object</code> is
2078 * output in summary mode.</p>
2079 *
2080 * <p>This is output after the size value.</p>
2081 *
2082 * <p><code>null</code> is accepted, but will be converted to
2083 * an empty String.</p>
2084 *
2085 * @param summaryObjectEndText the new end of summary text
2086 */
2087 protected void setSummaryObjectEndText(String summaryObjectEndText) {
2088 if (summaryObjectEndText == null) {
2089 summaryObjectEndText = "";
2090 }
2091 this.summaryObjectEndText = summaryObjectEndText;
2092 }
2093
2094 //----------------------------------------------------------------------------
2095
2096 /**
2097 * <p>Default <code>ToStringStyle</code>.</p>
2098 *
2099 * <p>This is an inner class rather than using
2100 * <code>StandardToStringStyle</code> to ensure its immutability.</p>
2101 */
2102 private static final class DefaultToStringStyle extends ToStringStyle {
2103
2104 /**
2105 * Required for serialization support.
2106 *
2107 * @see java.io.Serializable
2108 */
2109 private static final long serialVersionUID = 1L;
2110
2111 /**
2112 * <p>Constructor.</p>
2113 *
2114 * <p>Use the static constant rather than instantiating.</p>
2115 */
2116 DefaultToStringStyle() {
2117 super();
2118 }
2119
2120 /**
2121 * <p>Ensure <code>Singleton</code> after serialization.</p>
2122 *
2123 * @return the singleton
2124 */
2125 private Object readResolve() {
2126 return ToStringStyle.DEFAULT_STYLE;
2127 }
2128
2129 }
2130
2131 //----------------------------------------------------------------------------
2132
2133 /**
2134 * <p><code>ToStringStyle</code> that does not print out
2135 * the field names.</p>
2136 *
2137 * <p>This is an inner class rather than using
2138 * <code>StandardToStringStyle</code> to ensure its immutability.
2139 */
2140 private static final class NoFieldNameToStringStyle extends ToStringStyle {
2141
2142 private static final long serialVersionUID = 1L;
2143
2144 /**
2145 * <p>Constructor.</p>
2146 *
2147 * <p>Use the static constant rather than instantiating.</p>
2148 */
2149 NoFieldNameToStringStyle() {
2150 super();
2151 this.setUseFieldNames(false);
2152 }
2153
2154 /**
2155 * <p>Ensure <code>Singleton</code> after serialization.</p>
2156 *
2157 * @return the singleton
2158 */
2159 private Object readResolve() {
2160 return ToStringStyle.NO_FIELD_NAMES_STYLE;
2161 }
2162
2163 }
2164
2165 //----------------------------------------------------------------------------
2166
2167 /**
2168 * <p><code>ToStringStyle</code> that prints out the short
2169 * class name and no identity hashcode.</p>
2170 *
2171 * <p>This is an inner class rather than using
2172 * <code>StandardToStringStyle</code> to ensure its immutability.</p>
2173 */
2174 private static final class ShortPrefixToStringStyle extends ToStringStyle {
2175
2176 private static final long serialVersionUID = 1L;
2177
2178 /**
2179 * <p>Constructor.</p>
2180 *
2181 * <p>Use the static constant rather than instantiating.</p>
2182 */
2183 ShortPrefixToStringStyle() {
2184 super();
2185 this.setUseShortClassName(true);
2186 this.setUseIdentityHashCode(false);
2187 }
2188
2189 /**
2190 * <p>Ensure <code>Singleton</ode> after serialization.</p>
2191 * @return the singleton
2192 */
2193 private Object readResolve() {
2194 return ToStringStyle.SHORT_PREFIX_STYLE;
2195 }
2196
2197 }
2198
2199 /**
2200 * <p><code>ToStringStyle</code> that does not print out the
2201 * classname, identity hashcode, content start or field name.</p>
2202 *
2203 * <p>This is an inner class rather than using
2204 * <code>StandardToStringStyle</code> to ensure its immutability.</p>
2205 */
2206 private static final class SimpleToStringStyle extends ToStringStyle {
2207
2208 private static final long serialVersionUID = 1L;
2209
2210 /**
2211 * <p>Constructor.</p>
2212 *
2213 * <p>Use the static constant rather than instantiating.</p>
2214 */
2215 SimpleToStringStyle() {
2216 super();
2217 this.setUseClassName(false);
2218 this.setUseIdentityHashCode(false);
2219 this.setUseFieldNames(false);
2220 this.setContentStart("");
2221 this.setContentEnd("");
2222 }
2223
2224 /**
2225 * <p>Ensure <code>Singleton</ode> after serialization.</p>
2226 * @return the singleton
2227 */
2228 private Object readResolve() {
2229 return ToStringStyle.SIMPLE_STYLE;
2230 }
2231
2232 }
2233
2234 //----------------------------------------------------------------------------
2235
2236 /**
2237 * <p><code>ToStringStyle</code> that outputs on multiple lines.</p>
2238 *
2239 * <p>This is an inner class rather than using
2240 * <code>StandardToStringStyle</code> to ensure its immutability.</p>
2241 */
2242 private static final class MultiLineToStringStyle extends ToStringStyle {
2243
2244 private static final long serialVersionUID = 1L;
2245
2246 /**
2247 * <p>Constructor.</p>
2248 *
2249 * <p>Use the static constant rather than instantiating.</p>
2250 */
2251 MultiLineToStringStyle() {
2252 super();
2253 this.setContentStart("[");
2254 this.setFieldSeparator(SystemUtils.LINE_SEPARATOR + " ");
2255 this.setFieldSeparatorAtStart(true);
2256 this.setContentEnd(SystemUtils.LINE_SEPARATOR + "]");
2257 }
2258
2259 /**
2260 * <p>Ensure <code>Singleton</code> after serialization.</p>
2261 *
2262 * @return the singleton
2263 */
2264 private Object readResolve() {
2265 return ToStringStyle.MULTI_LINE_STYLE;
2266 }
2267
2268 }
2269
2270 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 Assists in creating consistent <code>equals(Object)</code>, <code>toString()</code>,
19 <code>hashCode()</code>, and <code>compareTo(Object)</code> methods.
20 @see java.lang.Object#equals(Object)
21 @see java.lang.Object#toString()
22 @see java.lang.Object#hashCode()
23 @see java.lang.Comparable#compareTo(Object)
24 @since 1.0
25 <p>These classes are not thread-safe.</p>
26 </body>
27 </html>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import java.util.concurrent.atomic.AtomicReference;
19
20 /**
21 * <p>
22 * A specialized implementation of the {@code ConcurrentInitializer} interface
23 * based on an {@link AtomicReference} variable.
24 * </p>
25 * <p>
26 * This class maintains a member field of type {@code AtomicReference}. It
27 * implements the following algorithm to create and initialize an object in its
28 * {@link #get()} method:
29 * <ul>
30 * <li>First it is checked whether the {@code AtomicReference} variable contains
31 * already a value. If this is the case, the value is directly returned.</li>
32 * <li>Otherwise the {@link #initialize()} method is called. This method must be
33 * defined in concrete subclasses to actually create the managed object.</li>
34 * <li>After the object was created by {@link #initialize()} it is checked
35 * whether the {@code AtomicReference} variable is still undefined. This has to
36 * be done because in the meantime another thread may have initialized the
37 * object. If the reference is still empty, the newly created object is stored
38 * in it and returned by this method.</li>
39 * <li>Otherwise the value stored in the {@code AtomicReference} is returned.</li>
40 * </ul>
41 * </p>
42 * <p>
43 * Because atomic variables are used this class does not need any
44 * synchronization. So there is no danger of deadlock, and access to the managed
45 * object is efficient. However, if multiple threads access the {@code
46 * AtomicInitializer} object before it has been initialized almost at the same
47 * time, it can happen that {@link #initialize()} is called multiple times. The
48 * algorithm outlined above guarantees that {@link #get()} always returns the
49 * same object though.
50 * </p>
51 * <p>
52 * Compared with the {@link LazyInitializer} class, this class can be more
53 * efficient because it does not need synchronization. The drawback is that the
54 * {@link #initialize()} method can be called multiple times which may be
55 * problematic if the creation of the managed object is expensive. As a rule of
56 * thumb this initializer implementation is preferable if there are not too many
57 * threads involved and the probability that multiple threads access an
58 * uninitialized object is small. If there is high parallelism,
59 * {@link LazyInitializer} is more appropriate.
60 * </p>
61 *
62 * @since 3.0
63 * @version $Id: AtomicInitializer.java 1088899 2011-04-05 05:31:27Z bayard $
64 * @param <T> the type of the object managed by this initializer class
65 */
66 public abstract class AtomicInitializer<T> implements ConcurrentInitializer<T> {
67 /** Holds the reference to the managed object. */
68 private final AtomicReference<T> reference = new AtomicReference<T>();
69
70 /**
71 * Returns the object managed by this initializer. The object is created if
72 * it is not available yet and stored internally. This method always returns
73 * the same object.
74 *
75 * @return the object created by this {@code AtomicInitializer}
76 * @throws ConcurrentException if an error occurred during initialization of
77 * the object
78 */
79 public T get() throws ConcurrentException {
80 T result = reference.get();
81
82 if (result == null) {
83 result = initialize();
84 if (!reference.compareAndSet(null, result)) {
85 // another thread has initialized the reference
86 result = reference.get();
87 }
88 }
89
90 return result;
91 }
92
93 /**
94 * Creates and initializes the object managed by this {@code
95 * AtomicInitializer}. This method is called by {@link #get()} when the
96 * managed object is not available yet. An implementation can focus on the
97 * creation of the object. No synchronization is needed, as this is already
98 * handled by {@code get()}. As stated by the class comment, it is possible
99 * that this method is called multiple times.
100 *
101 * @return the managed data object
102 * @throws ConcurrentException if an error occurs during object creation
103 */
104 protected abstract T initialize() throws ConcurrentException;
105 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import java.util.concurrent.atomic.AtomicReference;
19
20 /**
21 * <p>
22 * A specialized {@code ConcurrentInitializer} implementation which is similar
23 * to {@link AtomicInitializer}, but ensures that the {@link #initialize()}
24 * method is called only once.
25 * </p>
26 * <p>
27 * As {@link AtomicInitializer} this class is based on atomic variables, so it
28 * can create an object under concurrent access without synchronization.
29 * However, it implements an additional check to guarantee that the
30 * {@link #initialize()} method which actually creates the object cannot be
31 * called multiple times.
32 * </p>
33 * <p>
34 * Because of this additional check this implementation is slightly less
35 * efficient than {@link AtomicInitializer}, but if the object creation in the
36 * {@code initialize()} method is expensive or if multiple invocations of
37 * {@code initialize()} are problematic, it is the better alternative.
38 * </p>
39 * <p>
40 * From its semantics this class has the same properties as
41 * {@link LazyInitializer}. It is a &quot;save&quot; implementation of the lazy
42 * initializer pattern. Comparing both classes in terms of efficiency is
43 * difficult because which one is faster depends on multiple factors. Because
44 * {@code AtomicSafeInitializer} does not use synchronization at all it probably
45 * outruns {@link LazyInitializer}, at least under low or moderate concurrent
46 * access. Developers should run their own benchmarks on the expected target
47 * platform to decide which implementation is suitable for their specific use
48 * case.
49 * </p>
50 *
51 * @since 3.0
52 * @version $Id: AtomicSafeInitializer.java 1088899 2011-04-05 05:31:27Z bayard $
53 * @param <T> the type of the object managed by this initializer class
54 */
55 public abstract class AtomicSafeInitializer<T> implements
56 ConcurrentInitializer<T> {
57 /** A guard which ensures that initialize() is called only once. */
58 private final AtomicReference<AtomicSafeInitializer<T>> factory =
59 new AtomicReference<AtomicSafeInitializer<T>>();
60
61 /** Holds the reference to the managed object. */
62 private final AtomicReference<T> reference = new AtomicReference<T>();
63
64 /**
65 * Get (and initialize, if not initialized yet) the required object
66 *
67 * @return lazily initialized object
68 * @throws ConcurrentException if the initialization of the object causes an
69 * exception
70 */
71 public final T get() throws ConcurrentException {
72 T result;
73
74 while ((result = reference.get()) == null) {
75 if (factory.compareAndSet(null, this)) {
76 reference.set(initialize());
77 }
78 }
79
80 return result;
81 }
82
83 /**
84 * Creates and initializes the object managed by this
85 * {@code AtomicInitializer}. This method is called by {@link #get()} when
86 * the managed object is not available yet. An implementation can focus on
87 * the creation of the object. No synchronization is needed, as this is
88 * already handled by {@code get()}. This method is guaranteed to be called
89 * only once.
90 *
91 * @return the managed data object
92 * @throws ConcurrentException if an error occurs during object creation
93 */
94 protected abstract T initialize() throws ConcurrentException;
95 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.ExecutorService;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.Future;
23
24 /**
25 * <p>
26 * A class that allows complex initialization operations in a background task.
27 * </p>
28 * <p>
29 * Applications often have to do some expensive initialization steps when they
30 * are started, e.g. constructing a connection to a database, reading a
31 * configuration file, etc. Doing these things in parallel can enhance
32 * performance as the CPU load can be improved. However, when access to the
33 * resources initialized in a background thread is actually required,
34 * synchronization has to be performed to ensure that their initialization is
35 * complete.
36 * </p>
37 * <p>
38 * This abstract base class provides support for this use case. A concrete
39 * subclass must implement the {@link #initialize()} method. Here an arbitrary
40 * initialization can be implemented, and a result object can be returned. With
41 * this method in place the basic usage of this class is as follows (where
42 * {@code MyBackgroundInitializer} is a concrete subclass):
43 *
44 * <pre>
45 * MyBackgroundInitializer initializer = new MyBackgroundInitializer();
46 * initializer.start();
47 * // Now do some other things. Initialization runs in a parallel thread
48 * ...
49 * // Wait for the end of initialization and access the result object
50 * Object result = initializer.get();
51 * </pre>
52 *
53 * </p>
54 * <p>
55 * After the construction of a {@code BackgroundInitializer} object its
56 * {@link #start()} method has to be called. This starts the background
57 * processing. The application can now continue to do other things. When it
58 * needs access to the object produced by the {@code BackgroundInitializer} it
59 * calls its {@link #get()} method. If initialization is already complete,
60 * {@link #get()} returns the result object immediately. Otherwise it blocks
61 * until the result object is fully constructed.
62 * </p>
63 * <p>
64 * {@code BackgroundInitializer} is a thin wrapper around a {@code Future}
65 * object and uses an {@code ExecutorService} for running the background
66 * initialization task. It is possible to pass in an {@code ExecutorService} at
67 * construction time or set one using {@code setExternalExecutor()} before
68 * {@code start()} was called. Then this object is used to spawn the background
69 * task. If no {@code ExecutorService} has been provided, {@code
70 * BackgroundInitializer} creates a temporary {@code ExecutorService} and
71 * destroys it when initialization is complete.
72 * </p>
73 * <p>
74 * The methods provided by {@code BackgroundInitializer} provide for minimal
75 * interaction with the wrapped {@code Future} object. It is also possible to
76 * obtain the {@code Future} object directly. Then the enhanced functionality
77 * offered by {@code Future} can be used, e.g. to check whether the background
78 * operation is complete or to cancel the operation.
79 * </p>
80 *
81 * @since 3.0
82 * @version $Id: BackgroundInitializer.java 1082044 2011-03-16 04:26:58Z bayard $
83 * @param <T> the type of the object managed by this initializer class
84 */
85 public abstract class BackgroundInitializer<T> implements
86 ConcurrentInitializer<T> {
87 /** The external executor service for executing tasks. */
88 private ExecutorService externalExecutor;
89
90 /** A reference to the executor service that is actually used. */
91 private ExecutorService executor;
92
93 /** Stores the handle to the background task. */
94 private Future<T> future;
95
96 /**
97 * Creates a new instance of {@code BackgroundInitializer}. No external
98 * {@code ExecutorService} is used.
99 */
100 protected BackgroundInitializer() {
101 this(null);
102 }
103
104 /**
105 * Creates a new instance of {@code BackgroundInitializer} and initializes
106 * it with the given {@code ExecutorService}. If the {@code ExecutorService}
107 * is not null, the background task for initializing this object will be
108 * scheduled at this service. Otherwise a new temporary {@code
109 * ExecutorService} is created.
110 *
111 * @param exec an external {@code ExecutorService} to be used for task
112 * execution
113 */
114 protected BackgroundInitializer(ExecutorService exec) {
115 setExternalExecutor(exec);
116 }
117
118 /**
119 * Returns the external {@code ExecutorService} to be used by this class.
120 *
121 * @return the {@code ExecutorService}
122 */
123 public final synchronized ExecutorService getExternalExecutor() {
124 return externalExecutor;
125 }
126
127 /**
128 * Returns a flag whether this {@code BackgroundInitializer} has already
129 * been started.
130 *
131 * @return a flag whether the {@link #start()} method has already been
132 * called
133 */
134 public synchronized boolean isStarted() {
135 return future != null;
136 }
137
138 /**
139 * Sets an {@code ExecutorService} to be used by this class. The {@code
140 * ExecutorService} passed to this method is used for executing the
141 * background task. Thus it is possible to re-use an already existing
142 * {@code ExecutorService} or to use a specially configured one. If no
143 * {@code ExecutorService} is set, this instance creates a temporary one and
144 * destroys it after background initialization is complete. Note that this
145 * method must be called before {@link #start()}; otherwise an exception is
146 * thrown.
147 *
148 * @param externalExecutor the {@code ExecutorService} to be used
149 * @throws IllegalStateException if this initializer has already been
150 * started
151 */
152 public final synchronized void setExternalExecutor(
153 ExecutorService externalExecutor) {
154 if (isStarted()) {
155 throw new IllegalStateException(
156 "Cannot set ExecutorService after start()!");
157 }
158
159 this.externalExecutor = externalExecutor;
160 }
161
162 /**
163 * Starts the background initialization. With this method the initializer
164 * becomes active and invokes the {@link #initialize()} method in a
165 * background task. A {@code BackgroundInitializer} can be started exactly
166 * once. The return value of this method determines whether the start was
167 * successful: only the first invocation of this method returns <b>true</b>,
168 * following invocations will return <b>false</b>.
169 *
170 * @return a flag whether the initializer could be started successfully
171 */
172 public synchronized boolean start() {
173 // Not yet started?
174 if (!isStarted()) {
175
176 // Determine the executor to use and whether a temporary one has to
177 // be created
178 ExecutorService tempExec;
179 executor = getExternalExecutor();
180 if (executor == null) {
181 executor = tempExec = createExecutor();
182 } else {
183 tempExec = null;
184 }
185
186 future = executor.submit(createTask(tempExec));
187
188 return true;
189 }
190
191 return false;
192 }
193
194 /**
195 * Returns the result of the background initialization. This method blocks
196 * until initialization is complete. If the background processing caused a
197 * runtime exception, it is directly thrown by this method. Checked
198 * exceptions, including {@code InterruptedException} are wrapped in a
199 * {@link ConcurrentException}. Calling this method before {@link #start()}
200 * was called causes an {@code IllegalStateException} exception to be
201 * thrown.
202 *
203 * @return the object produced by this initializer
204 * @throws ConcurrentException if a checked exception occurred during
205 * background processing
206 * @throws IllegalStateException if {@link #start()} has not been called
207 */
208 public T get() throws ConcurrentException {
209 try {
210 return getFuture().get();
211 } catch (ExecutionException execex) {
212 ConcurrentUtils.handleCause(execex);
213 return null; // should not be reached
214 } catch (InterruptedException iex) {
215 // reset interrupted state
216 Thread.currentThread().interrupt();
217 throw new ConcurrentException(iex);
218 }
219 }
220
221 /**
222 * Returns the {@code Future} object that was created when {@link #start()}
223 * was called. Therefore this method can only be called after {@code
224 * start()}.
225 *
226 * @return the {@code Future} object wrapped by this initializer
227 * @throws IllegalStateException if {@link #start()} has not been called
228 */
229 public synchronized Future<T> getFuture() {
230 if (future == null) {
231 throw new IllegalStateException("start() must be called first!");
232 }
233
234 return future;
235 }
236
237 /**
238 * Returns the {@code ExecutorService} that is actually used for executing
239 * the background task. This method can be called after {@link #start()}
240 * (before {@code start()} it returns <b>null</b>). If an external executor
241 * was set, this is also the active executor. Otherwise this method returns
242 * the temporary executor that was created by this object.
243 *
244 * @return the {@code ExecutorService} for executing the background task
245 */
246 protected synchronized final ExecutorService getActiveExecutor() {
247 return executor;
248 }
249
250 /**
251 * Returns the number of background tasks to be created for this
252 * initializer. This information is evaluated when a temporary {@code
253 * ExecutorService} is created. This base implementation returns 1. Derived
254 * classes that do more complex background processing can override it. This
255 * method is called from a synchronized block by the {@link #start()}
256 * method. Therefore overriding methods should be careful with obtaining
257 * other locks and return as fast as possible.
258 *
259 * @return the number of background tasks required by this initializer
260 */
261 protected int getTaskCount() {
262 return 1;
263 }
264
265 /**
266 * Performs the initialization. This method is called in a background task
267 * when this {@code BackgroundInitializer} is started. It must be
268 * implemented by a concrete subclass. An implementation is free to perform
269 * arbitrary initialization. The object returned by this method can be
270 * queried using the {@link #get()} method.
271 *
272 * @return a result object
273 * @throws Exception if an error occurs
274 */
275 protected abstract T initialize() throws Exception;
276
277 /**
278 * Creates a task for the background initialization. The {@code Callable}
279 * object returned by this method is passed to the {@code ExecutorService}.
280 * This implementation returns a task that invokes the {@link #initialize()}
281 * method. If a temporary {@code ExecutorService} is used, it is destroyed
282 * at the end of the task.
283 *
284 * @param execDestroy the {@code ExecutorService} to be destroyed by the
285 * task
286 * @return a task for the background initialization
287 */
288 private Callable<T> createTask(ExecutorService execDestroy) {
289 return new InitializationTask(execDestroy);
290 }
291
292 /**
293 * Creates the {@code ExecutorService} to be used. This method is called if
294 * no {@code ExecutorService} was provided at construction time.
295 *
296 * @return the {@code ExecutorService} to be used
297 */
298 private ExecutorService createExecutor() {
299 return Executors.newFixedThreadPool(getTaskCount());
300 }
301
302 private class InitializationTask implements Callable<T> {
303 /** Stores the executor service to be destroyed at the end. */
304 private final ExecutorService execFinally;
305
306 /**
307 * Creates a new instance of {@code InitializationTask} and initializes
308 * it with the {@code ExecutorService} to be destroyed at the end.
309 *
310 * @param exec the {@code ExecutorService}
311 */
312 public InitializationTask(ExecutorService exec) {
313 execFinally = exec;
314 }
315
316 /**
317 * Initiates initialization and returns the result.
318 *
319 * @return the result object
320 * @throws Exception if an error occurs
321 */
322 public T call() throws Exception {
323 try {
324 return initialize();
325 } finally {
326 if (execFinally != null) {
327 execFinally.shutdown();
328 }
329 }
330 }
331 }
332 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import java.util.concurrent.Executors;
19 import java.util.concurrent.ThreadFactory;
20 import java.util.concurrent.atomic.AtomicLong;
21
22 /**
23 * <p>
24 * An implementation of the {@code ThreadFactory} interface that provides some
25 * configuration options for the threads it creates.
26 * </p>
27 * <p>
28 * A {@code ThreadFactory} is used for instance by an {@code ExecutorService} to
29 * create the threads it uses for executing tasks. In many cases users do not
30 * have to care about a {@code ThreadFactory} because the default one used by an
31 * {@code ExecutorService} will do. However, if there are special requirements
32 * for the threads, a custom {@code ThreadFactory} has to be created.
33 * </p>
34 * <p>
35 * This class provides some frequently needed configuration options for the
36 * threads it creates. These are the following:
37 * <ul>
38 * <li>A name pattern for the threads created by this factory can be specified.
39 * This is often useful if an application uses multiple executor services for
40 * different purposes. If the names of the threads used by these services have
41 * meaningful names, log output or exception traces can be much easier to read.
42 * Naming patterns are <em>format strings</em> as used by the {@code
43 * String.format()} method. The string can contain the place holder {@code %d}
44 * which will be replaced by the number of the current thread ({@code
45 * ThreadFactoryImpl} keeps a counter of the threads it has already created).
46 * For instance, the naming pattern {@code "My %d. worker thread"} will result
47 * in thread names like {@code "My 1. worker thread"}, {@code
48 * "My 2. worker thread"} and so on.</li>
49 * <li>A flag whether the threads created by this factory should be daemon
50 * threads. This can impact the exit behavior of the current Java application
51 * because the JVM shuts down if there are only daemon threads running.</li>
52 * <li>The priority of the thread. Here an integer value can be provided. The
53 * {@code java.lang.Thread} class defines constants for valid ranges of priority
54 * values.</li>
55 * <li>The {@code UncaughtExceptionHandler} for the thread. This handler is
56 * called if an uncaught exception occurs within the thread.</li>
57 * </ul>
58 * </p>
59 * <p>
60 * {@code BasicThreadFactory} wraps another thread factory which actually
61 * creates new threads. The configuration options are set on the threads created
62 * by the wrapped thread factory. On construction time the factory to be wrapped
63 * can be specified. If none is provided, a default {@code ThreadFactory} is
64 * used.
65 * </p>
66 * <p>
67 * Instances of {@code BasicThreadFactory} are not created directly, but the
68 * nested {@code Builder} class is used for this purpose. Using the builder only
69 * the configuration options an application is interested in need to be set. The
70 * following example shows how a {@code BasicThreadFactory} is created and
71 * installed in an {@code ExecutorService}:
72 *
73 * <pre>
74 * // Create a factory that produces daemon threads with a naming pattern and
75 * // a priority
76 * BasicThreadFactory factory = new BasicThreadFactory.Builder()
77 * .namingPattern(&quot;workerthread-%d&quot;)
78 * .daemon(true)
79 * .priority(Thread.MAX_PRIORITY)
80 * .build();
81 * // Create an executor service for single-threaded execution
82 * ExecutorService exec = Executors.newSingleThreadExecutor(factory);
83 * </pre>
84 * </p>
85 *
86 * @since 3.0
87 * @version $Id: BasicThreadFactory.java 1079423 2011-03-08 16:38:09Z sebb $
88 */
89 public class BasicThreadFactory implements ThreadFactory {
90 /** A counter for the threads created by this factory. */
91 private final AtomicLong threadCounter;
92
93 /** Stores the wrapped factory. */
94 private final ThreadFactory wrappedFactory;
95
96 /** Stores the uncaught exception handler. */
97 private final Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
98
99 /** Stores the naming pattern for newly created threads. */
100 private final String namingPattern;
101
102 /** Stores the priority. */
103 private final Integer priority;
104
105 /** Stores the daemon status flag. */
106 private final Boolean daemonFlag;
107
108 /**
109 * Creates a new instance of {@code ThreadFactoryImpl} and configures it
110 * from the specified {@code Builder} object.
111 *
112 * @param builder the {@code Builder} object
113 */
114 private BasicThreadFactory(Builder builder) {
115 if (builder.wrappedFactory == null) {
116 wrappedFactory = Executors.defaultThreadFactory();
117 } else {
118 wrappedFactory = builder.wrappedFactory;
119 }
120
121 namingPattern = builder.namingPattern;
122 priority = builder.priority;
123 daemonFlag = builder.daemonFlag;
124 uncaughtExceptionHandler = builder.exceptionHandler;
125
126 threadCounter = new AtomicLong();
127 }
128
129 /**
130 * Returns the wrapped {@code ThreadFactory}. This factory is used for
131 * actually creating threads. This method never returns <b>null</b>. If no
132 * {@code ThreadFactory} was passed when this object was created, a default
133 * thread factory is returned.
134 *
135 * @return the wrapped {@code ThreadFactory}
136 */
137 public final ThreadFactory getWrappedFactory() {
138 return wrappedFactory;
139 }
140
141 /**
142 * Returns the naming pattern for naming newly created threads. Result can
143 * be <b>null</b> if no naming pattern was provided.
144 *
145 * @return the naming pattern
146 */
147 public final String getNamingPattern() {
148 return namingPattern;
149 }
150
151 /**
152 * Returns the daemon flag. This flag determines whether newly created
153 * threads should be daemon threads. If <b>true</b>, this factory object
154 * calls {@code setDaemon(true)} on the newly created threads. Result can be
155 * <b>null</b> if no daemon flag was provided at creation time.
156 *
157 * @return the daemon flag
158 */
159 public final Boolean getDaemonFlag() {
160 return daemonFlag;
161 }
162
163 /**
164 * Returns the priority of the threads created by this factory. Result can
165 * be <b>null</b> if no priority was specified.
166 *
167 * @return the priority for newly created threads
168 */
169 public final Integer getPriority() {
170 return priority;
171 }
172
173 /**
174 * Returns the {@code UncaughtExceptionHandler} for the threads created by
175 * this factory. Result can be <b>null</b> if no handler was provided.
176 *
177 * @return the {@code UncaughtExceptionHandler}
178 */
179 public final Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
180 return uncaughtExceptionHandler;
181 }
182
183 /**
184 * Returns the number of threads this factory has already created. This
185 * class maintains an internal counter that is incremented each time the
186 * {@link #newThread(Runnable)} method is invoked.
187 *
188 * @return the number of threads created by this factory
189 */
190 public long getThreadCount() {
191 return threadCounter.get();
192 }
193
194 /**
195 * Creates a new thread. This implementation delegates to the wrapped
196 * factory for creating the thread. Then, on the newly created thread the
197 * corresponding configuration options are set.
198 *
199 * @param r the {@code Runnable} to be executed by the new thread
200 * @return the newly created thread
201 */
202 public Thread newThread(Runnable r) {
203 Thread t = getWrappedFactory().newThread(r);
204 initializeThread(t);
205
206 return t;
207 }
208
209 /**
210 * Initializes the specified thread. This method is called by
211 * {@link #newThread(Runnable)} after a new thread has been obtained from
212 * the wrapped thread factory. It initializes the thread according to the
213 * options set for this factory.
214 *
215 * @param t the thread to be initialized
216 */
217 private void initializeThread(Thread t) {
218
219 if (getNamingPattern() != null) {
220 Long count = Long.valueOf(threadCounter.incrementAndGet());
221 t.setName(String.format(getNamingPattern(), count));
222 }
223
224 if (getUncaughtExceptionHandler() != null) {
225 t.setUncaughtExceptionHandler(getUncaughtExceptionHandler());
226 }
227
228 if (getPriority() != null) {
229 t.setPriority(getPriority().intValue());
230 }
231
232 if (getDaemonFlag() != null) {
233 t.setDaemon(getDaemonFlag().booleanValue());
234 }
235 }
236
237 /**
238 * <p>
239 * A <em>builder</em> class for creating instances of {@code
240 * BasicThreadFactory}.
241 * </p>
242 * <p>
243 * Using this builder class instances of {@code BasicThreadFactory} can be
244 * created and initialized. The class provides methods that correspond to
245 * the configuration options supported by {@code BasicThreadFactory}. Method
246 * chaining is supported. Refer to the documentation of {@code
247 * BasicThreadFactory} for a usage example.
248 * </p>
249 *
250 * @version $Id: BasicThreadFactory.java 1079423 2011-03-08 16:38:09Z sebb $
251 */
252 public static class Builder
253 implements org.apache.commons.lang3.builder.Builder<BasicThreadFactory> {
254
255 /** The wrapped factory. */
256 private ThreadFactory wrappedFactory;
257
258 /** The uncaught exception handler. */
259 private Thread.UncaughtExceptionHandler exceptionHandler;
260
261 /** The naming pattern. */
262 private String namingPattern;
263
264 /** The priority. */
265 private Integer priority;
266
267 /** The daemon flag. */
268 private Boolean daemonFlag;
269
270 /**
271 * Sets the {@code ThreadFactory} to be wrapped by the new {@code
272 * BasicThreadFactory}.
273 *
274 * @param factory the wrapped {@code ThreadFactory} (must not be
275 * <b>null</b>)
276 * @return a reference to this {@code Builder}
277 * @throws NullPointerException if the passed in {@code ThreadFactory}
278 * is <b>null</b>
279 */
280 public Builder wrappedFactory(ThreadFactory factory) {
281 if (factory == null) {
282 throw new NullPointerException(
283 "Wrapped ThreadFactory must not be null!");
284 }
285
286 wrappedFactory = factory;
287 return this;
288 }
289
290 /**
291 * Sets the naming pattern to be used by the new {@code
292 * BasicThreadFactory}.
293 *
294 * @param pattern the naming pattern (must not be <b>null</b>)
295 * @return a reference to this {@code Builder}
296 * @throws NullPointerException if the naming pattern is <b>null</b>
297 */
298 public Builder namingPattern(String pattern) {
299 if (pattern == null) {
300 throw new NullPointerException(
301 "Naming pattern must not be null!");
302 }
303
304 namingPattern = pattern;
305 return this;
306 }
307
308 /**
309 * Sets the daemon flag for the new {@code BasicThreadFactory}. If this
310 * flag is set to <b>true</b> the new thread factory will create daemon
311 * threads.
312 *
313 * @param f the value of the daemon flag
314 * @return a reference to this {@code Builder}
315 */
316 public Builder daemon(boolean f) {
317 daemonFlag = Boolean.valueOf(f);
318 return this;
319 }
320
321 /**
322 * Sets the priority for the threads created by the new {@code
323 * BasicThreadFactory}.
324 *
325 * @param prio the priority
326 * @return a reference to this {@code Builder}
327 */
328 public Builder priority(int prio) {
329 priority = Integer.valueOf(prio);
330 return this;
331 }
332
333 /**
334 * Sets the uncaught exception handler for the threads created by the
335 * new {@code BasicThreadFactory}.
336 *
337 * @param handler the {@code UncaughtExceptionHandler} (must not be
338 * <b>null</b>)
339 * @return a reference to this {@code Builder}
340 * @throws NullPointerException if the exception handler is <b>null</b>
341 */
342 public Builder uncaughtExceptionHandler(
343 Thread.UncaughtExceptionHandler handler) {
344 if (handler == null) {
345 throw new NullPointerException(
346 "Uncaught exception handler must not be null!");
347 }
348
349 exceptionHandler = handler;
350 return this;
351 }
352
353 /**
354 * Resets this builder. All configuration options are set to default
355 * values. Note: If the {@link #build()} method was called, it is not
356 * necessary to call {@code reset()} explicitly because this is done
357 * automatically.
358 */
359 public void reset() {
360 wrappedFactory = null;
361 exceptionHandler = null;
362 namingPattern = null;
363 priority = null;
364 daemonFlag = null;
365 }
366
367 /**
368 * Creates a new {@code BasicThreadFactory} with all configuration
369 * options that have been specified by calling methods on this builder.
370 * After creating the factory {@link #reset()} is called.
371 *
372 * @return the new {@code BasicThreadFactory}
373 */
374 public BasicThreadFactory build() {
375 BasicThreadFactory factory = new BasicThreadFactory(this);
376 reset();
377 return factory;
378 }
379 }
380 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ExecutorService;
20
21 /**
22 * <p>
23 * A specialized {@link BackgroundInitializer} implementation that wraps a
24 * {@code Callable} object.
25 * </p>
26 * <p>
27 * An instance of this class is initialized with a {@code Callable} object when
28 * it is constructed. The implementation of the {@link #initialize()} method
29 * defined in the super class delegates to this {@code Callable} so that the
30 * {@code Callable} is executed in the background thread.
31 * </p>
32 * <p>
33 * The {@code java.util.concurrent.Callable} interface is a standard mechanism
34 * of the JDK to define tasks to be executed by another thread. The {@code
35 * CallableBackgroundInitializer} class allows combining this standard interface
36 * with the background initializer API.
37 * </p>
38 * <p>
39 * Usage of this class is very similar to the default usage pattern of the
40 * {@link BackgroundInitializer} class: Just create an instance and provide the
41 * {@code Callable} object to be executed, then call the initializer's
42 * {@link #start()} method. This causes the {@code Callable} to be executed in
43 * another thread. When the results of the {@code Callable} are needed the
44 * initializer's {@link #get()} method can be called (which may block until
45 * background execution is complete). The following code fragment shows a
46 * typical usage example:
47 *
48 * <pre>
49 * // a Callable that performs a complex computation
50 * Callable&lt;Integer&gt; computationCallable = new MyComputationCallable();
51 * // setup the background initializer
52 * CallableBackgroundInitializer&lt;Integer&gt; initializer =
53 * new CallableBackgroundInitializer(computationCallable);
54 * initializer.start();
55 * // Now do some other things. Initialization runs in a parallel thread
56 * ...
57 * // Wait for the end of initialization and access the result
58 * Integer result = initializer.get();
59 * </pre>
60 *
61 * </p>
62 *
63 * @since 3.0
64 * @version $Id: CallableBackgroundInitializer.java 1082044 2011-03-16 04:26:58Z bayard $
65 * @param <T> the type of the object managed by this initializer class
66 */
67 public class CallableBackgroundInitializer<T> extends BackgroundInitializer<T> {
68 /** The Callable to be executed. */
69 private final Callable<T> callable;
70
71 /**
72 * Creates a new instance of {@code CallableBackgroundInitializer} and sets
73 * the {@code Callable} to be executed in a background thread.
74 *
75 * @param call the {@code Callable} (must not be <b>null</b>)
76 * @throws IllegalArgumentException if the {@code Callable} is <b>null</b>
77 */
78 public CallableBackgroundInitializer(Callable<T> call) {
79 checkCallable(call);
80 callable = call;
81 }
82
83 /**
84 * Creates a new instance of {@code CallableBackgroundInitializer} and
85 * initializes it with the {@code Callable} to be executed in a background
86 * thread and the {@code ExecutorService} for managing the background
87 * execution.
88 *
89 * @param call the {@code Callable} (must not be <b>null</b>)
90 * @param exec an external {@code ExecutorService} to be used for task
91 * execution
92 * @throws IllegalArgumentException if the {@code Callable} is <b>null</b>
93 */
94 public CallableBackgroundInitializer(Callable<T> call, ExecutorService exec) {
95 super(exec);
96 checkCallable(call);
97 callable = call;
98 }
99
100 /**
101 * Performs initialization in a background thread. This implementation
102 * delegates to the {@code Callable} passed at construction time of this
103 * object.
104 *
105 * @return the result of the initialization
106 * @throws Exception if an error occurs
107 */
108 @Override
109 protected T initialize() throws Exception {
110 return callable.call();
111 }
112
113 /**
114 * Tests the passed in {@code Callable} and throws an exception if it is
115 * undefined.
116 *
117 * @param call the object to check
118 * @throws IllegalArgumentException if the {@code Callable} is <b>null</b>
119 */
120 private void checkCallable(Callable<T> call) {
121 if (call == null) {
122 throw new IllegalArgumentException("Callable must not be null!");
123 }
124 }
125 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 /**
19 * <p>
20 * An exception class used for reporting error conditions related to accessing
21 * data of background tasks.
22 * </p>
23 * <p>
24 * The purpose of this exception class is analogous to the default JDK exception
25 * class {@link java.util.concurrent.ExecutionException}, i.e. it wraps an
26 * exception that occurred during the execution of a task. However, in contrast
27 * to {@code ExecutionException}, it wraps only checked exceptions. Runtime
28 * exceptions are thrown directly.
29 * </p>
30 *
31 * @since 3.0
32 * @version $Id: ConcurrentException.java 1088899 2011-04-05 05:31:27Z bayard $
33 */
34 public class ConcurrentException extends Exception {
35 /**
36 * The serial version UID.
37 */
38 private static final long serialVersionUID = 6622707671812226130L;
39
40 /**
41 * Creates a new, uninitialized instance of {@code ConcurrentException}.
42 */
43 protected ConcurrentException() {
44 super();
45 }
46
47 /**
48 * Creates a new instance of {@code ConcurrentException} and initializes it
49 * with the given cause.
50 *
51 * @param cause the cause of this exception
52 * @throws IllegalArgumentException if the cause is not a checked exception
53 */
54 public ConcurrentException(Throwable cause) {
55 super(ConcurrentUtils.checkedException(cause));
56 }
57
58 /**
59 * Creates a new instance of {@code ConcurrentException} and initializes it
60 * with the given message and cause.
61 *
62 * @param msg the error message
63 * @param cause the cause of this exception
64 * @throws IllegalArgumentException if the cause is not a checked exception
65 */
66 public ConcurrentException(String msg, Throwable cause) {
67 super(msg, ConcurrentUtils.checkedException(cause));
68 }
69 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 /**
19 * <p>
20 * Definition of an interface for the thread-safe initialization of objects.
21 * </p>
22 * <p>
23 * The idea behind this interface is to provide access to an object in a
24 * thread-safe manner. A {@code ConcurrentInitializer} can be passed to multiple
25 * threads which can all access the object produced by the initializer. Through
26 * the {@link #get()} method the object can be queried.
27 * </p>
28 * <p>
29 * Concrete implementations of this interface will use different strategies for
30 * the creation of the managed object, e.g. lazy initialization or
31 * initialization in a background thread. This is completely transparent to
32 * client code, so it is possible to change the initialization strategy without
33 * affecting clients.
34 * </p>
35 *
36 * @since 3.0
37 * @version $Id: ConcurrentInitializer.java 1088899 2011-04-05 05:31:27Z bayard $
38 * @param <T> the type of the object managed by this initializer class
39 */
40 public interface ConcurrentInitializer<T> {
41 /**
42 * Returns the fully initialized object produced by this {@code
43 * ConcurrentInitializer}. A concrete implementation here returns the
44 * results of the initialization process. This method may block until
45 * results are available. Typically, once created the result object is
46 * always the same.
47 *
48 * @return the object created by this {@code ConcurrentException}
49 * @throws ConcurrentException if an error occurred during initialization of
50 * the object
51 */
52 T get() throws ConcurrentException;
53 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 /**
19 * <p>
20 * An exception class used for reporting runtime error conditions related to
21 * accessing data of background tasks.
22 * </p>
23 * <p>
24 * This class is an analogon of the {@link ConcurrentException} exception class.
25 * However, it is a runtime exception and thus does not need explicit catch
26 * clauses. Some methods of {@link ConcurrentUtils} throw {@code
27 * ConcurrentRuntimeException} exceptions rather than
28 * {@link ConcurrentException} exceptions. They can be used by client code that
29 * does not want to be bothered with checked exceptions.
30 * </p>
31 *
32 * @since 3.0
33 * @version $Id: ConcurrentRuntimeException.java 1088899 2011-04-05 05:31:27Z bayard $
34 */
35 public class ConcurrentRuntimeException extends RuntimeException {
36 /**
37 * The serial version UID.
38 */
39 private static final long serialVersionUID = -6582182735562919670L;
40
41 /**
42 * Creates a new, uninitialized instance of {@code
43 * ConcurrentRuntimeException}.
44 */
45 protected ConcurrentRuntimeException() {
46 super();
47 }
48
49 /**
50 * Creates a new instance of {@code ConcurrentRuntimeException} and
51 * initializes it with the given cause.
52 *
53 * @param cause the cause of this exception
54 * @throws IllegalArgumentException if the cause is not a checked exception
55 */
56 public ConcurrentRuntimeException(Throwable cause) {
57 super(ConcurrentUtils.checkedException(cause));
58 }
59
60 /**
61 * Creates a new instance of {@code ConcurrentRuntimeException} and
62 * initializes it with the given message and cause.
63 *
64 * @param msg the error message
65 * @param cause the cause of this exception
66 * @throws IllegalArgumentException if the cause is not a checked exception
67 */
68 public ConcurrentRuntimeException(String msg, Throwable cause) {
69 super(msg, ConcurrentUtils.checkedException(cause));
70 }
71 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import java.util.concurrent.ConcurrentMap;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Future;
21 import java.util.concurrent.TimeUnit;
22
23 /**
24 * <p>
25 * An utility class providing functionality related to the {@code
26 * java.util.concurrent} package.
27 * </p>
28 *
29 * @since 3.0
30 * @version $Id: ConcurrentUtils.java 1088899 2011-04-05 05:31:27Z bayard $
31 */
32 public class ConcurrentUtils {
33
34 /**
35 * Private constructor so that no instances can be created. This class
36 * contains only static utility methods.
37 */
38 private ConcurrentUtils() {
39 }
40
41 /**
42 * Inspects the cause of the specified {@code ExecutionException} and
43 * creates a {@code ConcurrentException} with the checked cause if
44 * necessary. This method performs the following checks on the cause of the
45 * passed in exception:
46 * <ul>
47 * <li>If the passed in exception is <b>null</b> or the cause is
48 * <b>null</b>, this method returns <b>null</b>.</li>
49 * <li>If the cause is a runtime exception, it is directly thrown.</li>
50 * <li>If the cause is an error, it is directly thrown, too.</li>
51 * <li>In any other case the cause is a checked exception. The method then
52 * creates a {@link ConcurrentException}, initializes it with the cause, and
53 * returns it.</li>
54 * </ul>
55 *
56 * @param ex the exception to be processed
57 * @return a {@code ConcurrentException} with the checked cause
58 */
59 public static ConcurrentException extractCause(ExecutionException ex) {
60 if (ex == null || ex.getCause() == null) {
61 return null;
62 }
63
64 throwCause(ex);
65 return new ConcurrentException(ex.getMessage(), ex.getCause());
66 }
67
68 /**
69 * Inspects the cause of the specified {@code ExecutionException} and
70 * creates a {@code ConcurrentRuntimeException} with the checked cause if
71 * necessary. This method works exactly like
72 * {@link #extractCause(ExecutionException)}. The only difference is that
73 * the cause of the specified {@code ExecutionException} is extracted as a
74 * runtime exception. This is an alternative for client code that does not
75 * want to deal with checked exceptions.
76 *
77 * @param ex the exception to be processed
78 * @return a {@code ConcurrentRuntimeException} with the checked cause
79 */
80 public static ConcurrentRuntimeException extractCauseUnchecked(
81 ExecutionException ex) {
82 if (ex == null || ex.getCause() == null) {
83 return null;
84 }
85
86 throwCause(ex);
87 return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause());
88 }
89
90 /**
91 * Handles the specified {@code ExecutionException}. This method calls
92 * {@link #extractCause(ExecutionException)} for obtaining the cause of the
93 * exception - which might already cause an unchecked exception or an error
94 * being thrown. If the cause is a checked exception however, it is wrapped
95 * in a {@code ConcurrentException}, which is thrown. If the passed in
96 * exception is <b>null</b> or has no cause, the method simply returns
97 * without throwing an exception.
98 *
99 * @param ex the exception to be handled
100 * @throws ConcurrentException if the cause of the {@code
101 * ExecutionException} is a checked exception
102 */
103 public static void handleCause(ExecutionException ex)
104 throws ConcurrentException {
105 ConcurrentException cex = extractCause(ex);
106
107 if (cex != null) {
108 throw cex;
109 }
110 }
111
112 /**
113 * Handles the specified {@code ExecutionException} and transforms it into a
114 * runtime exception. This method works exactly like
115 * {@link #handleCause(ExecutionException)}, but instead of a
116 * {@link ConcurrentException} it throws a
117 * {@link ConcurrentRuntimeException}. This is an alternative for client
118 * code that does not want to deal with checked exceptions.
119 *
120 * @param ex the exception to be handled
121 * @throws ConcurrentRuntimeException if the cause of the {@code
122 * ExecutionException} is a checked exception; this exception is then
123 * wrapped in the thrown runtime exception
124 */
125 public static void handleCauseUnchecked(ExecutionException ex) {
126 ConcurrentRuntimeException crex = extractCauseUnchecked(ex);
127
128 if (crex != null) {
129 throw crex;
130 }
131 }
132
133 /**
134 * Tests whether the specified {@code Throwable} is a checked exception. If
135 * not, an exception is thrown.
136 *
137 * @param ex the {@code Throwable} to check
138 * @return a flag whether the passed in exception is a checked exception
139 * @throws IllegalArgumentException if the {@code Throwable} is not a
140 * checked exception
141 */
142 static Throwable checkedException(Throwable ex) {
143 if (ex != null && !(ex instanceof RuntimeException)
144 && !(ex instanceof Error)) {
145 return ex;
146 } else {
147 throw new IllegalArgumentException("Not a checked exception: " + ex);
148 }
149 }
150
151 /**
152 * Tests whether the cause of the specified {@code ExecutionException}
153 * should be thrown and does it if necessary.
154 *
155 * @param ex the exception in question
156 */
157 private static void throwCause(ExecutionException ex) {
158 if (ex.getCause() instanceof RuntimeException) {
159 throw (RuntimeException) ex.getCause();
160 }
161
162 if (ex.getCause() instanceof Error) {
163 throw (Error) ex.getCause();
164 }
165 }
166
167 //-----------------------------------------------------------------------
168 /**
169 * Invokes the specified {@code ConcurrentInitializer} and returns the
170 * object produced by the initializer. This method just invokes the {@code
171 * get()} method of the given {@code ConcurrentInitializer}. It is
172 * <b>null</b>-safe: if the argument is <b>null</b>, result is also
173 * <b>null</b>.
174 *
175 * @param <T> the type of the object produced by the initializer
176 * @param initializer the {@code ConcurrentInitializer} to be invoked
177 * @return the object managed by the {@code ConcurrentInitializer}
178 * @throws ConcurrentException if the {@code ConcurrentInitializer} throws
179 * an exception
180 */
181 public static <T> T initialize(ConcurrentInitializer<T> initializer)
182 throws ConcurrentException {
183 return (initializer != null) ? initializer.get() : null;
184 }
185
186 /**
187 * Invokes the specified {@code ConcurrentInitializer} and transforms
188 * occurring exceptions to runtime exceptions. This method works like
189 * {@link #initialize(ConcurrentInitializer)}, but if the {@code
190 * ConcurrentInitializer} throws a {@link ConcurrentException}, it is
191 * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}.
192 * So client code does not have to deal with checked exceptions.
193 *
194 * @param <T> the type of the object produced by the initializer
195 * @param initializer the {@code ConcurrentInitializer} to be invoked
196 * @return the object managed by the {@code ConcurrentInitializer}
197 * @throws ConcurrentRuntimeException if the initializer throws an exception
198 */
199 public static <T> T initializeUnchecked(ConcurrentInitializer<T> initializer) {
200 try {
201 return initialize(initializer);
202 } catch (ConcurrentException cex) {
203 throw new ConcurrentRuntimeException(cex.getCause());
204 }
205 }
206
207 //-----------------------------------------------------------------------
208 /**
209 * <p>
210 * Puts a value in the specified {@code ConcurrentMap} if the key is not yet
211 * present. This method works similar to the {@code putIfAbsent()} method of
212 * the {@code ConcurrentMap} interface, but the value returned is different.
213 * Basically, this method is equivalent to the following code fragment:
214 *
215 * <pre>
216 * if (!map.containsKey(key)) {
217 * map.put(key, value);
218 * return value;
219 * } else {
220 * return map.get(key);
221 * }
222 * </pre>
223 *
224 * except that the action is performed atomically. So this method always
225 * returns the value which is stored in the map.
226 * </p>
227 * <p>
228 * This method is <b>null</b>-safe: It accepts a <b>null</b> map as input
229 * without throwing an exception. In this case the return value is
230 * <b>null</b>, too.
231 * </p>
232 *
233 * @param <K> the type of the keys of the map
234 * @param <V> the type of the values of the map
235 * @param map the map to be modified
236 * @param key the key of the value to be added
237 * @param value the value to be added
238 * @return the value stored in the map after this operation
239 */
240 public static <K, V> V putIfAbsent(ConcurrentMap<K, V> map, K key, V value) {
241 if (map == null) {
242 return null;
243 }
244
245 V result = map.putIfAbsent(key, value);
246 return (result != null) ? result : value;
247 }
248
249 /**
250 * Checks if a concurrent map contains a key and creates a corresponding
251 * value if not. This method first checks the presence of the key in the
252 * given map. If it is already contained, its value is returned. Otherwise
253 * the {@code get()} method of the passed in {@link ConcurrentInitializer}
254 * is called. With the resulting object
255 * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This
256 * handles the case that in the meantime another thread has added the key to
257 * the map. Both the map and the initializer can be <b>null</b>; in this
258 * case this method simply returns <b>null</b>.
259 *
260 * @param <K> the type of the keys of the map
261 * @param <V> the type of the values of the map
262 * @param map the map to be modified
263 * @param key the key of the value to be added
264 * @param init the {@link ConcurrentInitializer} for creating the value
265 * @return the value stored in the map after this operation; this may or may
266 * not be the object created by the {@link ConcurrentInitializer}
267 * @throws ConcurrentException if the initializer throws an exception
268 */
269 public static <K, V> V createIfAbsent(ConcurrentMap<K, V> map, K key,
270 ConcurrentInitializer<V> init) throws ConcurrentException {
271 if (map == null || init == null) {
272 return null;
273 }
274
275 V value = map.get(key);
276 if (value == null) {
277 return putIfAbsent(map, key, init.get());
278 }
279 return value;
280 }
281
282 /**
283 * Checks if a concurrent map contains a key and creates a corresponding
284 * value if not, suppressing checked exceptions. This method calls
285 * {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it
286 * is caught and re-thrown as a {@link ConcurrentRuntimeException}.
287 *
288 * @param <K> the type of the keys of the map
289 * @param <V> the type of the values of the map
290 * @param map the map to be modified
291 * @param key the key of the value to be added
292 * @param init the {@link ConcurrentInitializer} for creating the value
293 * @return the value stored in the map after this operation; this may or may
294 * not be the object created by the {@link ConcurrentInitializer}
295 * @throws ConcurrentRuntimeException if the initializer throws an exception
296 */
297 public static <K, V> V createIfAbsentUnchecked(ConcurrentMap<K, V> map,
298 K key, ConcurrentInitializer<V> init) {
299 try {
300 return createIfAbsent(map, key, init);
301 } catch (ConcurrentException cex) {
302 throw new ConcurrentRuntimeException(cex.getCause());
303 }
304 }
305
306 //-----------------------------------------------------------------------
307 /**
308 * <p>
309 * Gets an implementation of <code>Future</code> that is immediately done
310 * and returns the specified constant value.
311 * </p>
312 * <p>
313 * This can be useful to return a simple constant immediately from the
314 * concurrent processing, perhaps as part of avoiding nulls.
315 * A constant future can also be useful in testing.
316 * </p>
317 *
318 * @param <T> the type of the value used by this {@code Future} object
319 * @param value the constant value to return, may be null
320 * @return an instance of Future that will return the value, never null
321 */
322 public static <T> Future<T> constantFuture(T value) {
323 return new ConstantFuture<T>(value);
324 }
325
326 /**
327 * A specialized {@code Future} implementation which wraps a constant value.
328 * @param <T> the type of the value wrapped by this class
329 */
330 static final class ConstantFuture<T> implements Future<T> {
331 /** The constant value. */
332 private final T value;
333
334 /**
335 * Creates a new instance of {@code ConstantFuture} and initializes it
336 * with the constant value.
337 *
338 * @param value the value (may be <b>null</b>)
339 */
340 ConstantFuture(T value) {
341 this.value = value;
342 }
343
344 /**
345 * {@inheritDoc} This implementation always returns <b>true</b> because
346 * the constant object managed by this {@code Future} implementation is
347 * always available.
348 */
349 public boolean isDone() {
350 return true;
351 }
352
353 /**
354 * {@inheritDoc} This implementation just returns the constant value.
355 */
356 public T get() {
357 return value;
358 }
359
360 /**
361 * {@inheritDoc} This implementation just returns the constant value; it
362 * does not block, therefore the timeout has no meaning.
363 */
364 public T get(long timeout, TimeUnit unit) {
365 return value;
366 }
367
368 /**
369 * {@inheritDoc} This implementation always returns <b>false</b>; there
370 * is no background process which could be cancelled.
371 */
372 public boolean isCancelled() {
373 return false;
374 }
375
376 /**
377 * {@inheritDoc} The cancel operation is not supported. This
378 * implementation always returns <b>false</b>.
379 */
380 public boolean cancel(boolean mayInterruptIfRunning) {
381 return false;
382 }
383 }
384
385 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import org.apache.commons.lang3.ObjectUtils;
19
20 /**
21 * <p>
22 * A very simple implementation of the {@link ConcurrentInitializer} interface
23 * which always returns the same object.
24 * </p>
25 * <p>
26 * An instance of this class is passed a reference to an object when it is
27 * constructed. The {@link #get()} method just returns this object. No
28 * synchronization is required.
29 * </p>
30 * <p>
31 * This class is useful for instance for unit testing or in cases where a
32 * specific object has to be passed to an object which expects a
33 * {@link ConcurrentInitializer}.
34 * </p>
35 *
36 * @since 3.0
37 * @version $Id: ConstantInitializer.java 1088899 2011-04-05 05:31:27Z bayard $
38 * @param <T> the type of the object managed by this initializer
39 */
40 public class ConstantInitializer<T> implements ConcurrentInitializer<T> {
41 /** Constant for the format of the string representation. */
42 private static final String FMT_TO_STRING = "ConstantInitializer@%d [ object = %s ]";
43
44 /** Stores the managed object. */
45 private final T object;
46
47 /**
48 * Creates a new instance of {@code ConstantInitializer} and initializes it
49 * with the object to be managed. The {@code get()} method will always
50 * return the object passed here. This class does not place any restrictions
51 * on the object. It may be <b>null</b>, then {@code get()} will return
52 * <b>null</b>, too.
53 *
54 * @param obj the object to be managed by this initializer
55 */
56 public ConstantInitializer(T obj) {
57 object = obj;
58 }
59
60 /**
61 * Directly returns the object that was passed to the constructor. This is
62 * the same object as returned by {@code get()}. However, this method does
63 * not declare that it throws an exception.
64 *
65 * @return the object managed by this initializer
66 */
67 public final T getObject() {
68 return object;
69 }
70
71 /**
72 * Returns the object managed by this initializer. This implementation just
73 * returns the object passed to the constructor.
74 *
75 * @return the object managed by this initializer
76 * @throws ConcurrentException if an error occurs
77 */
78 public T get() throws ConcurrentException {
79 return getObject();
80 }
81
82 /**
83 * Returns a hash code for this object. This implementation returns the hash
84 * code of the managed object.
85 *
86 * @return a hash code for this object
87 */
88 @Override
89 public int hashCode() {
90 return (getObject() != null) ? getObject().hashCode() : 0;
91 }
92
93 /**
94 * Compares this object with another one. This implementation returns
95 * <b>true</b> if and only if the passed in object is an instance of
96 * {@code ConstantInitializer} which refers to an object equals to the
97 * object managed by this instance.
98 *
99 * @param obj the object to compare to
100 * @return a flag whether the objects are equal
101 */
102 @Override
103 public boolean equals(Object obj) {
104 if (this == obj) {
105 return true;
106 }
107 if (!(obj instanceof ConstantInitializer<?>)) {
108 return false;
109 }
110
111 ConstantInitializer<?> c = (ConstantInitializer<?>) obj;
112 return ObjectUtils.equals(getObject(), c.getObject());
113 }
114
115 /**
116 * Returns a string representation for this object. This string also
117 * contains a string representation of the object managed by this
118 * initializer.
119 *
120 * @return a string for this object
121 */
122 @Override
123 public String toString() {
124 return String.format(FMT_TO_STRING, Integer.valueOf(System.identityHashCode(this)),
125 String.valueOf(getObject()));
126 }
127 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 /**
19 * <p>
20 * This class provides a generic implementation of the lazy initialization
21 * pattern.
22 * </p>
23 * <p>
24 * Sometimes an application has to deal with an object only under certain
25 * circumstances, e.g. when the user selects a specific menu item or if a
26 * special event is received. If the creation of the object is costly or the
27 * consumption of memory or other system resources is significant, it may make
28 * sense to defer the creation of this object until it is really needed. This is
29 * a use case for the lazy initialization pattern.
30 * </p>
31 * <p>
32 * This abstract base class provides an implementation of the double-check idiom
33 * for an instance field as discussed in Joshua Bloch's "Effective Java", 2nd
34 * edition, item 71. The class already implements all necessary synchronization.
35 * A concrete subclass has to implement the {@code initialize()} method, which
36 * actually creates the wrapped data object.
37 * </p>
38 * <p>
39 * As an usage example consider that we have a class {@code ComplexObject} whose
40 * instantiation is a complex operation. In order to apply lazy initialization
41 * to this class, a subclass of {@code LazyInitializer} has to be created:
42 *
43 * <pre>
44 * public class ComplexObjectInitializer extends LazyInitializer&lt;ComplexObject&gt; {
45 * &#064;Override
46 * protected ComplexObject initialize() {
47 * return new ComplexObject();
48 * }
49 * }
50 * </pre>
51 *
52 * Access to the data object is provided through the {@code get()} method. So,
53 * code that wants to obtain the {@code ComplexObject} instance would simply
54 * look like this:
55 *
56 * <pre>
57 * // Create an instance of the lazy initializer
58 * ComplexObjectInitializer initializer = new ComplexObjectInitializer();
59 * ...
60 * // When the object is actually needed:
61 * ComplexObject cobj = initializer.get();
62 * </pre>
63 *
64 * </p>
65 * <p>
66 * If multiple threads call the {@code get()} method when the object has not yet
67 * been created, they are blocked until initialization completes. The algorithm
68 * guarantees that only a single instance of the wrapped object class is
69 * created, which is passed to all callers. Once initialized, calls to the
70 * {@code get()} method are pretty fast because no synchronization is needed
71 * (only an access to a <b>volatile</b> member field).
72 * </p>
73 *
74 * @since 3.0
75 * @version $Id: LazyInitializer.java 1088899 2011-04-05 05:31:27Z bayard $
76 * @param <T> the type of the object managed by this initializer class
77 */
78 public abstract class LazyInitializer<T> implements ConcurrentInitializer<T> {
79 /** Stores the managed object. */
80 private volatile T object;
81
82 /**
83 * Returns the object wrapped by this instance. On first access the object
84 * is created. After that it is cached and can be accessed pretty fast.
85 *
86 * @return the object initialized by this {@code LazyInitializer}
87 * @throws ConcurrentException if an error occurred during initialization of
88 * the object
89 */
90 public T get() throws ConcurrentException {
91 // use a temporary variable to reduce the number of reads of the
92 // volatile field
93 T result = object;
94
95 if (result == null) {
96 synchronized (this) {
97 result = object;
98 if (result == null) {
99 object = result = initialize();
100 }
101 }
102 }
103
104 return result;
105 }
106
107 /**
108 * Creates and initializes the object managed by this {@code
109 * LazyInitializer}. This method is called by {@link #get()} when the object
110 * is accessed for the first time. An implementation can focus on the
111 * creation of the object. No synchronization is needed, as this is already
112 * handled by {@code get()}.
113 *
114 * @return the managed data object
115 * @throws ConcurrentException if an error occurs during object creation
116 */
117 protected abstract T initialize() throws ConcurrentException;
118 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.NoSuchElementException;
22 import java.util.Set;
23 import java.util.concurrent.ExecutorService;
24
25 /**
26 * <p>
27 * A specialized {@link BackgroundInitializer} implementation that can deal with
28 * multiple background initialization tasks.
29 * </p>
30 * <p>
31 * This class has a similar purpose as {@link BackgroundInitializer}. However,
32 * it is not limited to a single background initialization task. Rather it
33 * manages an arbitrary number of {@code BackgroundInitializer} objects,
34 * executes them, and waits until they are completely initialized. This is
35 * useful for applications that have to perform multiple initialization tasks
36 * that can run in parallel (i.e. that do not depend on each other). This class
37 * takes care about the management of an {@code ExecutorService} and shares it
38 * with the {@code BackgroundInitializer} objects it is responsible for; so the
39 * using application need not bother with these details.
40 * </p>
41 * <p>
42 * The typical usage scenario for {@code MultiBackgroundInitializer} is as
43 * follows:
44 * <ul>
45 * <li>Create a new instance of the class. Optionally pass in a pre-configured
46 * {@code ExecutorService}. Alternatively {@code MultiBackgroundInitializer} can
47 * create a temporary {@code ExecutorService} and delete it after initialization
48 * is complete.</li>
49 * <li>Create specialized {@link BackgroundInitializer} objects for the
50 * initialization tasks to be performed and add them to the {@code
51 * MultiBackgroundInitializer} using the
52 * {@link #addInitializer(String, BackgroundInitializer)} method.</li>
53 * <li>After all initializers have been added, call the {@link #start()} method.
54 * </li>
55 * <li>When access to the result objects produced by the {@code
56 * BackgroundInitializer} objects is needed call the {@link #get()} method. The
57 * object returned here provides access to all result objects created during
58 * initialization. It also stores information about exceptions that have
59 * occurred.</li>
60 * </ul>
61 * </p>
62 * <p>
63 * {@code MultiBackgroundInitializer} starts a special controller task that
64 * starts all {@code BackgroundInitializer} objects added to the instance.
65 * Before the an initializer is started it is checked whether this initializer
66 * already has an {@code ExecutorService} set. If this is the case, this {@code
67 * ExecutorService} is used for running the background task. Otherwise the
68 * current {@code ExecutorService} of this {@code MultiBackgroundInitializer} is
69 * shared with the initializer.
70 * </p>
71 * <p>
72 * The easiest way of using this class is to let it deal with the management of
73 * an {@code ExecutorService} itself: If no external {@code ExecutorService} is
74 * provided, the class creates a temporary {@code ExecutorService} (that is
75 * capable of executing all background tasks in parallel) and destroys it at the
76 * end of background processing.
77 * </p>
78 * <p>
79 * Alternatively an external {@code ExecutorService} can be provided - either at
80 * construction time or later by calling the
81 * {@link #setExternalExecutor(ExecutorService)} method. In this case all
82 * background tasks are scheduled at this external {@code ExecutorService}.
83 * <strong>Important note:</strong> When using an external {@code
84 * ExecutorService} be sure that the number of threads managed by the service is
85 * large enough. Otherwise a deadlock can happen! This is the case in the
86 * following scenario: {@code MultiBackgroundInitializer} starts a task that
87 * starts all registered {@code BackgroundInitializer} objects and waits for
88 * their completion. If for instance a single threaded {@code ExecutorService}
89 * is used, none of the background tasks can be executed, and the task created
90 * by {@code MultiBackgroundInitializer} waits forever.
91 * </p>
92 *
93 * @since 3.0
94 * @version $Id: MultiBackgroundInitializer.java 1082301 2011-03-16 21:02:15Z oheger $
95 */
96 public class MultiBackgroundInitializer
97 extends
98 BackgroundInitializer<MultiBackgroundInitializer.MultiBackgroundInitializerResults> {
99 /** A map with the child initializers. */
100 private final Map<String, BackgroundInitializer<?>> childInitializers =
101 new HashMap<String, BackgroundInitializer<?>>();
102
103 /**
104 * Creates a new instance of {@code MultiBackgroundInitializer}.
105 */
106 public MultiBackgroundInitializer() {
107 super();
108 }
109
110 /**
111 * Creates a new instance of {@code MultiBackgroundInitializer} and
112 * initializes it with the given external {@code ExecutorService}.
113 *
114 * @param exec the {@code ExecutorService} for executing the background
115 * tasks
116 */
117 public MultiBackgroundInitializer(ExecutorService exec) {
118 super(exec);
119 }
120
121 /**
122 * Adds a new {@code BackgroundInitializer} to this object. When this
123 * {@code MultiBackgroundInitializer} is started, the given initializer will
124 * be processed. This method must not be called after {@link #start()} has
125 * been invoked.
126 *
127 * @param name the name of the initializer (must not be <b>null</b>)
128 * @param init the {@code BackgroundInitializer} to add (must not be
129 * <b>null</b>)
130 * @throws IllegalArgumentException if a required parameter is missing
131 * @throws IllegalStateException if {@code start()} has already been called
132 */
133 public void addInitializer(String name, BackgroundInitializer<?> init) {
134 if (name == null) {
135 throw new IllegalArgumentException(
136 "Name of child initializer must not be null!");
137 }
138 if (init == null) {
139 throw new IllegalArgumentException(
140 "Child initializer must not be null!");
141 }
142
143 synchronized (this) {
144 if (isStarted()) {
145 throw new IllegalStateException(
146 "addInitializer() must not be called after start()!");
147 }
148 childInitializers.put(name, init);
149 }
150 }
151
152 /**
153 * Returns the number of tasks needed for executing all child {@code
154 * BackgroundInitializer} objects in parallel. This implementation sums up
155 * the required tasks for all child initializers (which is necessary if one
156 * of the child initializers is itself a {@code MultiBackgroundInitializer}
157 * ). Then it adds 1 for the control task that waits for the completion of
158 * the children.
159 *
160 * @return the number of tasks required for background processing
161 */
162 @Override
163 protected int getTaskCount() {
164 int result = 1;
165
166 for (BackgroundInitializer<?> bi : childInitializers.values()) {
167 result += bi.getTaskCount();
168 }
169
170 return result;
171 }
172
173 /**
174 * Creates the results object. This implementation starts all child {@code
175 * BackgroundInitializer} objects. Then it collects their results and
176 * creates a {@code MultiBackgroundInitializerResults} object with this
177 * data. If a child initializer throws a checked exceptions, it is added to
178 * the results object. Unchecked exceptions are propagated.
179 *
180 * @return the results object
181 * @throws Exception if an error occurs
182 */
183 @Override
184 protected MultiBackgroundInitializerResults initialize() throws Exception {
185 Map<String, BackgroundInitializer<?>> inits;
186 synchronized (this) {
187 // create a snapshot to operate on
188 inits = new HashMap<String, BackgroundInitializer<?>>(
189 childInitializers);
190 }
191
192 // start the child initializers
193 ExecutorService exec = getActiveExecutor();
194 for (BackgroundInitializer<?> bi : inits.values()) {
195 if (bi.getExternalExecutor() == null) {
196 // share the executor service if necessary
197 bi.setExternalExecutor(exec);
198 }
199 bi.start();
200 }
201
202 // collect the results
203 Map<String, Object> results = new HashMap<String, Object>();
204 Map<String, ConcurrentException> excepts = new HashMap<String, ConcurrentException>();
205 for (Map.Entry<String, BackgroundInitializer<?>> e : inits.entrySet()) {
206 try {
207 results.put(e.getKey(), e.getValue().get());
208 } catch (ConcurrentException cex) {
209 excepts.put(e.getKey(), cex);
210 }
211 }
212
213 return new MultiBackgroundInitializerResults(inits, results, excepts);
214 }
215
216 /**
217 * A data class for storing the results of the background initialization
218 * performed by {@code MultiBackgroundInitializer}. Objects of this inner
219 * class are returned by {@link MultiBackgroundInitializer#initialize()}.
220 * They allow access to all result objects produced by the
221 * {@link BackgroundInitializer} objects managed by the owning instance. It
222 * is also possible to retrieve status information about single
223 * {@link BackgroundInitializer}s, i.e. whether they completed normally or
224 * caused an exception.
225 */
226 public static class MultiBackgroundInitializerResults {
227 /** A map with the child initializers. */
228 private final Map<String, BackgroundInitializer<?>> initializers;
229
230 /** A map with the result objects. */
231 private final Map<String, Object> resultObjects;
232
233 /** A map with the exceptions. */
234 private final Map<String, ConcurrentException> exceptions;
235
236 /**
237 * Creates a new instance of {@code MultiBackgroundInitializerResults}
238 * and initializes it with maps for the {@code BackgroundInitializer}
239 * objects, their result objects and the exceptions thrown by them.
240 *
241 * @param inits the {@code BackgroundInitializer} objects
242 * @param results the result objects
243 * @param excepts the exceptions
244 */
245 private MultiBackgroundInitializerResults(
246 Map<String, BackgroundInitializer<?>> inits,
247 Map<String, Object> results,
248 Map<String, ConcurrentException> excepts) {
249 initializers = inits;
250 resultObjects = results;
251 exceptions = excepts;
252 }
253
254 /**
255 * Returns the {@code BackgroundInitializer} with the given name. If the
256 * name cannot be resolved, an exception is thrown.
257 *
258 * @param name the name of the {@code BackgroundInitializer}
259 * @return the {@code BackgroundInitializer} with this name
260 * @throws NoSuchElementException if the name cannot be resolved
261 */
262 public BackgroundInitializer<?> getInitializer(String name) {
263 return checkName(name);
264 }
265
266 /**
267 * Returns the result object produced by the {@code
268 * BackgroundInitializer} with the given name. This is the object
269 * returned by the initializer's {@code initialize()} method. If this
270 * {@code BackgroundInitializer} caused an exception, <b>null</b> is
271 * returned. If the name cannot be resolved, an exception is thrown.
272 *
273 * @param name the name of the {@code BackgroundInitializer}
274 * @return the result object produced by this {@code
275 * BackgroundInitializer}
276 * @throws NoSuchElementException if the name cannot be resolved
277 */
278 public Object getResultObject(String name) {
279 checkName(name);
280 return resultObjects.get(name);
281 }
282
283 /**
284 * Returns a flag whether the {@code BackgroundInitializer} with the
285 * given name caused an exception.
286 *
287 * @param name the name of the {@code BackgroundInitializer}
288 * @return a flag whether this initializer caused an exception
289 * @throws NoSuchElementException if the name cannot be resolved
290 */
291 public boolean isException(String name) {
292 checkName(name);
293 return exceptions.containsKey(name);
294 }
295
296 /**
297 * Returns the {@code ConcurrentException} object that was thrown by the
298 * {@code BackgroundInitializer} with the given name. If this
299 * initializer did not throw an exception, the return value is
300 * <b>null</b>. If the name cannot be resolved, an exception is thrown.
301 *
302 * @param name the name of the {@code BackgroundInitializer}
303 * @return the exception thrown by this initializer
304 * @throws NoSuchElementException if the name cannot be resolved
305 */
306 public ConcurrentException getException(String name) {
307 checkName(name);
308 return exceptions.get(name);
309 }
310
311 /**
312 * Returns a set with the names of all {@code BackgroundInitializer}
313 * objects managed by the {@code MultiBackgroundInitializer}.
314 *
315 * @return an (unmodifiable) set with the names of the managed {@code
316 * BackgroundInitializer} objects
317 */
318 public Set<String> initializerNames() {
319 return Collections.unmodifiableSet(initializers.keySet());
320 }
321
322 /**
323 * Returns a flag whether the whole initialization was successful. This
324 * is the case if no child initializer has thrown an exception.
325 *
326 * @return a flag whether the initialization was successful
327 */
328 public boolean isSuccessful() {
329 return exceptions.isEmpty();
330 }
331
332 /**
333 * Checks whether an initializer with the given name exists. If not,
334 * throws an exception. If it exists, the associated child initializer
335 * is returned.
336 *
337 * @param name the name to check
338 * @return the initializer with this name
339 * @throws NoSuchElementException if the name is unknown
340 */
341 private BackgroundInitializer<?> checkName(String name) {
342 BackgroundInitializer<?> init = initializers.get(name);
343 if (init == null) {
344 throw new NoSuchElementException(
345 "No child initializer with name " + name);
346 }
347
348 return init;
349 }
350 }
351 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import java.util.concurrent.ScheduledExecutorService;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.ScheduledThreadPoolExecutor;
21 import java.util.concurrent.TimeUnit;
22
23 /**
24 * <p>
25 * A specialized <em>semaphore</em> implementation that provides a number of
26 * permits in a given time frame.
27 * </p>
28 * <p>
29 * This class is similar to the {@code java.util.concurrent.Semaphore} class
30 * provided by the JDK in that it manages a configurable number of permits.
31 * Using the {@link #acquire()} method a permit can be requested by a thread.
32 * However, there is an additional timing dimension: there is no {@code
33 * release()} method for freeing a permit, but all permits are automatically
34 * released at the end of a configurable time frame. If a thread calls
35 * {@link #acquire()} and the available permits are already exhausted for this
36 * time frame, the thread is blocked. When the time frame ends all permits
37 * requested so far are restored, and blocking threads are waked up again, so
38 * that they can try to acquire a new permit. This basically means that in the
39 * specified time frame only the given number of operations is possible.
40 * </p>
41 * <p>
42 * A use case for this class is to artificially limit the load produced by a
43 * process. As an example consider an application that issues database queries
44 * on a production system in a background process to gather statistical
45 * information. This background processing should not produce so much database
46 * load that the functionality and the performance of the production system are
47 * impacted. Here a {@code TimedSemaphore} could be installed to guarantee that
48 * only a given number of database queries are issued per second.
49 * </p>
50 * <p>
51 * A thread class for performing database queries could look as follows:
52 *
53 * <pre>
54 * public class StatisticsThread extends Thread {
55 * // The semaphore for limiting database load.
56 * private final TimedSemaphore semaphore;
57 * // Create an instance and set the semaphore
58 * public StatisticsThread(TimedSemaphore timedSemaphore) {
59 * semaphore = timedSemaphore;
60 * }
61 * // Gather statistics
62 * public void run() {
63 * try {
64 * while(true) {
65 * semaphore.acquire(); // limit database load
66 * performQuery(); // issue a query
67 * }
68 * } catch(InterruptedException) {
69 * // fall through
70 * }
71 * }
72 * ...
73 * }
74 * </pre>
75 *
76 * The following code fragment shows how a {@code TimedSemaphore} is created
77 * that allows only 10 operations per second and passed to the statistics
78 * thread:
79 *
80 * <pre>
81 * TimedSemaphore sem = new TimedSemaphore(1, TimeUnit.SECOND, 10);
82 * StatisticsThread thread = new StatisticsThread(sem);
83 * thread.start();
84 * </pre>
85 *
86 * </p>
87 * <p>
88 * When creating an instance the time period for the semaphore must be
89 * specified. {@code TimedSemaphore} uses an executor service with a
90 * corresponding period to monitor this interval. The {@code
91 * ScheduledExecutorService} to be used for this purpose can be provided at
92 * construction time. Alternatively the class creates an internal executor
93 * service.
94 * </p>
95 * <p>
96 * Client code that uses {@code TimedSemaphore} has to call the
97 * {@link #acquire()} method in aach processing step. {@code TimedSemaphore}
98 * keeps track of the number of invocations of the {@link #acquire()} method and
99 * blocks the calling thread if the counter exceeds the limit specified. When
100 * the timer signals the end of the time period the counter is reset and all
101 * waiting threads are released. Then another cycle can start.
102 * </p>
103 * <p>
104 * It is possible to modify the limit at any time using the
105 * {@link #setLimit(int)} method. This is useful if the load produced by an
106 * operation has to be adapted dynamically. In the example scenario with the
107 * thread collecting statistics it may make sense to specify a low limit during
108 * day time while allowing a higher load in the night time. Reducing the limit
109 * takes effect immediately by blocking incoming callers. If the limit is
110 * increased, waiting threads are not released immediately, but wake up when the
111 * timer runs out. Then, in the next period more processing steps can be
112 * performed without blocking. By setting the limit to 0 the semaphore can be
113 * switched off: in this mode the {@link #acquire()} method never blocks, but
114 * lets all callers pass directly.
115 * </p>
116 * <p>
117 * When the {@code TimedSemaphore} is no more needed its {@link #shutdown()}
118 * method should be called. This causes the periodic task that monitors the time
119 * interval to be canceled. If the {@code ScheduledExecutorService} has been
120 * created by the semaphore at construction time, it is also shut down.
121 * resources. After that {@link #acquire()} must not be called any more.
122 * </p>
123 *
124 * @since 3.0
125 * @version $Id: TimedSemaphore.java 1082044 2011-03-16 04:26:58Z bayard $
126 */
127 public class TimedSemaphore {
128 /**
129 * Constant for a value representing no limit. If the limit is set to a
130 * value less or equal this constant, the {@code TimedSemaphore} will be
131 * effectively switched off.
132 */
133 public static final int NO_LIMIT = 0;
134
135 /** Constant for the thread pool size for the executor. */
136 private static final int THREAD_POOL_SIZE = 1;
137
138 /** The executor service for managing the timer thread. */
139 private final ScheduledExecutorService executorService;
140
141 /** Stores the period for this timed semaphore. */
142 private final long period;
143
144 /** The time unit for the period. */
145 private final TimeUnit unit;
146
147 /** A flag whether the executor service was created by this object. */
148 private final boolean ownExecutor;
149
150 /** A future object representing the timer task. */
151 private ScheduledFuture<?> task;
152
153 /** Stores the total number of invocations of the acquire() method. */
154 private long totalAcquireCount;
155
156 /**
157 * The counter for the periods. This counter is increased every time a
158 * period ends.
159 */
160 private long periodCount;
161
162 /** The limit. */
163 private int limit;
164
165 /** The current counter. */
166 private int acquireCount;
167
168 /** The number of invocations of acquire() in the last period. */
169 private int lastCallsPerPeriod;
170
171 /** A flag whether shutdown() was called. */
172 private boolean shutdown;
173
174 /**
175 * Creates a new instance of {@link TimedSemaphore} and initializes it with
176 * the given time period and the limit.
177 *
178 * @param timePeriod the time period
179 * @param timeUnit the unit for the period
180 * @param limit the limit for the semaphore
181 * @throws IllegalArgumentException if the period is less or equals 0
182 */
183 public TimedSemaphore(long timePeriod, TimeUnit timeUnit, int limit) {
184 this(null, timePeriod, timeUnit, limit);
185 }
186
187 /**
188 * Creates a new instance of {@link TimedSemaphore} and initializes it with
189 * an executor service, the given time period, and the limit. The executor
190 * service will be used for creating a periodic task for monitoring the time
191 * period. It can be <b>null</b>, then a default service will be created.
192 *
193 * @param service the executor service
194 * @param timePeriod the time period
195 * @param timeUnit the unit for the period
196 * @param limit the limit for the semaphore
197 * @throws IllegalArgumentException if the period is less or equals 0
198 */
199 public TimedSemaphore(ScheduledExecutorService service, long timePeriod,
200 TimeUnit timeUnit, int limit) {
201 if (timePeriod <= 0) {
202 throw new IllegalArgumentException("Time period must be greater 0!");
203 }
204
205 period = timePeriod;
206 unit = timeUnit;
207
208 if (service != null) {
209 executorService = service;
210 ownExecutor = false;
211 } else {
212 ScheduledThreadPoolExecutor s = new ScheduledThreadPoolExecutor(
213 THREAD_POOL_SIZE);
214 s.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
215 s.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
216 executorService = s;
217 ownExecutor = true;
218 }
219
220 setLimit(limit);
221 }
222
223 /**
224 * Returns the limit enforced by this semaphore. The limit determines how
225 * many invocations of {@link #acquire()} are allowed within the monitored
226 * period.
227 *
228 * @return the limit
229 */
230 public final synchronized int getLimit() {
231 return limit;
232 }
233
234 /**
235 * Sets the limit. This is the number of times the {@link #acquire()} method
236 * can be called within the time period specified. If this limit is reached,
237 * further invocations of {@link #acquire()} will block. Setting the limit
238 * to a value &lt;= {@link #NO_LIMIT} will cause the limit to be disabled,
239 * i.e. an arbitrary number of{@link #acquire()} invocations is allowed in
240 * the time period.
241 *
242 * @param limit the limit
243 */
244 public final synchronized void setLimit(int limit) {
245 this.limit = limit;
246 }
247
248 /**
249 * Initializes a shutdown. After that the object cannot be used any more.
250 * This method can be invoked an arbitrary number of times. All invocations
251 * after the first one do not have any effect.
252 */
253 public synchronized void shutdown() {
254 if (!shutdown) {
255
256 if (ownExecutor) {
257 // if the executor was created by this instance, it has
258 // to be shutdown
259 getExecutorService().shutdownNow();
260 }
261 if (task != null) {
262 task.cancel(false);
263 }
264
265 shutdown = true;
266 }
267 }
268
269 /**
270 * Tests whether the {@link #shutdown()} method has been called on this
271 * object. If this method returns <b>true</b>, this instance cannot be used
272 * any longer.
273 *
274 * @return a flag whether a shutdown has been performed
275 */
276 public synchronized boolean isShutdown() {
277 return shutdown;
278 }
279
280 /**
281 * Tries to acquire a permit from this semaphore. This method will block if
282 * the limit for the current period has already been reached. If
283 * {@link #shutdown()} has already been invoked, calling this method will
284 * cause an exception. The very first call of this method starts the timer
285 * task which monitors the time period set for this {@code TimedSemaphore}.
286 * From now on the semaphore is active.
287 *
288 * @throws InterruptedException if the thread gets interrupted
289 * @throws IllegalStateException if this semaphore is already shut down
290 */
291 public synchronized void acquire() throws InterruptedException {
292 if (isShutdown()) {
293 throw new IllegalStateException("TimedSemaphore is shut down!");
294 }
295
296 if (task == null) {
297 task = startTimer();
298 }
299
300 boolean canPass = false;
301 do {
302 canPass = getLimit() <= NO_LIMIT || acquireCount < getLimit();
303 if (!canPass) {
304 wait();
305 } else {
306 acquireCount++;
307 }
308 } while (!canPass);
309 }
310
311 /**
312 * Returns the number of (successful) acquire invocations during the last
313 * period. This is the number of times the {@link #acquire()} method was
314 * called without blocking. This can be useful for testing or debugging
315 * purposes or to determine a meaningful threshold value. If a limit is set,
316 * the value returned by this method won't be greater than this limit.
317 *
318 * @return the number of non-blocking invocations of the {@link #acquire()}
319 * method
320 */
321 public synchronized int getLastAcquiresPerPeriod() {
322 return lastCallsPerPeriod;
323 }
324
325 /**
326 * Returns the number of invocations of the {@link #acquire()} method for
327 * the current period. This may be useful for testing or debugging purposes.
328 *
329 * @return the current number of {@link #acquire()} invocations
330 */
331 public synchronized int getAcquireCount() {
332 return acquireCount;
333 }
334
335 /**
336 * Returns the number of calls to the {@link #acquire()} method that can
337 * still be performed in the current period without blocking. This method
338 * can give an indication whether it is safe to call the {@link #acquire()}
339 * method without risking to be suspended. However, there is no guarantee
340 * that a subsequent call to {@link #acquire()} actually is not-blocking
341 * because in the mean time other threads may have invoked the semaphore.
342 *
343 * @return the current number of available {@link #acquire()} calls in the
344 * current period
345 */
346 public synchronized int getAvailablePermits() {
347 return getLimit() - getAcquireCount();
348 }
349
350 /**
351 * Returns the average number of successful (i.e. non-blocking)
352 * {@link #acquire()} invocations for the entire life-time of this {@code
353 * TimedSemaphore}. This method can be used for instance for statistical
354 * calculations.
355 *
356 * @return the average number of {@link #acquire()} invocations per time
357 * unit
358 */
359 public synchronized double getAverageCallsPerPeriod() {
360 return (periodCount == 0) ? 0 : (double) totalAcquireCount
361 / (double) periodCount;
362 }
363
364 /**
365 * Returns the time period. This is the time monitored by this semaphore.
366 * Only a given number of invocations of the {@link #acquire()} method is
367 * possible in this period.
368 *
369 * @return the time period
370 */
371 public long getPeriod() {
372 return period;
373 }
374
375 /**
376 * Returns the time unit. This is the unit used by {@link #getPeriod()}.
377 *
378 * @return the time unit
379 */
380 public TimeUnit getUnit() {
381 return unit;
382 }
383
384 /**
385 * Returns the executor service used by this instance.
386 *
387 * @return the executor service
388 */
389 protected ScheduledExecutorService getExecutorService() {
390 return executorService;
391 }
392
393 /**
394 * Starts the timer. This method is called when {@link #acquire()} is called
395 * for the first time. It schedules a task to be executed at fixed rate to
396 * monitor the time period specified.
397 *
398 * @return a future object representing the task scheduled
399 */
400 protected ScheduledFuture<?> startTimer() {
401 return getExecutorService().scheduleAtFixedRate(new Runnable() {
402 public void run() {
403 endOfPeriod();
404 }
405 }, getPeriod(), getPeriod(), getUnit());
406 }
407
408 /**
409 * The current time period is finished. This method is called by the timer
410 * used internally to monitor the time period. It resets the counter and
411 * releases the threads waiting for this barrier.
412 */
413 synchronized void endOfPeriod() {
414 lastCallsPerPeriod = acquireCount;
415 totalAcquireCount += acquireCount;
416 periodCount++;
417 acquireCount = 0;
418 notifyAll();
419 }
420 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 Provides support classes for multi-threaded programming. This package is
19 intended to be an extension to <code>java.util.concurrent</code>.
20 <p>These classes are thread-safe.</p>
21 </body>
22 </html>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.event;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.io.ObjectOutputStream;
23 import java.io.Serializable;
24 import java.lang.reflect.Array;
25 import java.lang.reflect.InvocationHandler;
26 import java.lang.reflect.Method;
27 import java.lang.reflect.Proxy;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.concurrent.CopyOnWriteArrayList;
31
32 import org.apache.commons.lang3.Validate;
33
34 /**
35 * An EventListenerSupport object can be used to manage a list of event
36 * listeners of a particular type. The class provides
37 * {@link #addListener(Object)} and {@link #removeListener(Object)} methods
38 * for registering listeners, as well as a {@link #fire()} method for firing
39 * events to the listeners.
40 *
41 * <p/>
42 * To use this class, suppose you want to support ActionEvents. You would do:
43 * <code><pre>
44 * public class MyActionEventSource
45 * {
46 * private EventListenerSupport<ActionListener> actionListeners =
47 * EventListenerSupport.create(ActionListener.class);
48 *
49 * public void someMethodThatFiresAction()
50 * {
51 * ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "somethingCool");
52 * actionListeners.fire().actionPerformed(e);
53 * }
54 * }
55 * </pre></code>
56 *
57 * Serializing an {@link EventListenerSupport} instance will result in any
58 * non-{@link Serializable} listeners being silently dropped.
59 *
60 * @param <L> the type of event listener that is supported by this proxy.
61 *
62 * @since 3.0
63 * @version $Id: EventListenerSupport.java 1082302 2011-03-16 21:08:27Z oheger $
64 */
65 public class EventListenerSupport<L> implements Serializable {
66
67 /** Serialization version */
68 private static final long serialVersionUID = 3593265990380473632L;
69
70 /**
71 * The list used to hold the registered listeners. This list is
72 * intentionally a thread-safe copy-on-write-array so that traversals over
73 * the list of listeners will be atomic.
74 */
75 private List<L> listeners = new CopyOnWriteArrayList<L>();
76
77 /**
78 * The proxy representing the collection of listeners. Calls to this proxy
79 * object will sent to all registered listeners.
80 */
81 private transient L proxy;
82
83 /**
84 * Empty typed array for #getListeners().
85 */
86 private transient L[] prototypeArray;
87
88 /**
89 * Creates an EventListenerSupport object which supports the specified
90 * listener type.
91 *
92 * @param <T> the type of the listener interface
93 * @param listenerInterface the type of listener interface that will receive
94 * events posted using this class.
95 *
96 * @return an EventListenerSupport object which supports the specified
97 * listener type.
98 *
99 * @throws NullPointerException if <code>listenerInterface</code> is
100 * <code>null</code>.
101 * @throws IllegalArgumentException if <code>listenerInterface</code> is
102 * not an interface.
103 */
104 public static <T> EventListenerSupport<T> create(Class<T> listenerInterface) {
105 return new EventListenerSupport<T>(listenerInterface);
106 }
107
108 /**
109 * Creates an EventListenerSupport object which supports the provided
110 * listener interface.
111 *
112 * @param listenerInterface the type of listener interface that will receive
113 * events posted using this class.
114 *
115 * @throws NullPointerException if <code>listenerInterface</code> is
116 * <code>null</code>.
117 * @throws IllegalArgumentException if <code>listenerInterface</code> is
118 * not an interface.
119 */
120 public EventListenerSupport(Class<L> listenerInterface) {
121 this(listenerInterface, Thread.currentThread().getContextClassLoader());
122 }
123
124 /**
125 * Creates an EventListenerSupport object which supports the provided
126 * listener interface using the specified class loader to create the JDK
127 * dynamic proxy.
128 *
129 * @param listenerInterface the listener interface.
130 * @param classLoader the class loader.
131 *
132 * @throws NullPointerException if <code>listenerInterface</code> or
133 * <code>classLoader</code> is <code>null</code>.
134 * @throws IllegalArgumentException if <code>listenerInterface</code> is
135 * not an interface.
136 */
137 public EventListenerSupport(Class<L> listenerInterface, ClassLoader classLoader) {
138 this();
139 Validate.notNull(listenerInterface, "Listener interface cannot be null.");
140 Validate.notNull(classLoader, "ClassLoader cannot be null.");
141 Validate.isTrue(listenerInterface.isInterface(), "Class {0} is not an interface",
142 listenerInterface.getName());
143 initializeTransientFields(listenerInterface, classLoader);
144 }
145
146 /**
147 * Create a new EventListenerSupport instance.
148 * Serialization-friendly constructor.
149 */
150 private EventListenerSupport() {
151 }
152
153 /**
154 * Returns a proxy object which can be used to call listener methods on all
155 * of the registered event listeners. All calls made to this proxy will be
156 * forwarded to all registered listeners.
157 *
158 * @return a proxy object which can be used to call listener methods on all
159 * of the registered event listeners
160 */
161 public L fire() {
162 return proxy;
163 }
164
165 //**********************************************************************************************************************
166 // Other Methods
167 //**********************************************************************************************************************
168
169 /**
170 * Registers an event listener.
171 *
172 * @param listener the event listener (may not be <code>null</code>).
173 *
174 * @throws NullPointerException if <code>listener</code> is
175 * <code>null</code>.
176 */
177 public void addListener(L listener) {
178 Validate.notNull(listener, "Listener object cannot be null.");
179 listeners.add(listener);
180 }
181
182 /**
183 * Returns the number of registered listeners.
184 *
185 * @return the number of registered listeners.
186 */
187 int getListenerCount() {
188 return listeners.size();
189 }
190
191 /**
192 * Unregisters an event listener.
193 *
194 * @param listener the event listener (may not be <code>null</code>).
195 *
196 * @throws NullPointerException if <code>listener</code> is
197 * <code>null</code>.
198 */
199 public void removeListener(L listener) {
200 Validate.notNull(listener, "Listener object cannot be null.");
201 listeners.remove(listener);
202 }
203
204 /**
205 * Get an array containing the currently registered listeners.
206 * Modification to this array's elements will have no effect on the
207 * {@link EventListenerSupport} instance.
208 * @return L[]
209 */
210 public L[] getListeners() {
211 return listeners.toArray(prototypeArray);
212 }
213
214 /**
215 * Serialize.
216 * @param objectOutputStream the output stream
217 * @throws IOException if an IO error occurs
218 */
219 private void writeObject(ObjectOutputStream objectOutputStream) throws IOException {
220 ArrayList<L> serializableListeners = new ArrayList<L>();
221
222 // don't just rely on instanceof Serializable:
223 ObjectOutputStream testObjectOutputStream = new ObjectOutputStream(new ByteArrayOutputStream());
224 for (L listener : listeners) {
225 try {
226 testObjectOutputStream.writeObject(listener);
227 serializableListeners.add(listener);
228 } catch (IOException exception) {
229 //recreate test stream in case of indeterminate state
230 testObjectOutputStream = new ObjectOutputStream(new ByteArrayOutputStream());
231 }
232 }
233 /*
234 * we can reconstitute everything we need from an array of our listeners,
235 * which has the additional advantage of typically requiring less storage than a list:
236 */
237 objectOutputStream.writeObject(serializableListeners.toArray(prototypeArray));
238 }
239
240 /**
241 * Deserialize.
242 * @param objectInputStream the input stream
243 * @throws IOException if an IO error occurs
244 * @throws ClassNotFoundException if the class cannot be resolved
245 */
246 private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
247 @SuppressWarnings("unchecked")
248 L[] listeners = (L[]) objectInputStream.readObject();
249
250 this.listeners = new CopyOnWriteArrayList<L>(listeners);
251
252 @SuppressWarnings("unchecked")
253 Class<L> listenerInterface = (Class<L>) listeners.getClass().getComponentType();
254
255 initializeTransientFields(listenerInterface, Thread.currentThread().getContextClassLoader());
256 }
257
258 /**
259 * Initialize transient fields.
260 * @param listenerInterface the class of the listener interface
261 * @param classLoader the class loader to be used
262 */
263 private void initializeTransientFields(Class<L> listenerInterface, ClassLoader classLoader) {
264 @SuppressWarnings("unchecked")
265 L[] array = (L[]) Array.newInstance(listenerInterface, 0);
266 this.prototypeArray = array;
267 createProxy(listenerInterface, classLoader);
268 }
269
270 /**
271 * Create the proxy object.
272 * @param listenerInterface the class of the listener interface
273 * @param classLoader the class loader to be used
274 */
275 private void createProxy(Class<L> listenerInterface, ClassLoader classLoader) {
276 proxy = listenerInterface.cast(Proxy.newProxyInstance(classLoader,
277 new Class[] { listenerInterface }, createInvocationHandler()));
278 }
279
280 /**
281 * Create the {@link InvocationHandler} responsible for broadcasting calls
282 * to the managed listeners. Subclasses can override to provide custom behavior.
283 * @return ProxyInvocationHandler
284 */
285 protected InvocationHandler createInvocationHandler() {
286 return new ProxyInvocationHandler();
287 }
288
289 /**
290 * An invocation handler used to dispatch the event(s) to all the listeners.
291 */
292 protected class ProxyInvocationHandler implements InvocationHandler {
293 /** Serialization version */
294 private static final long serialVersionUID = 1L;
295
296 /**
297 * Propagates the method call to all registered listeners in place of
298 * the proxy listener object.
299 *
300 * @param proxy the proxy object representing a listener on which the
301 * invocation was called.
302 * @param method the listener method that will be called on all of the
303 * listeners.
304 * @param args event arguments to propagate to the listeners.
305 * @return the result of the method call
306 * @throws Throwable if an error occurs
307 */
308 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
309 for (L listener : listeners) {
310 method.invoke(listener, args);
311 }
312 return null;
313 }
314 }
315 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.event;
18
19 import java.lang.reflect.InvocationHandler;
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Proxy;
23 import java.util.Arrays;
24 import java.util.HashSet;
25 import java.util.Set;
26
27 import org.apache.commons.lang3.reflect.MethodUtils;
28
29 /**
30 * Provides some useful event-based utility methods.
31 *
32 * @since 3.0
33 * @version $Id: EventUtils.java 1091072 2011-04-11 13:42:03Z mbenson $
34 */
35 public class EventUtils {
36
37 /**
38 * Adds an event listener to the specified source. This looks for an "add" method corresponding to the event
39 * type (addActionListener, for example).
40 * @param eventSource the event source
41 * @param listenerType the event listener type
42 * @param listener the listener
43 * @param <L> the event listener type
44 *
45 * @throws IllegalArgumentException if the object doesn't support the listener type
46 */
47 public static <L> void addEventListener(Object eventSource, Class<L> listenerType, L listener) {
48 try {
49 MethodUtils.invokeMethod(eventSource, "add" + listenerType.getSimpleName(), listener);
50 } catch (NoSuchMethodException e) {
51 throw new IllegalArgumentException("Class " + eventSource.getClass().getName()
52 + " does not have a public add" + listenerType.getSimpleName()
53 + " method which takes a parameter of type " + listenerType.getName() + ".");
54 } catch (IllegalAccessException e) {
55 throw new IllegalArgumentException("Class " + eventSource.getClass().getName()
56 + " does not have an accessible add" + listenerType.getSimpleName ()
57 + " method which takes a parameter of type " + listenerType.getName() + ".");
58 } catch (InvocationTargetException e) {
59 throw new RuntimeException("Unable to add listener.", e.getCause());
60 }
61 }
62
63 /**
64 * Binds an event listener to a specific method on a specific object.
65 *
66 * @param <L> the event listener type
67 * @param target the target object
68 * @param methodName the name of the method to be called
69 * @param eventSource the object which is generating events (JButton, JList, etc.)
70 * @param listenerType the listener interface (ActionListener.class, SelectionListener.class, etc.)
71 * @param eventTypes the event types (method names) from the listener interface (if none specified, all will be
72 * supported)
73 */
74 public static <L> void bindEventsToMethod(Object target, String methodName, Object eventSource,
75 Class<L> listenerType, String... eventTypes) {
76 final L listener = listenerType.cast(Proxy.newProxyInstance(target.getClass().getClassLoader(),
77 new Class[] { listenerType }, new EventBindingInvocationHandler(target, methodName, eventTypes)));
78 addEventListener(eventSource, listenerType, listener);
79 }
80
81 private static class EventBindingInvocationHandler implements InvocationHandler {
82 private final Object target;
83 private final String methodName;
84 private final Set<String> eventTypes;
85
86 /**
87 * Creates a new instance of {@code EventBindingInvocationHandler}.
88 *
89 * @param target the target object for method invocations
90 * @param methodName the name of the method to be invoked
91 * @param eventTypes the names of the supported event types
92 */
93 EventBindingInvocationHandler(final Object target, final String methodName, String[] eventTypes) {
94 this.target = target;
95 this.methodName = methodName;
96 this.eventTypes = new HashSet<String>(Arrays.asList(eventTypes));
97 }
98
99 /**
100 * Handles a method invocation on the proxy object.
101 *
102 * @param proxy the proxy instance
103 * @param method the method to be invoked
104 * @param parameters the parameters for the method invocation
105 * @return the result of the method call
106 * @throws Throwable if an error occurs
107 */
108 public Object invoke(final Object proxy, final Method method, final Object[] parameters) throws Throwable {
109 if (eventTypes.isEmpty() || eventTypes.contains(method.getName())) {
110 if (hasMatchingParametersMethod(method)) {
111 return MethodUtils.invokeMethod(target, methodName, parameters);
112 } else {
113 return MethodUtils.invokeMethod(target, methodName);
114 }
115 }
116 return null;
117 }
118
119 /**
120 * Checks whether a method for the passed in parameters can be found.
121 *
122 * @param method the listener method invoked
123 * @return a flag whether the parameters could be matched
124 */
125 private boolean hasMatchingParametersMethod(final Method method) {
126 return MethodUtils.getAccessibleMethod(target.getClass(), methodName, method.getParameterTypes()) != null;
127 }
128 }
129 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 Provides some useful event-based utilities.
19 @since 3.0
20 </body>
21 </html>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 /**
19 * Exception thrown when a clone cannot be created. In contrast to
20 * {@link CloneNotSupportedException} this is a {@link RuntimeException}.
21 *
22 * @since 3.0
23 */
24 public class CloneFailedException extends RuntimeException {
25 // ~ Static fields/initializers ---------------------------------------------
26
27 private static final long serialVersionUID = 20091223L;
28
29 // ~ Constructors -----------------------------------------------------------
30
31 /**
32 * Constructs a CloneFailedException.
33 *
34 * @param message description of the exception
35 * @since upcoming
36 */
37 public CloneFailedException(final String message) {
38 super(message);
39 }
40
41 /**
42 * Constructs a CloneFailedException.
43 *
44 * @param cause cause of the exception
45 * @since upcoming
46 */
47 public CloneFailedException(final Throwable cause) {
48 super(cause);
49 }
50
51 /**
52 * Constructs a CloneFailedException.
53 *
54 * @param message description of the exception
55 * @param cause cause of the exception
56 * @since upcoming
57 */
58 public CloneFailedException(final String message, final Throwable cause) {
59 super(message, cause);
60 }
61 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 import java.util.List;
19 import java.util.Set;
20
21 import org.apache.commons.lang3.tuple.Pair;
22
23 /**
24 * <p>
25 * An exception that provides an easy and safe way to add contextual information.
26 * </p><p>
27 * An exception trace itself is often insufficient to provide rapid diagnosis of the issue.
28 * Frequently what is needed is a select few pieces of local contextual data.
29 * Providing this data is tricky however, due to concerns over formatting and nulls.
30 * </p><p>
31 * The contexted exception approach allows the exception to be created together with a
32 * list of context label-value pairs. This additional information is automatically included in
33 * the message and printed stack trace.
34 * </p><p>
35 * An unchecked version of this exception is provided by ContextedRuntimeException.
36 * </p>
37 * <p>
38 * To use this class write code as follows:
39 * </p>
40 * <pre>
41 * try {
42 * ...
43 * } catch (Exception e) {
44 * throw new ContextedException("Error posting account transaction", e)
45 * .addContextValue("Account Number", accountNumber)
46 * .addContextValue("Amount Posted", amountPosted)
47 * .addContextValue("Previous Balance", previousBalance)
48 * }
49 * }
50 * </pre> or improve diagnose data at a higher level:
51 * <pre>
52 * try {
53 * ...
54 * } catch (ContextedException e) {
55 * throw e.setContextValue("Transaction Id", transactionId);
56 * } catch (Exception e) {
57 * if (e instanceof ExceptionContext) {
58 * e.setContextValue("Transaction Id", transactionId);
59 * }
60 * throw e;
61 * }
62 * }
63 * </pre>
64 * </p><p>
65 * The output in a printStacktrace() (which often is written to a log) would look something like the following:
66 * <pre>
67 * org.apache.commons.lang3.exception.ContextedException: java.lang.Exception: Error posting account transaction
68 * Exception Context:
69 * [1:Account Number=null]
70 * [2:Amount Posted=100.00]
71 * [3:Previous Balance=-2.17]
72 * [4:Transaction Id=94ef1d15-d443-46c4-822b-637f26244899]
73 *
74 * ---------------------------------
75 * at org.apache.commons.lang3.exception.ContextedExceptionTest.testAddValue(ContextedExceptionTest.java:88)
76 * ..... (rest of trace)
77 * </pre>
78 * </p>
79 *
80 * @see ContextedRuntimeException
81 * @since 3.0
82 */
83 public class ContextedException extends Exception implements ExceptionContext {
84
85 /** The serialization version. */
86 private static final long serialVersionUID = 20110706L;
87 /** The context where the data is stored. */
88 private final ExceptionContext exceptionContext;
89
90 /**
91 * Instantiates ContextedException without message or cause.
92 * <p>
93 * The context information is stored using a default implementation.
94 */
95 public ContextedException() {
96 super();
97 exceptionContext = new DefaultExceptionContext();
98 }
99
100 /**
101 * Instantiates ContextedException with message, but without cause.
102 * <p>
103 * The context information is stored using a default implementation.
104 *
105 * @param message the exception message, may be null
106 */
107 public ContextedException(String message) {
108 super(message);
109 exceptionContext = new DefaultExceptionContext();
110 }
111
112 /**
113 * Instantiates ContextedException with cause, but without message.
114 * <p>
115 * The context information is stored using a default implementation.
116 *
117 * @param cause the underlying cause of the exception, may be null
118 */
119 public ContextedException(Throwable cause) {
120 super(cause);
121 exceptionContext = new DefaultExceptionContext();
122 }
123
124 /**
125 * Instantiates ContextedException with cause and message.
126 * <p>
127 * The context information is stored using a default implementation.
128 *
129 * @param message the exception message, may be null
130 * @param cause the underlying cause of the exception, may be null
131 */
132 public ContextedException(String message, Throwable cause) {
133 super(message, cause);
134 exceptionContext = new DefaultExceptionContext();
135 }
136
137 /**
138 * Instantiates ContextedException with cause, message, and ExceptionContext.
139 *
140 * @param message the exception message, may be null
141 * @param cause the underlying cause of the exception, may be null
142 * @param context the context used to store the additional information, null uses default implementation
143 */
144 public ContextedException(String message, Throwable cause, ExceptionContext context) {
145 super(message, cause);
146 if (context == null) {
147 context = new DefaultExceptionContext();
148 }
149 exceptionContext = context;
150 }
151
152 //-----------------------------------------------------------------------
153 /**
154 * Adds information helpful to a developer in diagnosing and correcting the problem.
155 * For the information to be meaningful, the value passed should have a reasonable
156 * toString() implementation.
157 * Different values can be added with the same label multiple times.
158 * <p>
159 * Note: This exception is only serializable if the object added is serializable.
160 * </p>
161 *
162 * @param label a textual label associated with information, {@code null} not recommended
163 * @param value information needed to understand exception, may be {@code null}
164 * @return {@code this}, for method chaining, not {@code null}
165 */
166 public ContextedException addContextValue(String label, Object value) {
167 exceptionContext.addContextValue(label, value);
168 return this;
169 }
170
171 /**
172 * Sets information helpful to a developer in diagnosing and correcting the problem.
173 * For the information to be meaningful, the value passed should have a reasonable
174 * toString() implementation.
175 * Any existing values with the same labels are removed before the new one is added.
176 * <p>
177 * Note: This exception is only serializable if the object added as value is serializable.
178 * </p>
179 *
180 * @param label a textual label associated with information, {@code null} not recommended
181 * @param value information needed to understand exception, may be {@code null}
182 * @return {@code this}, for method chaining, not {@code null}
183 */
184 public ContextedException setContextValue(String label, Object value) {
185 exceptionContext.setContextValue(label, value);
186 return this;
187 }
188
189 /**
190 * {@inheritDoc}
191 */
192 public List<Object> getContextValues(String label) {
193 return this.exceptionContext.getContextValues(label);
194 }
195
196 /**
197 * {@inheritDoc}
198 */
199 public Object getFirstContextValue(String label) {
200 return this.exceptionContext.getFirstContextValue(label);
201 }
202
203 /**
204 * {@inheritDoc}
205 */
206 public List<Pair<String, Object>> getContextEntries() {
207 return this.exceptionContext.getContextEntries();
208 }
209
210 /**
211 * {@inheritDoc}
212 */
213 public Set<String> getContextLabels() {
214 return exceptionContext.getContextLabels();
215 }
216
217 /**
218 * Provides the message explaining the exception, including the contextual data.
219 *
220 * @see java.lang.Throwable#getMessage()
221 * @return the message, never null
222 */
223 @Override
224 public String getMessage(){
225 return getFormattedExceptionMessage(super.getMessage());
226 }
227
228 /**
229 * Provides the message explaining the exception without the contextual data.
230 *
231 * @see java.lang.Throwable#getMessage()
232 * @return the message
233 * @since 3.0.1
234 */
235 public String getRawMessage() {
236 return super.getMessage();
237 }
238
239 /**
240 * {@inheritDoc}
241 */
242 public String getFormattedExceptionMessage(String baseMessage) {
243 return exceptionContext.getFormattedExceptionMessage(baseMessage);
244 }
245 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 import java.util.List;
19 import java.util.Set;
20
21 import org.apache.commons.lang3.tuple.Pair;
22
23 /**
24 * <p>
25 * A runtime exception that provides an easy and safe way to add contextual information.
26 * </p><p>
27 * An exception trace itself is often insufficient to provide rapid diagnosis of the issue.
28 * Frequently what is needed is a select few pieces of local contextual data.
29 * Providing this data is tricky however, due to concerns over formatting and nulls.
30 * </p><p>
31 * The contexted exception approach allows the exception to be created together with a
32 * list of context label-value pairs. This additional information is automatically included in
33 * the message and printed stack trace.
34 * </p><p>
35 * A checked version of this exception is provided by ContextedException.
36 * </p>
37 * <p>
38 * To use this class write code as follows:
39 * </p>
40 * <pre>
41 * try {
42 * ...
43 * } catch (Exception e) {
44 * throw new ContextedRuntimeException("Error posting account transaction", e)
45 * .addContextValue("Account Number", accountNumber)
46 * .addContextValue("Amount Posted", amountPosted)
47 * .addContextValue("Previous Balance", previousBalance)
48 * }
49 * }
50 * </pre> or improve diagnose data at a higher level:
51 * <pre>
52 * try {
53 * ...
54 * } catch (ContextedRuntimeException e) {
55 * throw e.setContextValue("Transaction Id", transactionId);
56 * } catch (Exception e) {
57 * if (e instanceof ExceptionContext) {
58 * e.setContextValue("Transaction Id", transactionId);
59 * }
60 * throw e;
61 * }
62 * }
63 * </pre>
64 * </p><p>
65 * The output in a printStacktrace() (which often is written to a log) would look something like the following:
66 * <pre>
67 * org.apache.commons.lang3.exception.ContextedRuntimeException: java.lang.Exception: Error posting account transaction
68 * Exception Context:
69 * [1:Account Number=null]
70 * [2:Amount Posted=100.00]
71 * [3:Previous Balance=-2.17]
72 * [4:Transaction Id=94ef1d15-d443-46c4-822b-637f26244899]
73 *
74 * ---------------------------------
75 * at org.apache.commons.lang3.exception.ContextedRuntimeExceptionTest.testAddValue(ContextedExceptionTest.java:88)
76 * ..... (rest of trace)
77 * </pre>
78 * </p>
79 *
80 * @see ContextedException
81 * @since 3.0
82 */
83 public class ContextedRuntimeException extends RuntimeException implements ExceptionContext {
84
85 /** The serialization version. */
86 private static final long serialVersionUID = 20110706L;
87 /** The context where the data is stored. */
88 private final ExceptionContext exceptionContext;
89
90 /**
91 * Instantiates ContextedRuntimeException without message or cause.
92 * <p>
93 * The context information is stored using a default implementation.
94 */
95 public ContextedRuntimeException() {
96 super();
97 exceptionContext = new DefaultExceptionContext();
98 }
99
100 /**
101 * Instantiates ContextedRuntimeException with message, but without cause.
102 * <p>
103 * The context information is stored using a default implementation.
104 *
105 * @param message the exception message, may be null
106 */
107 public ContextedRuntimeException(String message) {
108 super(message);
109 exceptionContext = new DefaultExceptionContext();
110 }
111
112 /**
113 * Instantiates ContextedRuntimeException with cause, but without message.
114 * <p>
115 * The context information is stored using a default implementation.
116 *
117 * @param cause the underlying cause of the exception, may be null
118 */
119 public ContextedRuntimeException(Throwable cause) {
120 super(cause);
121 exceptionContext = new DefaultExceptionContext();
122 }
123
124 /**
125 * Instantiates ContextedRuntimeException with cause and message.
126 * <p>
127 * The context information is stored using a default implementation.
128 *
129 * @param message the exception message, may be null
130 * @param cause the underlying cause of the exception, may be null
131 */
132 public ContextedRuntimeException(String message, Throwable cause) {
133 super(message, cause);
134 exceptionContext = new DefaultExceptionContext();
135 }
136
137 /**
138 * Instantiates ContextedRuntimeException with cause, message, and ExceptionContext.
139 *
140 * @param message the exception message, may be null
141 * @param cause the underlying cause of the exception, may be null
142 * @param context the context used to store the additional information, null uses default implementation
143 */
144 public ContextedRuntimeException(String message, Throwable cause, ExceptionContext context) {
145 super(message, cause);
146 if (context == null) {
147 context = new DefaultExceptionContext();
148 }
149 exceptionContext = context;
150 }
151
152 //-----------------------------------------------------------------------
153 /**
154 * Adds information helpful to a developer in diagnosing and correcting the problem.
155 * For the information to be meaningful, the value passed should have a reasonable
156 * toString() implementation.
157 * Different values can be added with the same label multiple times.
158 * <p>
159 * Note: This exception is only serializable if the object added is serializable.
160 * </p>
161 *
162 * @param label a textual label associated with information, {@code null} not recommended
163 * @param value information needed to understand exception, may be {@code null}
164 * @return {@code this}, for method chaining, not {@code null}
165 */
166 public ContextedRuntimeException addContextValue(String label, Object value) {
167 exceptionContext.addContextValue(label, value);
168 return this;
169 }
170
171 /**
172 * Sets information helpful to a developer in diagnosing and correcting the problem.
173 * For the information to be meaningful, the value passed should have a reasonable
174 * toString() implementation.
175 * Any existing values with the same labels are removed before the new one is added.
176 * <p>
177 * Note: This exception is only serializable if the object added as value is serializable.
178 * </p>
179 *
180 * @param label a textual label associated with information, {@code null} not recommended
181 * @param value information needed to understand exception, may be {@code null}
182 * @return {@code this}, for method chaining, not {@code null}
183 */
184 public ContextedRuntimeException setContextValue(String label, Object value) {
185 exceptionContext.setContextValue(label, value);
186 return this;
187 }
188
189 /**
190 * {@inheritDoc}
191 */
192 public List<Object> getContextValues(String label) {
193 return this.exceptionContext.getContextValues(label);
194 }
195
196 /**
197 * {@inheritDoc}
198 */
199 public Object getFirstContextValue(String label) {
200 return this.exceptionContext.getFirstContextValue(label);
201 }
202
203 /**
204 * {@inheritDoc}
205 */
206 public List<Pair<String, Object>> getContextEntries() {
207 return this.exceptionContext.getContextEntries();
208 }
209
210 /**
211 * {@inheritDoc}
212 */
213 public Set<String> getContextLabels() {
214 return exceptionContext.getContextLabels();
215 }
216
217 /**
218 * Provides the message explaining the exception, including the contextual data.
219 *
220 * @see java.lang.Throwable#getMessage()
221 * @return the message, never null
222 */
223 @Override
224 public String getMessage(){
225 return getFormattedExceptionMessage(super.getMessage());
226 }
227
228 /**
229 * Provides the message explaining the exception without the contextual data.
230 *
231 * @see java.lang.Throwable#getMessage()
232 * @return the message
233 * @since 3.0.1
234 */
235 public String getRawMessage() {
236 return super.getMessage();
237 }
238
239 /**
240 * {@inheritDoc}
241 */
242 public String getFormattedExceptionMessage(String baseMessage) {
243 return exceptionContext.getFormattedExceptionMessage(baseMessage);
244 }
245
246 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 import java.io.Serializable;
19 import java.util.ArrayList;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Set;
24
25 import org.apache.commons.lang3.StringUtils;
26 import org.apache.commons.lang3.tuple.ImmutablePair;
27 import org.apache.commons.lang3.tuple.Pair;
28
29 /**
30 * Default implementation of the context storing the label-value pairs for contexted exceptions.
31 * <p>
32 * This implementation is serializable, however this is dependent on the values that
33 * are added also being serializable.
34 * </p>
35 *
36 * @see ContextedException
37 * @see ContextedRuntimeException
38 * @since 3.0
39 */
40 public class DefaultExceptionContext implements ExceptionContext, Serializable {
41
42 /** The serialization version. */
43 private static final long serialVersionUID = 20110706L;
44
45 /** The list storing the label-data pairs. */
46 private final List<Pair<String, Object>> contextValues = new ArrayList<Pair<String,Object>>();
47
48 /**
49 * {@inheritDoc}
50 */
51 public DefaultExceptionContext addContextValue(String label, Object value) {
52 contextValues.add(new ImmutablePair<String, Object>(label, value));
53 return this;
54 }
55
56 /**
57 * {@inheritDoc}
58 */
59 public DefaultExceptionContext setContextValue(String label, Object value) {
60 for (final Iterator<Pair<String, Object>> iter = contextValues.iterator(); iter.hasNext();) {
61 final Pair<String, Object> p = iter.next();
62 if (StringUtils.equals(label, p.getKey())) {
63 iter.remove();
64 }
65 }
66 addContextValue(label, value);
67 return this;
68 }
69
70 /**
71 * {@inheritDoc}
72 */
73 public List<Object> getContextValues(String label) {
74 final List<Object> values = new ArrayList<Object>();
75 for (final Pair<String, Object> pair : contextValues) {
76 if (StringUtils.equals(label, pair.getKey())) {
77 values.add(pair.getValue());
78 }
79 }
80 return values;
81 }
82
83 /**
84 * {@inheritDoc}
85 */
86 public Object getFirstContextValue(String label) {
87 for (final Pair<String, Object> pair : contextValues) {
88 if (StringUtils.equals(label, pair.getKey())) {
89 return pair.getValue();
90 }
91 }
92 return null;
93 }
94
95 /**
96 * {@inheritDoc}
97 */
98 public Set<String> getContextLabels() {
99 final Set<String> labels = new HashSet<String>();
100 for (final Pair<String, Object> pair : contextValues) {
101 labels.add(pair.getKey());
102 }
103 return labels;
104 }
105
106 /**
107 * {@inheritDoc}
108 */
109 public List<Pair<String, Object>> getContextEntries() {
110 return contextValues;
111 }
112
113 /**
114 * Builds the message containing the contextual information.
115 *
116 * @param baseMessage the base exception message <b>without</b> context information appended
117 * @return the exception message <b>with</b> context information appended, never null
118 */
119 public String getFormattedExceptionMessage(String baseMessage){
120 StringBuilder buffer = new StringBuilder(256);
121 if (baseMessage != null) {
122 buffer.append(baseMessage);
123 }
124
125 if (contextValues.size() > 0) {
126 if (buffer.length() > 0) {
127 buffer.append('\n');
128 }
129 buffer.append("Exception Context:\n");
130
131 int i = 0;
132 for (final Pair<String, Object> pair : contextValues) {
133 buffer.append("\t[");
134 buffer.append(++i);
135 buffer.append(':');
136 buffer.append(pair.getKey());
137 buffer.append("=");
138 final Object value = pair.getValue();
139 if (value == null) {
140 buffer.append("null");
141 } else {
142 String valueStr;
143 try {
144 valueStr = value.toString();
145 } catch (Exception e) {
146 valueStr = "Exception thrown on toString(): " + ExceptionUtils.getStackTrace(e);
147 }
148 buffer.append(valueStr);
149 }
150 buffer.append("]\n");
151 }
152 buffer.append("---------------------------------");
153 }
154 return buffer.toString();
155 }
156
157 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 import java.util.List;
19 import java.util.Set;
20
21 import org.apache.commons.lang3.tuple.Pair;
22
23 /**
24 * Allows the storage and retrieval of contextual information based on label-value
25 * pairs for exceptions.
26 * <p>
27 * Implementations are expected to manage the pairs in a list-style collection
28 * that keeps the pairs in the sequence of their addition.
29 * </p>
30 *
31 * @see ContextedException
32 * @see ContextedRuntimeException
33 * @since 3.0
34 */
35 public interface ExceptionContext {
36
37 /**
38 * Adds a contextual label-value pair into this context.
39 * <p>
40 * The pair will be added to the context, independently of an already
41 * existing pair with the same label.
42 * </p>
43 *
44 * @param label the label of the item to add, {@code null} not recommended
45 * @param value the value of item to add, may be {@code null}
46 * @return {@code this}, for method chaining, not {@code null}
47 */
48 public ExceptionContext addContextValue(String label, Object value);
49
50 /**
51 * Sets a contextual label-value pair into this context.
52 * <p>
53 * The pair will be added normally, but any existing label-value pair with
54 * the same label is removed from the context.
55 * </p>
56 *
57 * @param label the label of the item to add, {@code null} not recommended
58 * @param value the value of item to add, may be {@code null}
59 * @return {@code this}, for method chaining, not {@code null}
60 */
61 public ExceptionContext setContextValue(String label, Object value);
62
63 /**
64 * Retrieves all the contextual data values associated with the label.
65 *
66 * @param label the label to get the contextual values for, may be {@code null}
67 * @return the contextual values associated with the label, never {@code null}
68 */
69 public List<Object> getContextValues(String label);
70
71 /**
72 * Retrieves the first available contextual data value associated with the label.
73 *
74 * @param label the label to get the contextual value for, may be {@code null}
75 * @return the first contextual value associated with the label, may be {@code null}
76 */
77 public Object getFirstContextValue(String label);
78
79 /**
80 * Retrieves the full set of labels defined in the contextual data.
81 *
82 * @return the set of labels, not {@code null}
83 */
84 public Set<String> getContextLabels();
85
86 /**
87 * Retrieves the full list of label-value pairs defined in the contextual data.
88 *
89 * @return the list of pairs, not {@code null}
90 */
91 public List<Pair<String, Object>> getContextEntries();
92
93 /**
94 * Gets the contextualized error message based on a base message.
95 * This will add the context label-value pairs to the message.
96 *
97 * @param baseMessage the base exception message <b>without</b> context information appended
98 * @return the exception message <b>with</b> context information appended, not {@code null}
99 */
100 public String getFormattedExceptionMessage(String baseMessage);
101
102 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 import java.io.PrintStream;
19 import java.io.PrintWriter;
20 import java.io.StringWriter;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.StringTokenizer;
26
27 import org.apache.commons.lang3.ArrayUtils;
28 import org.apache.commons.lang3.ClassUtils;
29 import org.apache.commons.lang3.StringUtils;
30 import org.apache.commons.lang3.SystemUtils;
31
32 /**
33 * <p>Provides utilities for manipulating and examining
34 * <code>Throwable</code> objects.</p>
35 *
36 * @since 1.0
37 * @version $Id: ExceptionUtils.java 1144929 2011-07-10 18:26:16Z ggregory $
38 */
39 public class ExceptionUtils {
40
41 /**
42 * <p>Used when printing stack frames to denote the start of a
43 * wrapped exception.</p>
44 *
45 * <p>Package private for accessibility by test suite.</p>
46 */
47 static final String WRAPPED_MARKER = " [wrapped] ";
48
49 /**
50 * <p>The names of methods commonly used to access a wrapped exception.</p>
51 */
52 // TODO: Remove in Lang 4.0
53 private static final String[] CAUSE_METHOD_NAMES = {
54 "getCause",
55 "getNextException",
56 "getTargetException",
57 "getException",
58 "getSourceException",
59 "getRootCause",
60 "getCausedByException",
61 "getNested",
62 "getLinkedException",
63 "getNestedException",
64 "getLinkedCause",
65 "getThrowable",
66 };
67
68 /**
69 * <p>
70 * Public constructor allows an instance of <code>ExceptionUtils</code> to be created, although that is not
71 * normally necessary.
72 * </p>
73 */
74 public ExceptionUtils() {
75 super();
76 }
77
78 //-----------------------------------------------------------------------
79 /**
80 * <p>Returns the default names used when searching for the cause of an exception.</p>
81 *
82 * <p>This may be modified and used in the overloaded getCause(Throwable, String[]) method.</p>
83 *
84 * @return cloned array of the default method names
85 * @since 3.0
86 * @deprecated This feature will be removed in Lang 4.0
87 */
88 @Deprecated
89 public static String[] getDefaultCauseMethodNames() {
90 return ArrayUtils.clone(CAUSE_METHOD_NAMES);
91 }
92
93 //-----------------------------------------------------------------------
94 /**
95 * <p>Introspects the <code>Throwable</code> to obtain the cause.</p>
96 *
97 * <p>The method searches for methods with specific names that return a
98 * <code>Throwable</code> object. This will pick up most wrapping exceptions,
99 * including those from JDK 1.4.
100 *
101 * <p>The default list searched for are:</p>
102 * <ul>
103 * <li><code>getCause()</code></li>
104 * <li><code>getNextException()</code></li>
105 * <li><code>getTargetException()</code></li>
106 * <li><code>getException()</code></li>
107 * <li><code>getSourceException()</code></li>
108 * <li><code>getRootCause()</code></li>
109 * <li><code>getCausedByException()</code></li>
110 * <li><code>getNested()</code></li>
111 * </ul>
112 *
113 * <p>If none of the above is found, returns <code>null</code>.</p>
114 *
115 * @param throwable the throwable to introspect for a cause, may be null
116 * @return the cause of the <code>Throwable</code>,
117 * <code>null</code> if none found or null throwable input
118 * @since 1.0
119 * @deprecated This feature will be removed in Lang 4.0
120 */
121 @Deprecated
122 public static Throwable getCause(Throwable throwable) {
123 return getCause(throwable, CAUSE_METHOD_NAMES);
124 }
125
126 /**
127 * <p>Introspects the <code>Throwable</code> to obtain the cause.</p>
128 *
129 * <p>A <code>null</code> set of method names means use the default set.
130 * A <code>null</code> in the set of method names will be ignored.</p>
131 *
132 * @param throwable the throwable to introspect for a cause, may be null
133 * @param methodNames the method names, null treated as default set
134 * @return the cause of the <code>Throwable</code>,
135 * <code>null</code> if none found or null throwable input
136 * @since 1.0
137 * @deprecated This feature will be removed in Lang 4.0
138 */
139 @Deprecated
140 public static Throwable getCause(Throwable throwable, String[] methodNames) {
141 if (throwable == null) {
142 return null;
143 }
144
145 if (methodNames == null) {
146 methodNames = CAUSE_METHOD_NAMES;
147 }
148
149 for (String methodName : methodNames) {
150 if (methodName != null) {
151 Throwable cause = getCauseUsingMethodName(throwable, methodName);
152 if (cause != null) {
153 return cause;
154 }
155 }
156 }
157
158 return null;
159 }
160
161 /**
162 * <p>Introspects the <code>Throwable</code> to obtain the root cause.</p>
163 *
164 * <p>This method walks through the exception chain to the last element,
165 * "root" of the tree, using {@link #getCause(Throwable)}, and
166 * returns that exception.</p>
167 *
168 * <p>From version 2.2, this method handles recursive cause structures
169 * that might otherwise cause infinite loops. If the throwable parameter
170 * has a cause of itself, then null will be returned. If the throwable
171 * parameter cause chain loops, the last element in the chain before the
172 * loop is returned.</p>
173 *
174 * @param throwable the throwable to get the root cause for, may be null
175 * @return the root cause of the <code>Throwable</code>,
176 * <code>null</code> if none found or null throwable input
177 */
178 public static Throwable getRootCause(Throwable throwable) {
179 List<Throwable> list = getThrowableList(throwable);
180 return (list.size() < 2 ? null : (Throwable)list.get(list.size() - 1));
181 }
182
183 /**
184 * <p>Finds a <code>Throwable</code> by method name.</p>
185 *
186 * @param throwable the exception to examine
187 * @param methodName the name of the method to find and invoke
188 * @return the wrapped exception, or <code>null</code> if not found
189 */
190 // TODO: Remove in Lang 4.0
191 private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) {
192 Method method = null;
193 try {
194 method = throwable.getClass().getMethod(methodName);
195 } catch (NoSuchMethodException ignored) { // NOPMD
196 // exception ignored
197 } catch (SecurityException ignored) { // NOPMD
198 // exception ignored
199 }
200
201 if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
202 try {
203 return (Throwable) method.invoke(throwable);
204 } catch (IllegalAccessException ignored) { // NOPMD
205 // exception ignored
206 } catch (IllegalArgumentException ignored) { // NOPMD
207 // exception ignored
208 } catch (InvocationTargetException ignored) { // NOPMD
209 // exception ignored
210 }
211 }
212 return null;
213 }
214
215 //-----------------------------------------------------------------------
216 /**
217 * <p>Counts the number of <code>Throwable</code> objects in the
218 * exception chain.</p>
219 *
220 * <p>A throwable without cause will return <code>1</code>.
221 * A throwable with one cause will return <code>2</code> and so on.
222 * A <code>null</code> throwable will return <code>0</code>.</p>
223 *
224 * <p>From version 2.2, this method handles recursive cause structures
225 * that might otherwise cause infinite loops. The cause chain is
226 * processed until the end is reached, or until the next item in the
227 * chain is already in the result set.</p>
228 *
229 * @param throwable the throwable to inspect, may be null
230 * @return the count of throwables, zero if null input
231 */
232 public static int getThrowableCount(Throwable throwable) {
233 return getThrowableList(throwable).size();
234 }
235
236 /**
237 * <p>Returns the list of <code>Throwable</code> objects in the
238 * exception chain.</p>
239 *
240 * <p>A throwable without cause will return an array containing
241 * one element - the input throwable.
242 * A throwable with one cause will return an array containing
243 * two elements. - the input throwable and the cause throwable.
244 * A <code>null</code> throwable will return an array of size zero.</p>
245 *
246 * <p>From version 2.2, this method handles recursive cause structures
247 * that might otherwise cause infinite loops. The cause chain is
248 * processed until the end is reached, or until the next item in the
249 * chain is already in the result set.</p>
250 *
251 * @see #getThrowableList(Throwable)
252 * @param throwable the throwable to inspect, may be null
253 * @return the array of throwables, never null
254 */
255 public static Throwable[] getThrowables(Throwable throwable) {
256 List<Throwable> list = getThrowableList(throwable);
257 return list.toArray(new Throwable[list.size()]);
258 }
259
260 /**
261 * <p>Returns the list of <code>Throwable</code> objects in the
262 * exception chain.</p>
263 *
264 * <p>A throwable without cause will return a list containing
265 * one element - the input throwable.
266 * A throwable with one cause will return a list containing
267 * two elements. - the input throwable and the cause throwable.
268 * A <code>null</code> throwable will return a list of size zero.</p>
269 *
270 * <p>This method handles recursive cause structures that might
271 * otherwise cause infinite loops. The cause chain is processed until
272 * the end is reached, or until the next item in the chain is already
273 * in the result set.</p>
274 *
275 * @param throwable the throwable to inspect, may be null
276 * @return the list of throwables, never null
277 * @since Commons Lang 2.2
278 */
279 public static List<Throwable> getThrowableList(Throwable throwable) {
280 List<Throwable> list = new ArrayList<Throwable>();
281 while (throwable != null && list.contains(throwable) == false) {
282 list.add(throwable);
283 throwable = ExceptionUtils.getCause(throwable);
284 }
285 return list;
286 }
287
288 //-----------------------------------------------------------------------
289 /**
290 * <p>Returns the (zero based) index of the first <code>Throwable</code>
291 * that matches the specified class (exactly) in the exception chain.
292 * Subclasses of the specified class do not match - see
293 * {@link #indexOfType(Throwable, Class)} for the opposite.</p>
294 *
295 * <p>A <code>null</code> throwable returns <code>-1</code>.
296 * A <code>null</code> type returns <code>-1</code>.
297 * No match in the chain returns <code>-1</code>.</p>
298 *
299 * @param throwable the throwable to inspect, may be null
300 * @param clazz the class to search for, subclasses do not match, null returns -1
301 * @return the index into the throwable chain, -1 if no match or null input
302 */
303 public static int indexOfThrowable(Throwable throwable, Class<?> clazz) {
304 return indexOf(throwable, clazz, 0, false);
305 }
306
307 /**
308 * <p>Returns the (zero based) index of the first <code>Throwable</code>
309 * that matches the specified type in the exception chain from
310 * a specified index.
311 * Subclasses of the specified class do not match - see
312 * {@link #indexOfType(Throwable, Class, int)} for the opposite.</p>
313 *
314 * <p>A <code>null</code> throwable returns <code>-1</code>.
315 * A <code>null</code> type returns <code>-1</code>.
316 * No match in the chain returns <code>-1</code>.
317 * A negative start index is treated as zero.
318 * A start index greater than the number of throwables returns <code>-1</code>.</p>
319 *
320 * @param throwable the throwable to inspect, may be null
321 * @param clazz the class to search for, subclasses do not match, null returns -1
322 * @param fromIndex the (zero based) index of the starting position,
323 * negative treated as zero, larger than chain size returns -1
324 * @return the index into the throwable chain, -1 if no match or null input
325 */
326 public static int indexOfThrowable(Throwable throwable, Class<?> clazz, int fromIndex) {
327 return indexOf(throwable, clazz, fromIndex, false);
328 }
329
330 //-----------------------------------------------------------------------
331 /**
332 * <p>Returns the (zero based) index of the first <code>Throwable</code>
333 * that matches the specified class or subclass in the exception chain.
334 * Subclasses of the specified class do match - see
335 * {@link #indexOfThrowable(Throwable, Class)} for the opposite.</p>
336 *
337 * <p>A <code>null</code> throwable returns <code>-1</code>.
338 * A <code>null</code> type returns <code>-1</code>.
339 * No match in the chain returns <code>-1</code>.</p>
340 *
341 * @param throwable the throwable to inspect, may be null
342 * @param type the type to search for, subclasses match, null returns -1
343 * @return the index into the throwable chain, -1 if no match or null input
344 * @since 2.1
345 */
346 public static int indexOfType(Throwable throwable, Class<?> type) {
347 return indexOf(throwable, type, 0, true);
348 }
349
350 /**
351 * <p>Returns the (zero based) index of the first <code>Throwable</code>
352 * that matches the specified type in the exception chain from
353 * a specified index.
354 * Subclasses of the specified class do match - see
355 * {@link #indexOfThrowable(Throwable, Class)} for the opposite.</p>
356 *
357 * <p>A <code>null</code> throwable returns <code>-1</code>.
358 * A <code>null</code> type returns <code>-1</code>.
359 * No match in the chain returns <code>-1</code>.
360 * A negative start index is treated as zero.
361 * A start index greater than the number of throwables returns <code>-1</code>.</p>
362 *
363 * @param throwable the throwable to inspect, may be null
364 * @param type the type to search for, subclasses match, null returns -1
365 * @param fromIndex the (zero based) index of the starting position,
366 * negative treated as zero, larger than chain size returns -1
367 * @return the index into the throwable chain, -1 if no match or null input
368 * @since 2.1
369 */
370 public static int indexOfType(Throwable throwable, Class<?> type, int fromIndex) {
371 return indexOf(throwable, type, fromIndex, true);
372 }
373
374 /**
375 * <p>Worker method for the <code>indexOfType</code> methods.</p>
376 *
377 * @param throwable the throwable to inspect, may be null
378 * @param type the type to search for, subclasses match, null returns -1
379 * @param fromIndex the (zero based) index of the starting position,
380 * negative treated as zero, larger than chain size returns -1
381 * @param subclass if <code>true</code>, compares with {@link Class#isAssignableFrom(Class)}, otherwise compares
382 * using references
383 * @return index of the <code>type</code> within throwables nested withing the specified <code>throwable</code>
384 */
385 private static int indexOf(Throwable throwable, Class<?> type, int fromIndex, boolean subclass) {
386 if (throwable == null || type == null) {
387 return -1;
388 }
389 if (fromIndex < 0) {
390 fromIndex = 0;
391 }
392 Throwable[] throwables = ExceptionUtils.getThrowables(throwable);
393 if (fromIndex >= throwables.length) {
394 return -1;
395 }
396 if (subclass) {
397 for (int i = fromIndex; i < throwables.length; i++) {
398 if (type.isAssignableFrom(throwables[i].getClass())) {
399 return i;
400 }
401 }
402 } else {
403 for (int i = fromIndex; i < throwables.length; i++) {
404 if (type.equals(throwables[i].getClass())) {
405 return i;
406 }
407 }
408 }
409 return -1;
410 }
411
412 //-----------------------------------------------------------------------
413 /**
414 * <p>Prints a compact stack trace for the root cause of a throwable
415 * to <code>System.err</code>.</p>
416 *
417 * <p>The compact stack trace starts with the root cause and prints
418 * stack frames up to the place where it was caught and wrapped.
419 * Then it prints the wrapped exception and continues with stack frames
420 * until the wrapper exception is caught and wrapped again, etc.</p>
421 *
422 * <p>The output of this method is consistent across JDK versions.
423 * Note that this is the opposite order to the JDK1.4 display.</p>
424 *
425 * <p>The method is equivalent to <code>printStackTrace</code> for throwables
426 * that don't have nested causes.</p>
427 *
428 * @param throwable the throwable to output
429 * @since 2.0
430 */
431 public static void printRootCauseStackTrace(Throwable throwable) {
432 printRootCauseStackTrace(throwable, System.err);
433 }
434
435 /**
436 * <p>Prints a compact stack trace for the root cause of a throwable.</p>
437 *
438 * <p>The compact stack trace starts with the root cause and prints
439 * stack frames up to the place where it was caught and wrapped.
440 * Then it prints the wrapped exception and continues with stack frames
441 * until the wrapper exception is caught and wrapped again, etc.</p>
442 *
443 * <p>The output of this method is consistent across JDK versions.
444 * Note that this is the opposite order to the JDK1.4 display.</p>
445 *
446 * <p>The method is equivalent to <code>printStackTrace</code> for throwables
447 * that don't have nested causes.</p>
448 *
449 * @param throwable the throwable to output, may be null
450 * @param stream the stream to output to, may not be null
451 * @throws IllegalArgumentException if the stream is <code>null</code>
452 * @since 2.0
453 */
454 public static void printRootCauseStackTrace(Throwable throwable, PrintStream stream) {
455 if (throwable == null) {
456 return;
457 }
458 if (stream == null) {
459 throw new IllegalArgumentException("The PrintStream must not be null");
460 }
461 String trace[] = getRootCauseStackTrace(throwable);
462 for (String element : trace) {
463 stream.println(element);
464 }
465 stream.flush();
466 }
467
468 /**
469 * <p>Prints a compact stack trace for the root cause of a throwable.</p>
470 *
471 * <p>The compact stack trace starts with the root cause and prints
472 * stack frames up to the place where it was caught and wrapped.
473 * Then it prints the wrapped exception and continues with stack frames
474 * until the wrapper exception is caught and wrapped again, etc.</p>
475 *
476 * <p>The output of this method is consistent across JDK versions.
477 * Note that this is the opposite order to the JDK1.4 display.</p>
478 *
479 * <p>The method is equivalent to <code>printStackTrace</code> for throwables
480 * that don't have nested causes.</p>
481 *
482 * @param throwable the throwable to output, may be null
483 * @param writer the writer to output to, may not be null
484 * @throws IllegalArgumentException if the writer is <code>null</code>
485 * @since 2.0
486 */
487 public static void printRootCauseStackTrace(Throwable throwable, PrintWriter writer) {
488 if (throwable == null) {
489 return;
490 }
491 if (writer == null) {
492 throw new IllegalArgumentException("The PrintWriter must not be null");
493 }
494 String trace[] = getRootCauseStackTrace(throwable);
495 for (String element : trace) {
496 writer.println(element);
497 }
498 writer.flush();
499 }
500
501 //-----------------------------------------------------------------------
502 /**
503 * <p>Creates a compact stack trace for the root cause of the supplied
504 * <code>Throwable</code>.</p>
505 *
506 * <p>The output of this method is consistent across JDK versions.
507 * It consists of the root exception followed by each of its wrapping
508 * exceptions separated by '[wrapped]'. Note that this is the opposite
509 * order to the JDK1.4 display.</p>
510 *
511 * @param throwable the throwable to examine, may be null
512 * @return an array of stack trace frames, never null
513 * @since 2.0
514 */
515 public static String[] getRootCauseStackTrace(Throwable throwable) {
516 if (throwable == null) {
517 return ArrayUtils.EMPTY_STRING_ARRAY;
518 }
519 Throwable throwables[] = getThrowables(throwable);
520 int count = throwables.length;
521 List<String> frames = new ArrayList<String>();
522 List<String> nextTrace = getStackFrameList(throwables[count - 1]);
523 for (int i = count; --i >= 0;) {
524 List<String> trace = nextTrace;
525 if (i != 0) {
526 nextTrace = getStackFrameList(throwables[i - 1]);
527 removeCommonFrames(trace, nextTrace);
528 }
529 if (i == count - 1) {
530 frames.add(throwables[i].toString());
531 } else {
532 frames.add(WRAPPED_MARKER + throwables[i].toString());
533 }
534 for (int j = 0; j < trace.size(); j++) {
535 frames.add(trace.get(j));
536 }
537 }
538 return frames.toArray(new String[frames.size()]);
539 }
540
541 /**
542 * <p>Removes common frames from the cause trace given the two stack traces.</p>
543 *
544 * @param causeFrames stack trace of a cause throwable
545 * @param wrapperFrames stack trace of a wrapper throwable
546 * @throws IllegalArgumentException if either argument is null
547 * @since 2.0
548 */
549 public static void removeCommonFrames(List<String> causeFrames, List<String> wrapperFrames) {
550 if (causeFrames == null || wrapperFrames == null) {
551 throw new IllegalArgumentException("The List must not be null");
552 }
553 int causeFrameIndex = causeFrames.size() - 1;
554 int wrapperFrameIndex = wrapperFrames.size() - 1;
555 while (causeFrameIndex >= 0 && wrapperFrameIndex >= 0) {
556 // Remove the frame from the cause trace if it is the same
557 // as in the wrapper trace
558 String causeFrame = causeFrames.get(causeFrameIndex);
559 String wrapperFrame = wrapperFrames.get(wrapperFrameIndex);
560 if (causeFrame.equals(wrapperFrame)) {
561 causeFrames.remove(causeFrameIndex);
562 }
563 causeFrameIndex--;
564 wrapperFrameIndex--;
565 }
566 }
567
568 //-----------------------------------------------------------------------
569 /**
570 * <p>Gets the stack trace from a Throwable as a String.</p>
571 *
572 * <p>The result of this method vary by JDK version as this method
573 * uses {@link Throwable#printStackTrace(java.io.PrintWriter)}.
574 * On JDK1.3 and earlier, the cause exception will not be shown
575 * unless the specified throwable alters printStackTrace.</p>
576 *
577 * @param throwable the <code>Throwable</code> to be examined
578 * @return the stack trace as generated by the exception's
579 * <code>printStackTrace(PrintWriter)</code> method
580 */
581 public static String getStackTrace(Throwable throwable) {
582 StringWriter sw = new StringWriter();
583 PrintWriter pw = new PrintWriter(sw, true);
584 throwable.printStackTrace(pw);
585 return sw.getBuffer().toString();
586 }
587
588 /**
589 * <p>Captures the stack trace associated with the specified
590 * <code>Throwable</code> object, decomposing it into a list of
591 * stack frames.</p>
592 *
593 * <p>The result of this method vary by JDK version as this method
594 * uses {@link Throwable#printStackTrace(java.io.PrintWriter)}.
595 * On JDK1.3 and earlier, the cause exception will not be shown
596 * unless the specified throwable alters printStackTrace.</p>
597 *
598 * @param throwable the <code>Throwable</code> to examine, may be null
599 * @return an array of strings describing each stack frame, never null
600 */
601 public static String[] getStackFrames(Throwable throwable) {
602 if (throwable == null) {
603 return ArrayUtils.EMPTY_STRING_ARRAY;
604 }
605 return getStackFrames(getStackTrace(throwable));
606 }
607
608 //-----------------------------------------------------------------------
609 /**
610 * <p>Returns an array where each element is a line from the argument.</p>
611 *
612 * <p>The end of line is determined by the value of {@link SystemUtils#LINE_SEPARATOR}.</p>
613 *
614 * @param stackTrace a stack trace String
615 * @return an array where each element is a line from the argument
616 */
617 static String[] getStackFrames(String stackTrace) {
618 String linebreak = SystemUtils.LINE_SEPARATOR;
619 StringTokenizer frames = new StringTokenizer(stackTrace, linebreak);
620 List<String> list = new ArrayList<String>();
621 while (frames.hasMoreTokens()) {
622 list.add(frames.nextToken());
623 }
624 return list.toArray(new String[list.size()]);
625 }
626
627 /**
628 * <p>Produces a <code>List</code> of stack frames - the message
629 * is not included. Only the trace of the specified exception is
630 * returned, any caused by trace is stripped.</p>
631 *
632 * <p>This works in most cases - it will only fail if the exception
633 * message contains a line that starts with:
634 * <code>&quot;&nbsp;&nbsp;&nbsp;at&quot;.</code></p>
635 *
636 * @param t is any throwable
637 * @return List of stack frames
638 */
639 static List<String> getStackFrameList(Throwable t) {
640 String stackTrace = getStackTrace(t);
641 String linebreak = SystemUtils.LINE_SEPARATOR;
642 StringTokenizer frames = new StringTokenizer(stackTrace, linebreak);
643 List<String> list = new ArrayList<String>();
644 boolean traceStarted = false;
645 while (frames.hasMoreTokens()) {
646 String token = frames.nextToken();
647 // Determine if the line starts with <whitespace>at
648 int at = token.indexOf("at");
649 if (at != -1 && token.substring(0, at).trim().length() == 0) {
650 traceStarted = true;
651 list.add(token);
652 } else if (traceStarted) {
653 break;
654 }
655 }
656 return list;
657 }
658
659 //-----------------------------------------------------------------------
660 /**
661 * Gets a short message summarising the exception.
662 * <p>
663 * The message returned is of the form
664 * {ClassNameWithoutPackage}: {ThrowableMessage}
665 *
666 * @param th the throwable to get a message for, null returns empty string
667 * @return the message, non-null
668 * @since Commons Lang 2.2
669 */
670 public static String getMessage(Throwable th) {
671 if (th == null) {
672 return "";
673 }
674 String clsName = ClassUtils.getShortClassName(th, null);
675 String msg = th.getMessage();
676 return clsName + ": " + StringUtils.defaultString(msg);
677 }
678
679 //-----------------------------------------------------------------------
680 /**
681 * Gets a short message summarising the root cause exception.
682 * <p>
683 * The message returned is of the form
684 * {ClassNameWithoutPackage}: {ThrowableMessage}
685 *
686 * @param th the throwable to get a message for, null returns empty string
687 * @return the message, non-null
688 * @since Commons Lang 2.2
689 */
690 public static String getRootCauseMessage(Throwable th) {
691 Throwable root = ExceptionUtils.getRootCause(th);
692 root = (root == null ? th : root);
693 return getMessage(root);
694 }
695
696 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 Provides functionality for Exceptions.
19 <p>Contains the concept of an exception with context i.e. such an exception
20 will contain a map with keys and values. This provides an easy way to pass valuable
21 state information at exception time in useful form to a calling process.</p>
22 <p>Lastly, {@link org.apache.commons.lang3.exception.ExceptionUtils}
23 also contains <code>Throwable</code> manipulation and examination routines.</p>
24 @since 1.0
25 </body>
26 </html>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.math;
17
18 import java.math.BigInteger;
19
20 /**
21 * <p><code>Fraction</code> is a <code>Number</code> implementation that
22 * stores fractions accurately.</p>
23 *
24 * <p>This class is immutable, and interoperable with most methods that accept
25 * a <code>Number</code>.</p>
26 *
27 * <p>Note that this class is intended for common use cases, it is <i>int</i>
28 * based and thus suffers from various overflow issues. For a BigInteger based
29 * equivalent, please see the Commons Math BigFraction class. </p>
30 *
31 * @since 2.0
32 * @version $Id: Fraction.java 1088899 2011-04-05 05:31:27Z bayard $
33 */
34 public final class Fraction extends Number implements Comparable<Fraction> {
35
36 /**
37 * Required for serialization support. Lang version 2.0.
38 *
39 * @see java.io.Serializable
40 */
41 private static final long serialVersionUID = 65382027393090L;
42
43 /**
44 * <code>Fraction</code> representation of 0.
45 */
46 public static final Fraction ZERO = new Fraction(0, 1);
47 /**
48 * <code>Fraction</code> representation of 1.
49 */
50 public static final Fraction ONE = new Fraction(1, 1);
51 /**
52 * <code>Fraction</code> representation of 1/2.
53 */
54 public static final Fraction ONE_HALF = new Fraction(1, 2);
55 /**
56 * <code>Fraction</code> representation of 1/3.
57 */
58 public static final Fraction ONE_THIRD = new Fraction(1, 3);
59 /**
60 * <code>Fraction</code> representation of 2/3.
61 */
62 public static final Fraction TWO_THIRDS = new Fraction(2, 3);
63 /**
64 * <code>Fraction</code> representation of 1/4.
65 */
66 public static final Fraction ONE_QUARTER = new Fraction(1, 4);
67 /**
68 * <code>Fraction</code> representation of 2/4.
69 */
70 public static final Fraction TWO_QUARTERS = new Fraction(2, 4);
71 /**
72 * <code>Fraction</code> representation of 3/4.
73 */
74 public static final Fraction THREE_QUARTERS = new Fraction(3, 4);
75 /**
76 * <code>Fraction</code> representation of 1/5.
77 */
78 public static final Fraction ONE_FIFTH = new Fraction(1, 5);
79 /**
80 * <code>Fraction</code> representation of 2/5.
81 */
82 public static final Fraction TWO_FIFTHS = new Fraction(2, 5);
83 /**
84 * <code>Fraction</code> representation of 3/5.
85 */
86 public static final Fraction THREE_FIFTHS = new Fraction(3, 5);
87 /**
88 * <code>Fraction</code> representation of 4/5.
89 */
90 public static final Fraction FOUR_FIFTHS = new Fraction(4, 5);
91
92
93 /**
94 * The numerator number part of the fraction (the three in three sevenths).
95 */
96 private final int numerator;
97 /**
98 * The denominator number part of the fraction (the seven in three sevenths).
99 */
100 private final int denominator;
101
102 /**
103 * Cached output hashCode (class is immutable).
104 */
105 private transient int hashCode = 0;
106 /**
107 * Cached output toString (class is immutable).
108 */
109 private transient String toString = null;
110 /**
111 * Cached output toProperString (class is immutable).
112 */
113 private transient String toProperString = null;
114
115 /**
116 * <p>Constructs a <code>Fraction</code> instance with the 2 parts
117 * of a fraction Y/Z.</p>
118 *
119 * @param numerator the numerator, for example the three in 'three sevenths'
120 * @param denominator the denominator, for example the seven in 'three sevenths'
121 */
122 private Fraction(int numerator, int denominator) {
123 super();
124 this.numerator = numerator;
125 this.denominator = denominator;
126 }
127
128 /**
129 * <p>Creates a <code>Fraction</code> instance with the 2 parts
130 * of a fraction Y/Z.</p>
131 *
132 * <p>Any negative signs are resolved to be on the numerator.</p>
133 *
134 * @param numerator the numerator, for example the three in 'three sevenths'
135 * @param denominator the denominator, for example the seven in 'three sevenths'
136 * @return a new fraction instance
137 * @throws ArithmeticException if the denominator is <code>zero</code>
138 * or the denominator is {@code negative} and the numerator is {@code Integer#MIN_VALUE}
139 */
140 public static Fraction getFraction(int numerator, int denominator) {
141 if (denominator == 0) {
142 throw new ArithmeticException("The denominator must not be zero");
143 }
144 if (denominator < 0) {
145 if (numerator==Integer.MIN_VALUE ||
146 denominator==Integer.MIN_VALUE) {
147 throw new ArithmeticException("overflow: can't negate");
148 }
149 numerator = -numerator;
150 denominator = -denominator;
151 }
152 return new Fraction(numerator, denominator);
153 }
154
155 /**
156 * <p>Creates a <code>Fraction</code> instance with the 3 parts
157 * of a fraction X Y/Z.</p>
158 *
159 * <p>The negative sign must be passed in on the whole number part.</p>
160 *
161 * @param whole the whole number, for example the one in 'one and three sevenths'
162 * @param numerator the numerator, for example the three in 'one and three sevenths'
163 * @param denominator the denominator, for example the seven in 'one and three sevenths'
164 * @return a new fraction instance
165 * @throws ArithmeticException if the denominator is <code>zero</code>
166 * @throws ArithmeticException if the denominator is negative
167 * @throws ArithmeticException if the numerator is negative
168 * @throws ArithmeticException if the resulting numerator exceeds
169 * <code>Integer.MAX_VALUE</code>
170 */
171 public static Fraction getFraction(int whole, int numerator, int denominator) {
172 if (denominator == 0) {
173 throw new ArithmeticException("The denominator must not be zero");
174 }
175 if (denominator < 0) {
176 throw new ArithmeticException("The denominator must not be negative");
177 }
178 if (numerator < 0) {
179 throw new ArithmeticException("The numerator must not be negative");
180 }
181 long numeratorValue;
182 if (whole < 0) {
183 numeratorValue = whole * (long)denominator - numerator;
184 } else {
185 numeratorValue = whole * (long)denominator + numerator;
186 }
187 if (numeratorValue < Integer.MIN_VALUE ||
188 numeratorValue > Integer.MAX_VALUE) {
189 throw new ArithmeticException("Numerator too large to represent as an Integer.");
190 }
191 return new Fraction((int) numeratorValue, denominator);
192 }
193
194 /**
195 * <p>Creates a reduced <code>Fraction</code> instance with the 2 parts
196 * of a fraction Y/Z.</p>
197 *
198 * <p>For example, if the input parameters represent 2/4, then the created
199 * fraction will be 1/2.</p>
200 *
201 * <p>Any negative signs are resolved to be on the numerator.</p>
202 *
203 * @param numerator the numerator, for example the three in 'three sevenths'
204 * @param denominator the denominator, for example the seven in 'three sevenths'
205 * @return a new fraction instance, with the numerator and denominator reduced
206 * @throws ArithmeticException if the denominator is <code>zero</code>
207 */
208 public static Fraction getReducedFraction(int numerator, int denominator) {
209 if (denominator == 0) {
210 throw new ArithmeticException("The denominator must not be zero");
211 }
212 if (numerator==0) {
213 return ZERO; // normalize zero.
214 }
215 // allow 2^k/-2^31 as a valid fraction (where k>0)
216 if (denominator==Integer.MIN_VALUE && (numerator&1)==0) {
217 numerator/=2; denominator/=2;
218 }
219 if (denominator < 0) {
220 if (numerator==Integer.MIN_VALUE ||
221 denominator==Integer.MIN_VALUE) {
222 throw new ArithmeticException("overflow: can't negate");
223 }
224 numerator = -numerator;
225 denominator = -denominator;
226 }
227 // simplify fraction.
228 int gcd = greatestCommonDivisor(numerator, denominator);
229 numerator /= gcd;
230 denominator /= gcd;
231 return new Fraction(numerator, denominator);
232 }
233
234 /**
235 * <p>Creates a <code>Fraction</code> instance from a <code>double</code> value.</p>
236 *
237 * <p>This method uses the <a href="http://archives.math.utk.edu/articles/atuyl/confrac/">
238 * continued fraction algorithm</a>, computing a maximum of
239 * 25 convergents and bounding the denominator by 10,000.</p>
240 *
241 * @param value the double value to convert
242 * @return a new fraction instance that is close to the value
243 * @throws ArithmeticException if <code>|value| > Integer.MAX_VALUE</code>
244 * or <code>value = NaN</code>
245 * @throws ArithmeticException if the calculated denominator is <code>zero</code>
246 * @throws ArithmeticException if the the algorithm does not converge
247 */
248 public static Fraction getFraction(double value) {
249 int sign = (value < 0 ? -1 : 1);
250 value = Math.abs(value);
251 if (value > Integer.MAX_VALUE || Double.isNaN(value)) {
252 throw new ArithmeticException
253 ("The value must not be greater than Integer.MAX_VALUE or NaN");
254 }
255 int wholeNumber = (int) value;
256 value -= wholeNumber;
257
258 int numer0 = 0; // the pre-previous
259 int denom0 = 1; // the pre-previous
260 int numer1 = 1; // the previous
261 int denom1 = 0; // the previous
262 int numer2 = 0; // the current, setup in calculation
263 int denom2 = 0; // the current, setup in calculation
264 int a1 = (int) value;
265 int a2 = 0;
266 double x1 = 1;
267 double x2 = 0;
268 double y1 = value - a1;
269 double y2 = 0;
270 double delta1, delta2 = Double.MAX_VALUE;
271 double fraction;
272 int i = 1;
273 // System.out.println("---");
274 do {
275 delta1 = delta2;
276 a2 = (int) (x1 / y1);
277 x2 = y1;
278 y2 = x1 - a2 * y1;
279 numer2 = a1 * numer1 + numer0;
280 denom2 = a1 * denom1 + denom0;
281 fraction = (double) numer2 / (double) denom2;
282 delta2 = Math.abs(value - fraction);
283 // System.out.println(numer2 + " " + denom2 + " " + fraction + " " + delta2 + " " + y1);
284 a1 = a2;
285 x1 = x2;
286 y1 = y2;
287 numer0 = numer1;
288 denom0 = denom1;
289 numer1 = numer2;
290 denom1 = denom2;
291 i++;
292 // System.out.println(">>" + delta1 +" "+ delta2+" "+(delta1 > delta2)+" "+i+" "+denom2);
293 } while ((delta1 > delta2) && (denom2 <= 10000) && (denom2 > 0) && (i < 25));
294 if (i == 25) {
295 throw new ArithmeticException("Unable to convert double to fraction");
296 }
297 return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0);
298 }
299
300 /**
301 * <p>Creates a Fraction from a <code>String</code>.</p>
302 *
303 * <p>The formats accepted are:</p>
304 *
305 * <ol>
306 * <li><code>double</code> String containing a dot</li>
307 * <li>'X Y/Z'</li>
308 * <li>'Y/Z'</li>
309 * <li>'X' (a simple whole number)</li>
310 * </ol>
311 * and a .</p>
312 *
313 * @param str the string to parse, must not be <code>null</code>
314 * @return the new <code>Fraction</code> instance
315 * @throws IllegalArgumentException if the string is <code>null</code>
316 * @throws NumberFormatException if the number format is invalid
317 */
318 public static Fraction getFraction(String str) {
319 if (str == null) {
320 throw new IllegalArgumentException("The string must not be null");
321 }
322 // parse double format
323 int pos = str.indexOf('.');
324 if (pos >= 0) {
325 return getFraction(Double.parseDouble(str));
326 }
327
328 // parse X Y/Z format
329 pos = str.indexOf(' ');
330 if (pos > 0) {
331 int whole = Integer.parseInt(str.substring(0, pos));
332 str = str.substring(pos + 1);
333 pos = str.indexOf('/');
334 if (pos < 0) {
335 throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z");
336 } else {
337 int numer = Integer.parseInt(str.substring(0, pos));
338 int denom = Integer.parseInt(str.substring(pos + 1));
339 return getFraction(whole, numer, denom);
340 }
341 }
342
343 // parse Y/Z format
344 pos = str.indexOf('/');
345 if (pos < 0) {
346 // simple whole number
347 return getFraction(Integer.parseInt(str), 1);
348 } else {
349 int numer = Integer.parseInt(str.substring(0, pos));
350 int denom = Integer.parseInt(str.substring(pos + 1));
351 return getFraction(numer, denom);
352 }
353 }
354
355 // Accessors
356 //-------------------------------------------------------------------
357
358 /**
359 * <p>Gets the numerator part of the fraction.</p>
360 *
361 * <p>This method may return a value greater than the denominator, an
362 * improper fraction, such as the seven in 7/4.</p>
363 *
364 * @return the numerator fraction part
365 */
366 public int getNumerator() {
367 return numerator;
368 }
369
370 /**
371 * <p>Gets the denominator part of the fraction.</p>
372 *
373 * @return the denominator fraction part
374 */
375 public int getDenominator() {
376 return denominator;
377 }
378
379 /**
380 * <p>Gets the proper numerator, always positive.</p>
381 *
382 * <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
383 * This method returns the 3 from the proper fraction.</p>
384 *
385 * <p>If the fraction is negative such as -7/4, it can be resolved into
386 * -1 3/4, so this method returns the positive proper numerator, 3.</p>
387 *
388 * @return the numerator fraction part of a proper fraction, always positive
389 */
390 public int getProperNumerator() {
391 return Math.abs(numerator % denominator);
392 }
393
394 /**
395 * <p>Gets the proper whole part of the fraction.</p>
396 *
397 * <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
398 * This method returns the 1 from the proper fraction.</p>
399 *
400 * <p>If the fraction is negative such as -7/4, it can be resolved into
401 * -1 3/4, so this method returns the positive whole part -1.</p>
402 *
403 * @return the whole fraction part of a proper fraction, that includes the sign
404 */
405 public int getProperWhole() {
406 return numerator / denominator;
407 }
408
409 // Number methods
410 //-------------------------------------------------------------------
411
412 /**
413 * <p>Gets the fraction as an <code>int</code>. This returns the whole number
414 * part of the fraction.</p>
415 *
416 * @return the whole number fraction part
417 */
418 @Override
419 public int intValue() {
420 return numerator / denominator;
421 }
422
423 /**
424 * <p>Gets the fraction as a <code>long</code>. This returns the whole number
425 * part of the fraction.</p>
426 *
427 * @return the whole number fraction part
428 */
429 @Override
430 public long longValue() {
431 return (long) numerator / denominator;
432 }
433
434 /**
435 * <p>Gets the fraction as a <code>float</code>. This calculates the fraction
436 * as the numerator divided by denominator.</p>
437 *
438 * @return the fraction as a <code>float</code>
439 */
440 @Override
441 public float floatValue() {
442 return ((float) numerator) / ((float) denominator);
443 }
444
445 /**
446 * <p>Gets the fraction as a <code>double</code>. This calculates the fraction
447 * as the numerator divided by denominator.</p>
448 *
449 * @return the fraction as a <code>double</code>
450 */
451 @Override
452 public double doubleValue() {
453 return ((double) numerator) / ((double) denominator);
454 }
455
456 // Calculations
457 //-------------------------------------------------------------------
458
459 /**
460 * <p>Reduce the fraction to the smallest values for the numerator and
461 * denominator, returning the result.</p>
462 *
463 * <p>For example, if this fraction represents 2/4, then the result
464 * will be 1/2.</p>
465 *
466 * @return a new reduced fraction instance, or this if no simplification possible
467 */
468 public Fraction reduce() {
469 if (numerator == 0) {
470 return equals(ZERO) ? this : ZERO;
471 }
472 int gcd = greatestCommonDivisor(Math.abs(numerator), denominator);
473 if (gcd == 1) {
474 return this;
475 }
476 return Fraction.getFraction(numerator / gcd, denominator / gcd);
477 }
478
479 /**
480 * <p>Gets a fraction that is the inverse (1/fraction) of this one.</p>
481 *
482 * <p>The returned fraction is not reduced.</p>
483 *
484 * @return a new fraction instance with the numerator and denominator
485 * inverted.
486 * @throws ArithmeticException if the fraction represents zero.
487 */
488 public Fraction invert() {
489 if (numerator == 0) {
490 throw new ArithmeticException("Unable to invert zero.");
491 }
492 if (numerator==Integer.MIN_VALUE) {
493 throw new ArithmeticException("overflow: can't negate numerator");
494 }
495 if (numerator<0) {
496 return new Fraction(-denominator, -numerator);
497 } else {
498 return new Fraction(denominator, numerator);
499 }
500 }
501
502 /**
503 * <p>Gets a fraction that is the negative (-fraction) of this one.</p>
504 *
505 * <p>The returned fraction is not reduced.</p>
506 *
507 * @return a new fraction instance with the opposite signed numerator
508 */
509 public Fraction negate() {
510 // the positive range is one smaller than the negative range of an int.
511 if (numerator==Integer.MIN_VALUE) {
512 throw new ArithmeticException("overflow: too large to negate");
513 }
514 return new Fraction(-numerator, denominator);
515 }
516
517 /**
518 * <p>Gets a fraction that is the positive equivalent of this one.</p>
519 * <p>More precisely: <code>(fraction >= 0 ? this : -fraction)</code></p>
520 *
521 * <p>The returned fraction is not reduced.</p>
522 *
523 * @return <code>this</code> if it is positive, or a new positive fraction
524 * instance with the opposite signed numerator
525 */
526 public Fraction abs() {
527 if (numerator >= 0) {
528 return this;
529 }
530 return negate();
531 }
532
533 /**
534 * <p>Gets a fraction that is raised to the passed in power.</p>
535 *
536 * <p>The returned fraction is in reduced form.</p>
537 *
538 * @param power the power to raise the fraction to
539 * @return <code>this</code> if the power is one, <code>ONE</code> if the power
540 * is zero (even if the fraction equals ZERO) or a new fraction instance
541 * raised to the appropriate power
542 * @throws ArithmeticException if the resulting numerator or denominator exceeds
543 * <code>Integer.MAX_VALUE</code>
544 */
545 public Fraction pow(int power) {
546 if (power == 1) {
547 return this;
548 } else if (power == 0) {
549 return ONE;
550 } else if (power < 0) {
551 if (power==Integer.MIN_VALUE) { // MIN_VALUE can't be negated.
552 return this.invert().pow(2).pow(-(power/2));
553 }
554 return this.invert().pow(-power);
555 } else {
556 Fraction f = this.multiplyBy(this);
557 if ((power % 2) == 0) { // if even...
558 return f.pow(power/2);
559 } else { // if odd...
560 return f.pow(power/2).multiplyBy(this);
561 }
562 }
563 }
564
565 /**
566 * <p>Gets the greatest common divisor of the absolute value of
567 * two numbers, using the "binary gcd" method which avoids
568 * division and modulo operations. See Knuth 4.5.2 algorithm B.
569 * This algorithm is due to Josef Stein (1961).</p>
570 *
571 * @param u a non-zero number
572 * @param v a non-zero number
573 * @return the greatest common divisor, never zero
574 */
575 private static int greatestCommonDivisor(int u, int v) {
576 // From Commons Math:
577 if ((u == 0) || (v == 0)) {
578 if ((u == Integer.MIN_VALUE) || (v == Integer.MIN_VALUE)) {
579 throw new ArithmeticException("overflow: gcd is 2^31");
580 }
581 return Math.abs(u) + Math.abs(v);
582 }
583 //if either operand is abs 1, return 1:
584 if (Math.abs(u) == 1 || Math.abs(v) == 1) {
585 return 1;
586 }
587 // keep u and v negative, as negative integers range down to
588 // -2^31, while positive numbers can only be as large as 2^31-1
589 // (i.e. we can't necessarily negate a negative number without
590 // overflow)
591 if (u>0) { u=-u; } // make u negative
592 if (v>0) { v=-v; } // make v negative
593 // B1. [Find power of 2]
594 int k=0;
595 while ((u&1)==0 && (v&1)==0 && k<31) { // while u and v are both even...
596 u/=2; v/=2; k++; // cast out twos.
597 }
598 if (k==31) {
599 throw new ArithmeticException("overflow: gcd is 2^31");
600 }
601 // B2. Initialize: u and v have been divided by 2^k and at least
602 // one is odd.
603 int t = ((u&1)==1) ? v : -(u/2)/*B3*/;
604 // t negative: u was odd, v may be even (t replaces v)
605 // t positive: u was even, v is odd (t replaces u)
606 do {
607 /* assert u<0 && v<0; */
608 // B4/B3: cast out twos from t.
609 while ((t&1)==0) { // while t is even..
610 t/=2; // cast out twos
611 }
612 // B5 [reset max(u,v)]
613 if (t>0) {
614 u = -t;
615 } else {
616 v = t;
617 }
618 // B6/B3. at this point both u and v should be odd.
619 t = (v - u)/2;
620 // |u| larger: t positive (replace u)
621 // |v| larger: t negative (replace v)
622 } while (t!=0);
623 return -u*(1<<k); // gcd is u*2^k
624 }
625
626 // Arithmetic
627 //-------------------------------------------------------------------
628
629 /**
630 * Multiply two integers, checking for overflow.
631 *
632 * @param x a factor
633 * @param y a factor
634 * @return the product <code>x*y</code>
635 * @throws ArithmeticException if the result can not be represented as
636 * an int
637 */
638 private static int mulAndCheck(int x, int y) {
639 long m = ((long)x)*((long)y);
640 if (m < Integer.MIN_VALUE ||
641 m > Integer.MAX_VALUE) {
642 throw new ArithmeticException("overflow: mul");
643 }
644 return (int)m;
645 }
646
647 /**
648 * Multiply two non-negative integers, checking for overflow.
649 *
650 * @param x a non-negative factor
651 * @param y a non-negative factor
652 * @return the product <code>x*y</code>
653 * @throws ArithmeticException if the result can not be represented as
654 * an int
655 */
656 private static int mulPosAndCheck(int x, int y) {
657 /* assert x>=0 && y>=0; */
658 long m = ((long)x)*((long)y);
659 if (m > Integer.MAX_VALUE) {
660 throw new ArithmeticException("overflow: mulPos");
661 }
662 return (int)m;
663 }
664
665 /**
666 * Add two integers, checking for overflow.
667 *
668 * @param x an addend
669 * @param y an addend
670 * @return the sum <code>x+y</code>
671 * @throws ArithmeticException if the result can not be represented as
672 * an int
673 */
674 private static int addAndCheck(int x, int y) {
675 long s = (long)x+(long)y;
676 if (s < Integer.MIN_VALUE ||
677 s > Integer.MAX_VALUE) {
678 throw new ArithmeticException("overflow: add");
679 }
680 return (int)s;
681 }
682
683 /**
684 * Subtract two integers, checking for overflow.
685 *
686 * @param x the minuend
687 * @param y the subtrahend
688 * @return the difference <code>x-y</code>
689 * @throws ArithmeticException if the result can not be represented as
690 * an int
691 */
692 private static int subAndCheck(int x, int y) {
693 long s = (long)x-(long)y;
694 if (s < Integer.MIN_VALUE ||
695 s > Integer.MAX_VALUE) {
696 throw new ArithmeticException("overflow: add");
697 }
698 return (int)s;
699 }
700
701 /**
702 * <p>Adds the value of this fraction to another, returning the result in reduced form.
703 * The algorithm follows Knuth, 4.5.1.</p>
704 *
705 * @param fraction the fraction to add, must not be <code>null</code>
706 * @return a <code>Fraction</code> instance with the resulting values
707 * @throws IllegalArgumentException if the fraction is <code>null</code>
708 * @throws ArithmeticException if the resulting numerator or denominator exceeds
709 * <code>Integer.MAX_VALUE</code>
710 */
711 public Fraction add(Fraction fraction) {
712 return addSub(fraction, true /* add */);
713 }
714
715 /**
716 * <p>Subtracts the value of another fraction from the value of this one,
717 * returning the result in reduced form.</p>
718 *
719 * @param fraction the fraction to subtract, must not be <code>null</code>
720 * @return a <code>Fraction</code> instance with the resulting values
721 * @throws IllegalArgumentException if the fraction is <code>null</code>
722 * @throws ArithmeticException if the resulting numerator or denominator
723 * cannot be represented in an <code>int</code>.
724 */
725 public Fraction subtract(Fraction fraction) {
726 return addSub(fraction, false /* subtract */);
727 }
728
729 /**
730 * Implement add and subtract using algorithm described in Knuth 4.5.1.
731 *
732 * @param fraction the fraction to subtract, must not be <code>null</code>
733 * @param isAdd true to add, false to subtract
734 * @return a <code>Fraction</code> instance with the resulting values
735 * @throws IllegalArgumentException if the fraction is <code>null</code>
736 * @throws ArithmeticException if the resulting numerator or denominator
737 * cannot be represented in an <code>int</code>.
738 */
739 private Fraction addSub(Fraction fraction, boolean isAdd) {
740 if (fraction == null) {
741 throw new IllegalArgumentException("The fraction must not be null");
742 }
743 // zero is identity for addition.
744 if (numerator == 0) {
745 return isAdd ? fraction : fraction.negate();
746 }
747 if (fraction.numerator == 0) {
748 return this;
749 }
750 // if denominators are randomly distributed, d1 will be 1 about 61%
751 // of the time.
752 int d1 = greatestCommonDivisor(denominator, fraction.denominator);
753 if (d1==1) {
754 // result is ( (u*v' +/- u'v) / u'v')
755 int uvp = mulAndCheck(numerator, fraction.denominator);
756 int upv = mulAndCheck(fraction.numerator, denominator);
757 return new Fraction
758 (isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv),
759 mulPosAndCheck(denominator, fraction.denominator));
760 }
761 // the quantity 't' requires 65 bits of precision; see knuth 4.5.1
762 // exercise 7. we're going to use a BigInteger.
763 // t = u(v'/d1) +/- v(u'/d1)
764 BigInteger uvp = BigInteger.valueOf(numerator)
765 .multiply(BigInteger.valueOf(fraction.denominator/d1));
766 BigInteger upv = BigInteger.valueOf(fraction.numerator)
767 .multiply(BigInteger.valueOf(denominator/d1));
768 BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
769 // but d2 doesn't need extra precision because
770 // d2 = gcd(t,d1) = gcd(t mod d1, d1)
771 int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
772 int d2 = (tmodd1==0)?d1:greatestCommonDivisor(tmodd1, d1);
773
774 // result is (t/d2) / (u'/d1)(v'/d2)
775 BigInteger w = t.divide(BigInteger.valueOf(d2));
776 if (w.bitLength() > 31) {
777 throw new ArithmeticException
778 ("overflow: numerator too large after multiply");
779 }
780 return new Fraction
781 (w.intValue(),
782 mulPosAndCheck(denominator/d1, fraction.denominator/d2));
783 }
784
785 /**
786 * <p>Multiplies the value of this fraction by another, returning the
787 * result in reduced form.</p>
788 *
789 * @param fraction the fraction to multiply by, must not be <code>null</code>
790 * @return a <code>Fraction</code> instance with the resulting values
791 * @throws IllegalArgumentException if the fraction is <code>null</code>
792 * @throws ArithmeticException if the resulting numerator or denominator exceeds
793 * <code>Integer.MAX_VALUE</code>
794 */
795 public Fraction multiplyBy(Fraction fraction) {
796 if (fraction == null) {
797 throw new IllegalArgumentException("The fraction must not be null");
798 }
799 if (numerator == 0 || fraction.numerator == 0) {
800 return ZERO;
801 }
802 // knuth 4.5.1
803 // make sure we don't overflow unless the result *must* overflow.
804 int d1 = greatestCommonDivisor(numerator, fraction.denominator);
805 int d2 = greatestCommonDivisor(fraction.numerator, denominator);
806 return getReducedFraction
807 (mulAndCheck(numerator/d1, fraction.numerator/d2),
808 mulPosAndCheck(denominator/d2, fraction.denominator/d1));
809 }
810
811 /**
812 * <p>Divide the value of this fraction by another.</p>
813 *
814 * @param fraction the fraction to divide by, must not be <code>null</code>
815 * @return a <code>Fraction</code> instance with the resulting values
816 * @throws IllegalArgumentException if the fraction is <code>null</code>
817 * @throws ArithmeticException if the fraction to divide by is zero
818 * @throws ArithmeticException if the resulting numerator or denominator exceeds
819 * <code>Integer.MAX_VALUE</code>
820 */
821 public Fraction divideBy(Fraction fraction) {
822 if (fraction == null) {
823 throw new IllegalArgumentException("The fraction must not be null");
824 }
825 if (fraction.numerator == 0) {
826 throw new ArithmeticException("The fraction to divide by must not be zero");
827 }
828 return multiplyBy(fraction.invert());
829 }
830
831 // Basics
832 //-------------------------------------------------------------------
833
834 /**
835 * <p>Compares this fraction to another object to test if they are equal.</p>.
836 *
837 * <p>To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.</p>
838 *
839 * @param obj the reference object with which to compare
840 * @return <code>true</code> if this object is equal
841 */
842 @Override
843 public boolean equals(Object obj) {
844 if (obj == this) {
845 return true;
846 }
847 if (obj instanceof Fraction == false) {
848 return false;
849 }
850 Fraction other = (Fraction) obj;
851 return (getNumerator() == other.getNumerator() &&
852 getDenominator() == other.getDenominator());
853 }
854
855 /**
856 * <p>Gets a hashCode for the fraction.</p>
857 *
858 * @return a hash code value for this object
859 */
860 @Override
861 public int hashCode() {
862 if (hashCode == 0) {
863 // hashcode update should be atomic.
864 hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator();
865 }
866 return hashCode;
867 }
868
869 /**
870 * <p>Compares this object to another based on size.</p>
871 *
872 * <p>Note: this class has a natural ordering that is inconsistent
873 * with equals, because, for example, equals treats 1/2 and 2/4 as
874 * different, whereas compareTo treats them as equal.
875 *
876 * @param other the object to compare to
877 * @return -1 if this is less, 0 if equal, +1 if greater
878 * @throws ClassCastException if the object is not a <code>Fraction</code>
879 * @throws NullPointerException if the object is <code>null</code>
880 */
881 public int compareTo(Fraction other) {
882 if (this==other) {
883 return 0;
884 }
885 if (numerator == other.numerator && denominator == other.denominator) {
886 return 0;
887 }
888
889 // otherwise see which is less
890 long first = (long) numerator * (long) other.denominator;
891 long second = (long) other.numerator * (long) denominator;
892 if (first == second) {
893 return 0;
894 } else if (first < second) {
895 return -1;
896 } else {
897 return 1;
898 }
899 }
900
901 /**
902 * <p>Gets the fraction as a <code>String</code>.</p>
903 *
904 * <p>The format used is '<i>numerator</i>/<i>denominator</i>' always.
905 *
906 * @return a <code>String</code> form of the fraction
907 */
908 @Override
909 public String toString() {
910 if (toString == null) {
911 toString = new StringBuilder(32)
912 .append(getNumerator())
913 .append('/')
914 .append(getDenominator()).toString();
915 }
916 return toString;
917 }
918
919 /**
920 * <p>Gets the fraction as a proper <code>String</code> in the format X Y/Z.</p>
921 *
922 * <p>The format used in '<i>wholeNumber</i> <i>numerator</i>/<i>denominator</i>'.
923 * If the whole number is zero it will be ommitted. If the numerator is zero,
924 * only the whole number is returned.</p>
925 *
926 * @return a <code>String</code> form of the fraction
927 */
928 public String toProperString() {
929 if (toProperString == null) {
930 if (numerator == 0) {
931 toProperString = "0";
932 } else if (numerator == denominator) {
933 toProperString = "1";
934 } else if (numerator == -1 * denominator) {
935 toProperString = "-1";
936 } else if ((numerator>0?-numerator:numerator) < -denominator) {
937 // note that we do the magnitude comparison test above with
938 // NEGATIVE (not positive) numbers, since negative numbers
939 // have a larger range. otherwise numerator==Integer.MIN_VALUE
940 // is handled incorrectly.
941 int properNumerator = getProperNumerator();
942 if (properNumerator == 0) {
943 toProperString = Integer.toString(getProperWhole());
944 } else {
945 toProperString = new StringBuilder(32)
946 .append(getProperWhole()).append(' ')
947 .append(properNumerator).append('/')
948 .append(getDenominator()).toString();
949 }
950 } else {
951 toProperString = new StringBuilder(32)
952 .append(getNumerator()).append('/')
953 .append(getDenominator()).toString();
954 }
955 }
956 return toProperString;
957 }
958 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.math;
17
18 /**
19 * <p>Provides IEEE-754r variants of NumberUtils methods. </p>
20 *
21 * <p>See: <a href="http://en.wikipedia.org/wiki/IEEE_754r">http://en.wikipedia.org/wiki/IEEE_754r</a></p>
22 *
23 * @since 2.4
24 * @version $Id: IEEE754rUtils.java 1088899 2011-04-05 05:31:27Z bayard $
25 */
26 public class IEEE754rUtils {
27
28 /**
29 * <p>Returns the minimum value in an array.</p>
30 *
31 * @param array an array, must not be null or empty
32 * @return the minimum value in the array
33 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
34 * @throws IllegalArgumentException if <code>array</code> is empty
35 */
36 public static double min(double[] array) {
37 // Validates input
38 if (array == null) {
39 throw new IllegalArgumentException("The Array must not be null");
40 } else if (array.length == 0) {
41 throw new IllegalArgumentException("Array cannot be empty.");
42 }
43
44 // Finds and returns min
45 double min = array[0];
46 for (int i = 1; i < array.length; i++) {
47 min = min(array[i], min);
48 }
49
50 return min;
51 }
52
53 /**
54 * <p>Returns the minimum value in an array.</p>
55 *
56 * @param array an array, must not be null or empty
57 * @return the minimum value in the array
58 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
59 * @throws IllegalArgumentException if <code>array</code> is empty
60 */
61 public static float min(float[] array) {
62 // Validates input
63 if (array == null) {
64 throw new IllegalArgumentException("The Array must not be null");
65 } else if (array.length == 0) {
66 throw new IllegalArgumentException("Array cannot be empty.");
67 }
68
69 // Finds and returns min
70 float min = array[0];
71 for (int i = 1; i < array.length; i++) {
72 min = min(array[i], min);
73 }
74
75 return min;
76 }
77
78 /**
79 * <p>Gets the minimum of three <code>double</code> values.</p>
80 *
81 * <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
82 *
83 * @param a value 1
84 * @param b value 2
85 * @param c value 3
86 * @return the smallest of the values
87 */
88 public static double min(double a, double b, double c) {
89 return min(min(a, b), c);
90 }
91
92 /**
93 * <p>Gets the minimum of two <code>double</code> values.</p>
94 *
95 * <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
96 *
97 * @param a value 1
98 * @param b value 2
99 * @return the smallest of the values
100 */
101 public static double min(double a, double b) {
102 if(Double.isNaN(a)) {
103 return b;
104 } else
105 if(Double.isNaN(b)) {
106 return a;
107 } else {
108 return Math.min(a, b);
109 }
110 }
111
112 /**
113 * <p>Gets the minimum of three <code>float</code> values.</p>
114 *
115 * <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
116 *
117 * @param a value 1
118 * @param b value 2
119 * @param c value 3
120 * @return the smallest of the values
121 */
122 public static float min(float a, float b, float c) {
123 return min(min(a, b), c);
124 }
125
126 /**
127 * <p>Gets the minimum of two <code>float</code> values.</p>
128 *
129 * <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
130 *
131 * @param a value 1
132 * @param b value 2
133 * @return the smallest of the values
134 */
135 public static float min(float a, float b) {
136 if(Float.isNaN(a)) {
137 return b;
138 } else
139 if(Float.isNaN(b)) {
140 return a;
141 } else {
142 return Math.min(a, b);
143 }
144 }
145
146 /**
147 * <p>Returns the maximum value in an array.</p>
148 *
149 * @param array an array, must not be null or empty
150 * @return the minimum value in the array
151 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
152 * @throws IllegalArgumentException if <code>array</code> is empty
153 */
154 public static double max(double[] array) {
155 // Validates input
156 if (array== null) {
157 throw new IllegalArgumentException("The Array must not be null");
158 } else if (array.length == 0) {
159 throw new IllegalArgumentException("Array cannot be empty.");
160 }
161
162 // Finds and returns max
163 double max = array[0];
164 for (int j = 1; j < array.length; j++) {
165 max = max(array[j], max);
166 }
167
168 return max;
169 }
170
171 /**
172 * <p>Returns the maximum value in an array.</p>
173 *
174 * @param array an array, must not be null or empty
175 * @return the minimum value in the array
176 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
177 * @throws IllegalArgumentException if <code>array</code> is empty
178 */
179 public static float max(float[] array) {
180 // Validates input
181 if (array == null) {
182 throw new IllegalArgumentException("The Array must not be null");
183 } else if (array.length == 0) {
184 throw new IllegalArgumentException("Array cannot be empty.");
185 }
186
187 // Finds and returns max
188 float max = array[0];
189 for (int j = 1; j < array.length; j++) {
190 max = max(array[j], max);
191 }
192
193 return max;
194 }
195
196 /**
197 * <p>Gets the maximum of three <code>double</code> values.</p>
198 *
199 * <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
200 *
201 * @param a value 1
202 * @param b value 2
203 * @param c value 3
204 * @return the largest of the values
205 */
206 public static double max(double a, double b, double c) {
207 return max(max(a, b), c);
208 }
209
210 /**
211 * <p>Gets the maximum of two <code>double</code> values.</p>
212 *
213 * <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
214 *
215 * @param a value 1
216 * @param b value 2
217 * @return the largest of the values
218 */
219 public static double max(double a, double b) {
220 if(Double.isNaN(a)) {
221 return b;
222 } else
223 if(Double.isNaN(b)) {
224 return a;
225 } else {
226 return Math.max(a, b);
227 }
228 }
229
230 /**
231 * <p>Gets the maximum of three <code>float</code> values.</p>
232 *
233 * <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
234 *
235 * @param a value 1
236 * @param b value 2
237 * @param c value 3
238 * @return the largest of the values
239 */
240 public static float max(float a, float b, float c) {
241 return max(max(a, b), c);
242 }
243
244 /**
245 * <p>Gets the maximum of two <code>float</code> values.</p>
246 *
247 * <p>NaN is only returned if all numbers are NaN as per IEEE-754r. </p>
248 *
249 * @param a value 1
250 * @param b value 2
251 * @return the largest of the values
252 */
253 public static float max(float a, float b) {
254 if(Float.isNaN(a)) {
255 return b;
256 } else
257 if(Float.isNaN(b)) {
258 return a;
259 } else {
260 return Math.max(a, b);
261 }
262 }
263
264 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.math;
17
18 import java.math.BigDecimal;
19 import java.math.BigInteger;
20
21 import org.apache.commons.lang3.StringUtils;
22
23 /**
24 * <p>Provides extra functionality for Java Number classes.</p>
25 *
26 * @since 2.0
27 * @version $Id: NumberUtils.java 1153490 2011-08-03 13:53:35Z ggregory $
28 */
29 public class NumberUtils {
30
31 /** Reusable Long constant for zero. */
32 public static final Long LONG_ZERO = Long.valueOf(0L);
33 /** Reusable Long constant for one. */
34 public static final Long LONG_ONE = Long.valueOf(1L);
35 /** Reusable Long constant for minus one. */
36 public static final Long LONG_MINUS_ONE = Long.valueOf(-1L);
37 /** Reusable Integer constant for zero. */
38 public static final Integer INTEGER_ZERO = Integer.valueOf(0);
39 /** Reusable Integer constant for one. */
40 public static final Integer INTEGER_ONE = Integer.valueOf(1);
41 /** Reusable Integer constant for minus one. */
42 public static final Integer INTEGER_MINUS_ONE = Integer.valueOf(-1);
43 /** Reusable Short constant for zero. */
44 public static final Short SHORT_ZERO = Short.valueOf((short) 0);
45 /** Reusable Short constant for one. */
46 public static final Short SHORT_ONE = Short.valueOf((short) 1);
47 /** Reusable Short constant for minus one. */
48 public static final Short SHORT_MINUS_ONE = Short.valueOf((short) -1);
49 /** Reusable Byte constant for zero. */
50 public static final Byte BYTE_ZERO = Byte.valueOf((byte) 0);
51 /** Reusable Byte constant for one. */
52 public static final Byte BYTE_ONE = Byte.valueOf((byte) 1);
53 /** Reusable Byte constant for minus one. */
54 public static final Byte BYTE_MINUS_ONE = Byte.valueOf((byte) -1);
55 /** Reusable Double constant for zero. */
56 public static final Double DOUBLE_ZERO = Double.valueOf(0.0d);
57 /** Reusable Double constant for one. */
58 public static final Double DOUBLE_ONE = Double.valueOf(1.0d);
59 /** Reusable Double constant for minus one. */
60 public static final Double DOUBLE_MINUS_ONE = Double.valueOf(-1.0d);
61 /** Reusable Float constant for zero. */
62 public static final Float FLOAT_ZERO = Float.valueOf(0.0f);
63 /** Reusable Float constant for one. */
64 public static final Float FLOAT_ONE = Float.valueOf(1.0f);
65 /** Reusable Float constant for minus one. */
66 public static final Float FLOAT_MINUS_ONE = Float.valueOf(-1.0f);
67
68 /**
69 * <p><code>NumberUtils</code> instances should NOT be constructed in standard programming.
70 * Instead, the class should be used as <code>NumberUtils.toInt("6");</code>.</p>
71 *
72 * <p>This constructor is public to permit tools that require a JavaBean instance
73 * to operate.</p>
74 */
75 public NumberUtils() {
76 super();
77 }
78
79 //-----------------------------------------------------------------------
80 /**
81 * <p>Convert a <code>String</code> to an <code>int</code>, returning
82 * <code>zero</code> if the conversion fails.</p>
83 *
84 * <p>If the string is <code>null</code>, <code>zero</code> is returned.</p>
85 *
86 * <pre>
87 * NumberUtils.toInt(null) = 0
88 * NumberUtils.toInt("") = 0
89 * NumberUtils.toInt("1") = 1
90 * </pre>
91 *
92 * @param str the string to convert, may be null
93 * @return the int represented by the string, or <code>zero</code> if
94 * conversion fails
95 * @since 2.1
96 */
97 public static int toInt(String str) {
98 return toInt(str, 0);
99 }
100
101 /**
102 * <p>Convert a <code>String</code> to an <code>int</code>, returning a
103 * default value if the conversion fails.</p>
104 *
105 * <p>If the string is <code>null</code>, the default value is returned.</p>
106 *
107 * <pre>
108 * NumberUtils.toInt(null, 1) = 1
109 * NumberUtils.toInt("", 1) = 1
110 * NumberUtils.toInt("1", 0) = 1
111 * </pre>
112 *
113 * @param str the string to convert, may be null
114 * @param defaultValue the default value
115 * @return the int represented by the string, or the default if conversion fails
116 * @since 2.1
117 */
118 public static int toInt(String str, int defaultValue) {
119 if(str == null) {
120 return defaultValue;
121 }
122 try {
123 return Integer.parseInt(str);
124 } catch (NumberFormatException nfe) {
125 return defaultValue;
126 }
127 }
128
129 /**
130 * <p>Convert a <code>String</code> to a <code>long</code>, returning
131 * <code>zero</code> if the conversion fails.</p>
132 *
133 * <p>If the string is <code>null</code>, <code>zero</code> is returned.</p>
134 *
135 * <pre>
136 * NumberUtils.toLong(null) = 0L
137 * NumberUtils.toLong("") = 0L
138 * NumberUtils.toLong("1") = 1L
139 * </pre>
140 *
141 * @param str the string to convert, may be null
142 * @return the long represented by the string, or <code>0</code> if
143 * conversion fails
144 * @since 2.1
145 */
146 public static long toLong(String str) {
147 return toLong(str, 0L);
148 }
149
150 /**
151 * <p>Convert a <code>String</code> to a <code>long</code>, returning a
152 * default value if the conversion fails.</p>
153 *
154 * <p>If the string is <code>null</code>, the default value is returned.</p>
155 *
156 * <pre>
157 * NumberUtils.toLong(null, 1L) = 1L
158 * NumberUtils.toLong("", 1L) = 1L
159 * NumberUtils.toLong("1", 0L) = 1L
160 * </pre>
161 *
162 * @param str the string to convert, may be null
163 * @param defaultValue the default value
164 * @return the long represented by the string, or the default if conversion fails
165 * @since 2.1
166 */
167 public static long toLong(String str, long defaultValue) {
168 if (str == null) {
169 return defaultValue;
170 }
171 try {
172 return Long.parseLong(str);
173 } catch (NumberFormatException nfe) {
174 return defaultValue;
175 }
176 }
177
178 /**
179 * <p>Convert a <code>String</code> to a <code>float</code>, returning
180 * <code>0.0f</code> if the conversion fails.</p>
181 *
182 * <p>If the string <code>str</code> is <code>null</code>,
183 * <code>0.0f</code> is returned.</p>
184 *
185 * <pre>
186 * NumberUtils.toFloat(null) = 0.0f
187 * NumberUtils.toFloat("") = 0.0f
188 * NumberUtils.toFloat("1.5") = 1.5f
189 * </pre>
190 *
191 * @param str the string to convert, may be <code>null</code>
192 * @return the float represented by the string, or <code>0.0f</code>
193 * if conversion fails
194 * @since 2.1
195 */
196 public static float toFloat(String str) {
197 return toFloat(str, 0.0f);
198 }
199
200 /**
201 * <p>Convert a <code>String</code> to a <code>float</code>, returning a
202 * default value if the conversion fails.</p>
203 *
204 * <p>If the string <code>str</code> is <code>null</code>, the default
205 * value is returned.</p>
206 *
207 * <pre>
208 * NumberUtils.toFloat(null, 1.1f) = 1.0f
209 * NumberUtils.toFloat("", 1.1f) = 1.1f
210 * NumberUtils.toFloat("1.5", 0.0f) = 1.5f
211 * </pre>
212 *
213 * @param str the string to convert, may be <code>null</code>
214 * @param defaultValue the default value
215 * @return the float represented by the string, or defaultValue
216 * if conversion fails
217 * @since 2.1
218 */
219 public static float toFloat(String str, float defaultValue) {
220 if (str == null) {
221 return defaultValue;
222 }
223 try {
224 return Float.parseFloat(str);
225 } catch (NumberFormatException nfe) {
226 return defaultValue;
227 }
228 }
229
230 /**
231 * <p>Convert a <code>String</code> to a <code>double</code>, returning
232 * <code>0.0d</code> if the conversion fails.</p>
233 *
234 * <p>If the string <code>str</code> is <code>null</code>,
235 * <code>0.0d</code> is returned.</p>
236 *
237 * <pre>
238 * NumberUtils.toDouble(null) = 0.0d
239 * NumberUtils.toDouble("") = 0.0d
240 * NumberUtils.toDouble("1.5") = 1.5d
241 * </pre>
242 *
243 * @param str the string to convert, may be <code>null</code>
244 * @return the double represented by the string, or <code>0.0d</code>
245 * if conversion fails
246 * @since 2.1
247 */
248 public static double toDouble(String str) {
249 return toDouble(str, 0.0d);
250 }
251
252 /**
253 * <p>Convert a <code>String</code> to a <code>double</code>, returning a
254 * default value if the conversion fails.</p>
255 *
256 * <p>If the string <code>str</code> is <code>null</code>, the default
257 * value is returned.</p>
258 *
259 * <pre>
260 * NumberUtils.toDouble(null, 1.1d) = 1.1d
261 * NumberUtils.toDouble("", 1.1d) = 1.1d
262 * NumberUtils.toDouble("1.5", 0.0d) = 1.5d
263 * </pre>
264 *
265 * @param str the string to convert, may be <code>null</code>
266 * @param defaultValue the default value
267 * @return the double represented by the string, or defaultValue
268 * if conversion fails
269 * @since 2.1
270 */
271 public static double toDouble(String str, double defaultValue) {
272 if (str == null) {
273 return defaultValue;
274 }
275 try {
276 return Double.parseDouble(str);
277 } catch (NumberFormatException nfe) {
278 return defaultValue;
279 }
280 }
281
282 //-----------------------------------------------------------------------
283 /**
284 * <p>Convert a <code>String</code> to a <code>byte</code>, returning
285 * <code>zero</code> if the conversion fails.</p>
286 *
287 * <p>If the string is <code>null</code>, <code>zero</code> is returned.</p>
288 *
289 * <pre>
290 * NumberUtils.toByte(null) = 0
291 * NumberUtils.toByte("") = 0
292 * NumberUtils.toByte("1") = 1
293 * </pre>
294 *
295 * @param str the string to convert, may be null
296 * @return the byte represented by the string, or <code>zero</code> if
297 * conversion fails
298 * @since 2.5
299 */
300 public static byte toByte(String str) {
301 return toByte(str, (byte) 0);
302 }
303
304 /**
305 * <p>Convert a <code>String</code> to a <code>byte</code>, returning a
306 * default value if the conversion fails.</p>
307 *
308 * <p>If the string is <code>null</code>, the default value is returned.</p>
309 *
310 * <pre>
311 * NumberUtils.toByte(null, 1) = 1
312 * NumberUtils.toByte("", 1) = 1
313 * NumberUtils.toByte("1", 0) = 1
314 * </pre>
315 *
316 * @param str the string to convert, may be null
317 * @param defaultValue the default value
318 * @return the byte represented by the string, or the default if conversion fails
319 * @since 2.5
320 */
321 public static byte toByte(String str, byte defaultValue) {
322 if(str == null) {
323 return defaultValue;
324 }
325 try {
326 return Byte.parseByte(str);
327 } catch (NumberFormatException nfe) {
328 return defaultValue;
329 }
330 }
331
332 /**
333 * <p>Convert a <code>String</code> to a <code>short</code>, returning
334 * <code>zero</code> if the conversion fails.</p>
335 *
336 * <p>If the string is <code>null</code>, <code>zero</code> is returned.</p>
337 *
338 * <pre>
339 * NumberUtils.toShort(null) = 0
340 * NumberUtils.toShort("") = 0
341 * NumberUtils.toShort("1") = 1
342 * </pre>
343 *
344 * @param str the string to convert, may be null
345 * @return the short represented by the string, or <code>zero</code> if
346 * conversion fails
347 * @since 2.5
348 */
349 public static short toShort(String str) {
350 return toShort(str, (short) 0);
351 }
352
353 /**
354 * <p>Convert a <code>String</code> to an <code>short</code>, returning a
355 * default value if the conversion fails.</p>
356 *
357 * <p>If the string is <code>null</code>, the default value is returned.</p>
358 *
359 * <pre>
360 * NumberUtils.toShort(null, 1) = 1
361 * NumberUtils.toShort("", 1) = 1
362 * NumberUtils.toShort("1", 0) = 1
363 * </pre>
364 *
365 * @param str the string to convert, may be null
366 * @param defaultValue the default value
367 * @return the short represented by the string, or the default if conversion fails
368 * @since 2.5
369 */
370 public static short toShort(String str, short defaultValue) {
371 if(str == null) {
372 return defaultValue;
373 }
374 try {
375 return Short.parseShort(str);
376 } catch (NumberFormatException nfe) {
377 return defaultValue;
378 }
379 }
380
381 //-----------------------------------------------------------------------
382 // must handle Long, Float, Integer, Float, Short,
383 // BigDecimal, BigInteger and Byte
384 // useful methods:
385 // Byte.decode(String)
386 // Byte.valueOf(String,int radix)
387 // Byte.valueOf(String)
388 // Double.valueOf(String)
389 // Float.valueOf(String)
390 // Float.valueOf(String)
391 // Integer.valueOf(String,int radix)
392 // Integer.valueOf(String)
393 // Integer.decode(String)
394 // Integer.getInteger(String)
395 // Integer.getInteger(String,int val)
396 // Integer.getInteger(String,Integer val)
397 // Integer.valueOf(String)
398 // Double.valueOf(String)
399 // new Byte(String)
400 // Long.valueOf(String)
401 // Long.getLong(String)
402 // Long.getLong(String,int)
403 // Long.getLong(String,Integer)
404 // Long.valueOf(String,int)
405 // Long.valueOf(String)
406 // Short.valueOf(String)
407 // Short.decode(String)
408 // Short.valueOf(String,int)
409 // Short.valueOf(String)
410 // new BigDecimal(String)
411 // new BigInteger(String)
412 // new BigInteger(String,int radix)
413 // Possible inputs:
414 // 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd
415 // plus minus everything. Prolly more. A lot are not separable.
416
417 /**
418 * <p>Turns a string value into a java.lang.Number.</p>
419 *
420 * <p>First, the value is examined for a type qualifier on the end
421 * (<code>'f','F','d','D','l','L'</code>). If it is found, it starts
422 * trying to create successively larger types from the type specified
423 * until one is found that can represent the value.</p>
424 *
425 * <p>If a type specifier is not found, it will check for a decimal point
426 * and then try successively larger types from <code>Integer</code> to
427 * <code>BigInteger</code> and from <code>Float</code> to
428 * <code>BigDecimal</code>.</p>
429 *
430 * <p>If the string starts with <code>0x</code> or <code>-0x</code>, it
431 * will be interpreted as a hexadecimal integer. Values with leading
432 * <code>0</code>'s will not be interpreted as octal.</p>
433 *
434 * <p>Returns <code>null</code> if the string is <code>null</code>.</p>
435 *
436 * <p>This method does not trim the input string, i.e., strings with leading
437 * or trailing spaces will generate NumberFormatExceptions.</p>
438 *
439 * @param str String containing a number, may be null
440 * @return Number created from the string
441 * @throws NumberFormatException if the value cannot be converted
442 */
443 public static Number createNumber(String str) throws NumberFormatException {
444 if (str == null) {
445 return null;
446 }
447 if (StringUtils.isBlank(str)) {
448 throw new NumberFormatException("A blank string is not a valid number");
449 }
450 if (str.startsWith("--")) {
451 // this is protection for poorness in java.lang.BigDecimal.
452 // it accepts this as a legal value, but it does not appear
453 // to be in specification of class. OS X Java parses it to
454 // a wrong value.
455 return null;
456 }
457 if (str.startsWith("0x") || str.startsWith("-0x")) {
458 return createInteger(str);
459 }
460 char lastChar = str.charAt(str.length() - 1);
461 String mant;
462 String dec;
463 String exp;
464 int decPos = str.indexOf('.');
465 int expPos = str.indexOf('e') + str.indexOf('E') + 1;
466
467 if (decPos > -1) {
468
469 if (expPos > -1) {
470 if (expPos < decPos || expPos > str.length()) {
471 throw new NumberFormatException(str + " is not a valid number.");
472 }
473 dec = str.substring(decPos + 1, expPos);
474 } else {
475 dec = str.substring(decPos + 1);
476 }
477 mant = str.substring(0, decPos);
478 } else {
479 if (expPos > -1) {
480 if (expPos > str.length()) {
481 throw new NumberFormatException(str + " is not a valid number.");
482 }
483 mant = str.substring(0, expPos);
484 } else {
485 mant = str;
486 }
487 dec = null;
488 }
489 if (!Character.isDigit(lastChar) && lastChar != '.') {
490 if (expPos > -1 && expPos < str.length() - 1) {
491 exp = str.substring(expPos + 1, str.length() - 1);
492 } else {
493 exp = null;
494 }
495 //Requesting a specific type..
496 String numeric = str.substring(0, str.length() - 1);
497 boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
498 switch (lastChar) {
499 case 'l' :
500 case 'L' :
501 if (dec == null
502 && exp == null
503 && (numeric.charAt(0) == '-' && isDigits(numeric.substring(1)) || isDigits(numeric))) {
504 try {
505 return createLong(numeric);
506 } catch (NumberFormatException nfe) { // NOPMD
507 // Too big for a long
508 }
509 return createBigInteger(numeric);
510
511 }
512 throw new NumberFormatException(str + " is not a valid number.");
513 case 'f' :
514 case 'F' :
515 try {
516 Float f = NumberUtils.createFloat(numeric);
517 if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
518 //If it's too big for a float or the float value = 0 and the string
519 //has non-zeros in it, then float does not have the precision we want
520 return f;
521 }
522
523 } catch (NumberFormatException nfe) { // NOPMD
524 // ignore the bad number
525 }
526 //$FALL-THROUGH$
527 case 'd' :
528 case 'D' :
529 try {
530 Double d = NumberUtils.createDouble(numeric);
531 if (!(d.isInfinite() || (d.floatValue() == 0.0D && !allZeros))) {
532 return d;
533 }
534 } catch (NumberFormatException nfe) { // NOPMD
535 // ignore the bad number
536 }
537 try {
538 return createBigDecimal(numeric);
539 } catch (NumberFormatException e) { // NOPMD
540 // ignore the bad number
541 }
542 //$FALL-THROUGH$
543 default :
544 throw new NumberFormatException(str + " is not a valid number.");
545
546 }
547 } else {
548 //User doesn't have a preference on the return type, so let's start
549 //small and go from there...
550 if (expPos > -1 && expPos < str.length() - 1) {
551 exp = str.substring(expPos + 1, str.length());
552 } else {
553 exp = null;
554 }
555 if (dec == null && exp == null) {
556 //Must be an int,long,bigint
557 try {
558 return createInteger(str);
559 } catch (NumberFormatException nfe) { // NOPMD
560 // ignore the bad number
561 }
562 try {
563 return createLong(str);
564 } catch (NumberFormatException nfe) { // NOPMD
565 // ignore the bad number
566 }
567 return createBigInteger(str);
568
569 } else {
570 //Must be a float,double,BigDec
571 boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
572 try {
573 Float f = createFloat(str);
574 if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
575 return f;
576 }
577 } catch (NumberFormatException nfe) { // NOPMD
578 // ignore the bad number
579 }
580 try {
581 Double d = createDouble(str);
582 if (!(d.isInfinite() || (d.doubleValue() == 0.0D && !allZeros))) {
583 return d;
584 }
585 } catch (NumberFormatException nfe) { // NOPMD
586 // ignore the bad number
587 }
588
589 return createBigDecimal(str);
590
591 }
592 }
593 }
594
595 /**
596 * <p>Utility method for {@link #createNumber(java.lang.String)}.</p>
597 *
598 * <p>Returns <code>true</code> if s is <code>null</code>.</p>
599 *
600 * @param str the String to check
601 * @return if it is all zeros or <code>null</code>
602 */
603 private static boolean isAllZeros(String str) {
604 if (str == null) {
605 return true;
606 }
607 for (int i = str.length() - 1; i >= 0; i--) {
608 if (str.charAt(i) != '0') {
609 return false;
610 }
611 }
612 return str.length() > 0;
613 }
614
615 //-----------------------------------------------------------------------
616 /**
617 * <p>Convert a <code>String</code> to a <code>Float</code>.</p>
618 *
619 * <p>Returns <code>null</code> if the string is <code>null</code>.</p>
620 *
621 * @param str a <code>String</code> to convert, may be null
622 * @return converted <code>Float</code>
623 * @throws NumberFormatException if the value cannot be converted
624 */
625 public static Float createFloat(String str) {
626 if (str == null) {
627 return null;
628 }
629 return Float.valueOf(str);
630 }
631
632 /**
633 * <p>Convert a <code>String</code> to a <code>Double</code>.</p>
634 *
635 * <p>Returns <code>null</code> if the string is <code>null</code>.</p>
636 *
637 * @param str a <code>String</code> to convert, may be null
638 * @return converted <code>Double</code>
639 * @throws NumberFormatException if the value cannot be converted
640 */
641 public static Double createDouble(String str) {
642 if (str == null) {
643 return null;
644 }
645 return Double.valueOf(str);
646 }
647
648 /**
649 * <p>Convert a <code>String</code> to a <code>Integer</code>, handling
650 * hex and octal notations.</p>
651 *
652 * <p>Returns <code>null</code> if the string is <code>null</code>.</p>
653 *
654 * @param str a <code>String</code> to convert, may be null
655 * @return converted <code>Integer</code>
656 * @throws NumberFormatException if the value cannot be converted
657 */
658 public static Integer createInteger(String str) {
659 if (str == null) {
660 return null;
661 }
662 // decode() handles 0xAABD and 0777 (hex and octal) as well.
663 return Integer.decode(str);
664 }
665
666 /**
667 * <p>Convert a <code>String</code> to a <code>Long</code>.</p>
668 *
669 * <p>Returns <code>null</code> if the string is <code>null</code>.</p>
670 *
671 * @param str a <code>String</code> to convert, may be null
672 * @return converted <code>Long</code>
673 * @throws NumberFormatException if the value cannot be converted
674 */
675 public static Long createLong(String str) {
676 if (str == null) {
677 return null;
678 }
679 return Long.valueOf(str);
680 }
681
682 /**
683 * <p>Convert a <code>String</code> to a <code>BigInteger</code>.</p>
684 *
685 * <p>Returns <code>null</code> if the string is <code>null</code>.</p>
686 *
687 * @param str a <code>String</code> to convert, may be null
688 * @return converted <code>BigInteger</code>
689 * @throws NumberFormatException if the value cannot be converted
690 */
691 public static BigInteger createBigInteger(String str) {
692 if (str == null) {
693 return null;
694 }
695 return new BigInteger(str);
696 }
697
698 /**
699 * <p>Convert a <code>String</code> to a <code>BigDecimal</code>.</p>
700 *
701 * <p>Returns <code>null</code> if the string is <code>null</code>.</p>
702 *
703 * @param str a <code>String</code> to convert, may be null
704 * @return converted <code>BigDecimal</code>
705 * @throws NumberFormatException if the value cannot be converted
706 */
707 public static BigDecimal createBigDecimal(String str) {
708 if (str == null) {
709 return null;
710 }
711 // handle JDK1.3.1 bug where "" throws IndexOutOfBoundsException
712 if (StringUtils.isBlank(str)) {
713 throw new NumberFormatException("A blank string is not a valid number");
714 }
715 return new BigDecimal(str);
716 }
717
718 // Min in array
719 //--------------------------------------------------------------------
720 /**
721 * <p>Returns the minimum value in an array.</p>
722 *
723 * @param array an array, must not be null or empty
724 * @return the minimum value in the array
725 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
726 * @throws IllegalArgumentException if <code>array</code> is empty
727 */
728 public static long min(long[] array) {
729 // Validates input
730 if (array == null) {
731 throw new IllegalArgumentException("The Array must not be null");
732 } else if (array.length == 0) {
733 throw new IllegalArgumentException("Array cannot be empty.");
734 }
735
736 // Finds and returns min
737 long min = array[0];
738 for (int i = 1; i < array.length; i++) {
739 if (array[i] < min) {
740 min = array[i];
741 }
742 }
743
744 return min;
745 }
746
747 /**
748 * <p>Returns the minimum value in an array.</p>
749 *
750 * @param array an array, must not be null or empty
751 * @return the minimum value in the array
752 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
753 * @throws IllegalArgumentException if <code>array</code> is empty
754 */
755 public static int min(int[] array) {
756 // Validates input
757 if (array == null) {
758 throw new IllegalArgumentException("The Array must not be null");
759 } else if (array.length == 0) {
760 throw new IllegalArgumentException("Array cannot be empty.");
761 }
762
763 // Finds and returns min
764 int min = array[0];
765 for (int j = 1; j < array.length; j++) {
766 if (array[j] < min) {
767 min = array[j];
768 }
769 }
770
771 return min;
772 }
773
774 /**
775 * <p>Returns the minimum value in an array.</p>
776 *
777 * @param array an array, must not be null or empty
778 * @return the minimum value in the array
779 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
780 * @throws IllegalArgumentException if <code>array</code> is empty
781 */
782 public static short min(short[] array) {
783 // Validates input
784 if (array == null) {
785 throw new IllegalArgumentException("The Array must not be null");
786 } else if (array.length == 0) {
787 throw new IllegalArgumentException("Array cannot be empty.");
788 }
789
790 // Finds and returns min
791 short min = array[0];
792 for (int i = 1; i < array.length; i++) {
793 if (array[i] < min) {
794 min = array[i];
795 }
796 }
797
798 return min;
799 }
800
801 /**
802 * <p>Returns the minimum value in an array.</p>
803 *
804 * @param array an array, must not be null or empty
805 * @return the minimum value in the array
806 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
807 * @throws IllegalArgumentException if <code>array</code> is empty
808 */
809 public static byte min(byte[] array) {
810 // Validates input
811 if (array == null) {
812 throw new IllegalArgumentException("The Array must not be null");
813 } else if (array.length == 0) {
814 throw new IllegalArgumentException("Array cannot be empty.");
815 }
816
817 // Finds and returns min
818 byte min = array[0];
819 for (int i = 1; i < array.length; i++) {
820 if (array[i] < min) {
821 min = array[i];
822 }
823 }
824
825 return min;
826 }
827
828 /**
829 * <p>Returns the minimum value in an array.</p>
830 *
831 * @param array an array, must not be null or empty
832 * @return the minimum value in the array
833 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
834 * @throws IllegalArgumentException if <code>array</code> is empty
835 * @see IEEE754rUtils#min(double[]) IEEE754rUtils for a version of this method that handles NaN differently
836 */
837 public static double min(double[] array) {
838 // Validates input
839 if (array == null) {
840 throw new IllegalArgumentException("The Array must not be null");
841 } else if (array.length == 0) {
842 throw new IllegalArgumentException("Array cannot be empty.");
843 }
844
845 // Finds and returns min
846 double min = array[0];
847 for (int i = 1; i < array.length; i++) {
848 if (Double.isNaN(array[i])) {
849 return Double.NaN;
850 }
851 if (array[i] < min) {
852 min = array[i];
853 }
854 }
855
856 return min;
857 }
858
859 /**
860 * <p>Returns the minimum value in an array.</p>
861 *
862 * @param array an array, must not be null or empty
863 * @return the minimum value in the array
864 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
865 * @throws IllegalArgumentException if <code>array</code> is empty
866 * @see IEEE754rUtils#min(float[]) IEEE754rUtils for a version of this method that handles NaN differently
867 */
868 public static float min(float[] array) {
869 // Validates input
870 if (array == null) {
871 throw new IllegalArgumentException("The Array must not be null");
872 } else if (array.length == 0) {
873 throw new IllegalArgumentException("Array cannot be empty.");
874 }
875
876 // Finds and returns min
877 float min = array[0];
878 for (int i = 1; i < array.length; i++) {
879 if (Float.isNaN(array[i])) {
880 return Float.NaN;
881 }
882 if (array[i] < min) {
883 min = array[i];
884 }
885 }
886
887 return min;
888 }
889
890 // Max in array
891 //--------------------------------------------------------------------
892 /**
893 * <p>Returns the maximum value in an array.</p>
894 *
895 * @param array an array, must not be null or empty
896 * @return the minimum value in the array
897 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
898 * @throws IllegalArgumentException if <code>array</code> is empty
899 */
900 public static long max(long[] array) {
901 // Validates input
902 if (array == null) {
903 throw new IllegalArgumentException("The Array must not be null");
904 } else if (array.length == 0) {
905 throw new IllegalArgumentException("Array cannot be empty.");
906 }
907
908 // Finds and returns max
909 long max = array[0];
910 for (int j = 1; j < array.length; j++) {
911 if (array[j] > max) {
912 max = array[j];
913 }
914 }
915
916 return max;
917 }
918
919 /**
920 * <p>Returns the maximum value in an array.</p>
921 *
922 * @param array an array, must not be null or empty
923 * @return the minimum value in the array
924 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
925 * @throws IllegalArgumentException if <code>array</code> is empty
926 */
927 public static int max(int[] array) {
928 // Validates input
929 if (array == null) {
930 throw new IllegalArgumentException("The Array must not be null");
931 } else if (array.length == 0) {
932 throw new IllegalArgumentException("Array cannot be empty.");
933 }
934
935 // Finds and returns max
936 int max = array[0];
937 for (int j = 1; j < array.length; j++) {
938 if (array[j] > max) {
939 max = array[j];
940 }
941 }
942
943 return max;
944 }
945
946 /**
947 * <p>Returns the maximum value in an array.</p>
948 *
949 * @param array an array, must not be null or empty
950 * @return the minimum value in the array
951 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
952 * @throws IllegalArgumentException if <code>array</code> is empty
953 */
954 public static short max(short[] array) {
955 // Validates input
956 if (array == null) {
957 throw new IllegalArgumentException("The Array must not be null");
958 } else if (array.length == 0) {
959 throw new IllegalArgumentException("Array cannot be empty.");
960 }
961
962 // Finds and returns max
963 short max = array[0];
964 for (int i = 1; i < array.length; i++) {
965 if (array[i] > max) {
966 max = array[i];
967 }
968 }
969
970 return max;
971 }
972
973 /**
974 * <p>Returns the maximum value in an array.</p>
975 *
976 * @param array an array, must not be null or empty
977 * @return the minimum value in the array
978 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
979 * @throws IllegalArgumentException if <code>array</code> is empty
980 */
981 public static byte max(byte[] array) {
982 // Validates input
983 if (array == null) {
984 throw new IllegalArgumentException("The Array must not be null");
985 } else if (array.length == 0) {
986 throw new IllegalArgumentException("Array cannot be empty.");
987 }
988
989 // Finds and returns max
990 byte max = array[0];
991 for (int i = 1; i < array.length; i++) {
992 if (array[i] > max) {
993 max = array[i];
994 }
995 }
996
997 return max;
998 }
999
1000 /**
1001 * <p>Returns the maximum value in an array.</p>
1002 *
1003 * @param array an array, must not be null or empty
1004 * @return the minimum value in the array
1005 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
1006 * @throws IllegalArgumentException if <code>array</code> is empty
1007 * @see IEEE754rUtils#max(double[]) IEEE754rUtils for a version of this method that handles NaN differently
1008 */
1009 public static double max(double[] array) {
1010 // Validates input
1011 if (array== null) {
1012 throw new IllegalArgumentException("The Array must not be null");
1013 } else if (array.length == 0) {
1014 throw new IllegalArgumentException("Array cannot be empty.");
1015 }
1016
1017 // Finds and returns max
1018 double max = array[0];
1019 for (int j = 1; j < array.length; j++) {
1020 if (Double.isNaN(array[j])) {
1021 return Double.NaN;
1022 }
1023 if (array[j] > max) {
1024 max = array[j];
1025 }
1026 }
1027
1028 return max;
1029 }
1030
1031 /**
1032 * <p>Returns the maximum value in an array.</p>
1033 *
1034 * @param array an array, must not be null or empty
1035 * @return the minimum value in the array
1036 * @throws IllegalArgumentException if <code>array</code> is <code>null</code>
1037 * @throws IllegalArgumentException if <code>array</code> is empty
1038 * @see IEEE754rUtils#max(float[]) IEEE754rUtils for a version of this method that handles NaN differently
1039 */
1040 public static float max(float[] array) {
1041 // Validates input
1042 if (array == null) {
1043 throw new IllegalArgumentException("The Array must not be null");
1044 } else if (array.length == 0) {
1045 throw new IllegalArgumentException("Array cannot be empty.");
1046 }
1047
1048 // Finds and returns max
1049 float max = array[0];
1050 for (int j = 1; j < array.length; j++) {
1051 if (Float.isNaN(array[j])) {
1052 return Float.NaN;
1053 }
1054 if (array[j] > max) {
1055 max = array[j];
1056 }
1057 }
1058
1059 return max;
1060 }
1061
1062 // 3 param min
1063 //-----------------------------------------------------------------------
1064 /**
1065 * <p>Gets the minimum of three <code>long</code> values.</p>
1066 *
1067 * @param a value 1
1068 * @param b value 2
1069 * @param c value 3
1070 * @return the smallest of the values
1071 */
1072 public static long min(long a, long b, long c) {
1073 if (b < a) {
1074 a = b;
1075 }
1076 if (c < a) {
1077 a = c;
1078 }
1079 return a;
1080 }
1081
1082 /**
1083 * <p>Gets the minimum of three <code>int</code> values.</p>
1084 *
1085 * @param a value 1
1086 * @param b value 2
1087 * @param c value 3
1088 * @return the smallest of the values
1089 */
1090 public static int min(int a, int b, int c) {
1091 if (b < a) {
1092 a = b;
1093 }
1094 if (c < a) {
1095 a = c;
1096 }
1097 return a;
1098 }
1099
1100 /**
1101 * <p>Gets the minimum of three <code>short</code> values.</p>
1102 *
1103 * @param a value 1
1104 * @param b value 2
1105 * @param c value 3
1106 * @return the smallest of the values
1107 */
1108 public static short min(short a, short b, short c) {
1109 if (b < a) {
1110 a = b;
1111 }
1112 if (c < a) {
1113 a = c;
1114 }
1115 return a;
1116 }
1117
1118 /**
1119 * <p>Gets the minimum of three <code>byte</code> values.</p>
1120 *
1121 * @param a value 1
1122 * @param b value 2
1123 * @param c value 3
1124 * @return the smallest of the values
1125 */
1126 public static byte min(byte a, byte b, byte c) {
1127 if (b < a) {
1128 a = b;
1129 }
1130 if (c < a) {
1131 a = c;
1132 }
1133 return a;
1134 }
1135
1136 /**
1137 * <p>Gets the minimum of three <code>double</code> values.</p>
1138 *
1139 * <p>If any value is <code>NaN</code>, <code>NaN</code> is
1140 * returned. Infinity is handled.</p>
1141 *
1142 * @param a value 1
1143 * @param b value 2
1144 * @param c value 3
1145 * @return the smallest of the values
1146 * @see IEEE754rUtils#min(double, double, double) for a version of this method that handles NaN differently
1147 */
1148 public static double min(double a, double b, double c) {
1149 return Math.min(Math.min(a, b), c);
1150 }
1151
1152 /**
1153 * <p>Gets the minimum of three <code>float</code> values.</p>
1154 *
1155 * <p>If any value is <code>NaN</code>, <code>NaN</code> is
1156 * returned. Infinity is handled.</p>
1157 *
1158 * @param a value 1
1159 * @param b value 2
1160 * @param c value 3
1161 * @return the smallest of the values
1162 * @see IEEE754rUtils#min(float, float, float) for a version of this method that handles NaN differently
1163 */
1164 public static float min(float a, float b, float c) {
1165 return Math.min(Math.min(a, b), c);
1166 }
1167
1168 // 3 param max
1169 //-----------------------------------------------------------------------
1170 /**
1171 * <p>Gets the maximum of three <code>long</code> values.</p>
1172 *
1173 * @param a value 1
1174 * @param b value 2
1175 * @param c value 3
1176 * @return the largest of the values
1177 */
1178 public static long max(long a, long b, long c) {
1179 if (b > a) {
1180 a = b;
1181 }
1182 if (c > a) {
1183 a = c;
1184 }
1185 return a;
1186 }
1187
1188 /**
1189 * <p>Gets the maximum of three <code>int</code> values.</p>
1190 *
1191 * @param a value 1
1192 * @param b value 2
1193 * @param c value 3
1194 * @return the largest of the values
1195 */
1196 public static int max(int a, int b, int c) {
1197 if (b > a) {
1198 a = b;
1199 }
1200 if (c > a) {
1201 a = c;
1202 }
1203 return a;
1204 }
1205
1206 /**
1207 * <p>Gets the maximum of three <code>short</code> values.</p>
1208 *
1209 * @param a value 1
1210 * @param b value 2
1211 * @param c value 3
1212 * @return the largest of the values
1213 */
1214 public static short max(short a, short b, short c) {
1215 if (b > a) {
1216 a = b;
1217 }
1218 if (c > a) {
1219 a = c;
1220 }
1221 return a;
1222 }
1223
1224 /**
1225 * <p>Gets the maximum of three <code>byte</code> values.</p>
1226 *
1227 * @param a value 1
1228 * @param b value 2
1229 * @param c value 3
1230 * @return the largest of the values
1231 */
1232 public static byte max(byte a, byte b, byte c) {
1233 if (b > a) {
1234 a = b;
1235 }
1236 if (c > a) {
1237 a = c;
1238 }
1239 return a;
1240 }
1241
1242 /**
1243 * <p>Gets the maximum of three <code>double</code> values.</p>
1244 *
1245 * <p>If any value is <code>NaN</code>, <code>NaN</code> is
1246 * returned. Infinity is handled.</p>
1247 *
1248 * @param a value 1
1249 * @param b value 2
1250 * @param c value 3
1251 * @return the largest of the values
1252 * @see IEEE754rUtils#max(double, double, double) for a version of this method that handles NaN differently
1253 */
1254 public static double max(double a, double b, double c) {
1255 return Math.max(Math.max(a, b), c);
1256 }
1257
1258 /**
1259 * <p>Gets the maximum of three <code>float</code> values.</p>
1260 *
1261 * <p>If any value is <code>NaN</code>, <code>NaN</code> is
1262 * returned. Infinity is handled.</p>
1263 *
1264 * @param a value 1
1265 * @param b value 2
1266 * @param c value 3
1267 * @return the largest of the values
1268 * @see IEEE754rUtils#max(float, float, float) for a version of this method that handles NaN differently
1269 */
1270 public static float max(float a, float b, float c) {
1271 return Math.max(Math.max(a, b), c);
1272 }
1273
1274 //-----------------------------------------------------------------------
1275 /**
1276 * <p>Checks whether the <code>String</code> contains only
1277 * digit characters.</p>
1278 *
1279 * <p><code>Null</code> and empty String will return
1280 * <code>false</code>.</p>
1281 *
1282 * @param str the <code>String</code> to check
1283 * @return <code>true</code> if str contains only Unicode numeric
1284 */
1285 public static boolean isDigits(String str) {
1286 if (StringUtils.isEmpty(str)) {
1287 return false;
1288 }
1289 for (int i = 0; i < str.length(); i++) {
1290 if (!Character.isDigit(str.charAt(i))) {
1291 return false;
1292 }
1293 }
1294 return true;
1295 }
1296
1297 /**
1298 * <p>Checks whether the String a valid Java number.</p>
1299 *
1300 * <p>Valid numbers include hexadecimal marked with the <code>0x</code>
1301 * qualifier, scientific notation and numbers marked with a type
1302 * qualifier (e.g. 123L).</p>
1303 *
1304 * <p><code>Null</code> and empty String will return
1305 * <code>false</code>.</p>
1306 *
1307 * @param str the <code>String</code> to check
1308 * @return <code>true</code> if the string is a correctly formatted number
1309 */
1310 public static boolean isNumber(String str) {
1311 if (StringUtils.isEmpty(str)) {
1312 return false;
1313 }
1314 char[] chars = str.toCharArray();
1315 int sz = chars.length;
1316 boolean hasExp = false;
1317 boolean hasDecPoint = false;
1318 boolean allowSigns = false;
1319 boolean foundDigit = false;
1320 // deal with any possible sign up front
1321 int start = (chars[0] == '-') ? 1 : 0;
1322 if (sz > start + 1 && chars[start] == '0' && chars[start + 1] == 'x') {
1323 int i = start + 2;
1324 if (i == sz) {
1325 return false; // str == "0x"
1326 }
1327 // checking hex (it can't be anything else)
1328 for (; i < chars.length; i++) {
1329 if ((chars[i] < '0' || chars[i] > '9')
1330 && (chars[i] < 'a' || chars[i] > 'f')
1331 && (chars[i] < 'A' || chars[i] > 'F')) {
1332 return false;
1333 }
1334 }
1335 return true;
1336 }
1337 sz--; // don't want to loop to the last char, check it afterwords
1338 // for type qualifiers
1339 int i = start;
1340 // loop to the next to last char or to the last char if we need another digit to
1341 // make a valid number (e.g. chars[0..5] = "1234E")
1342 while (i < sz || (i < sz + 1 && allowSigns && !foundDigit)) {
1343 if (chars[i] >= '0' && chars[i] <= '9') {
1344 foundDigit = true;
1345 allowSigns = false;
1346
1347 } else if (chars[i] == '.') {
1348 if (hasDecPoint || hasExp) {
1349 // two decimal points or dec in exponent
1350 return false;
1351 }
1352 hasDecPoint = true;
1353 } else if (chars[i] == 'e' || chars[i] == 'E') {
1354 // we've already taken care of hex.
1355 if (hasExp) {
1356 // two E's
1357 return false;
1358 }
1359 if (!foundDigit) {
1360 return false;
1361 }
1362 hasExp = true;
1363 allowSigns = true;
1364 } else if (chars[i] == '+' || chars[i] == '-') {
1365 if (!allowSigns) {
1366 return false;
1367 }
1368 allowSigns = false;
1369 foundDigit = false; // we need a digit after the E
1370 } else {
1371 return false;
1372 }
1373 i++;
1374 }
1375 if (i < chars.length) {
1376 if (chars[i] >= '0' && chars[i] <= '9') {
1377 // no type qualifier, OK
1378 return true;
1379 }
1380 if (chars[i] == 'e' || chars[i] == 'E') {
1381 // can't have an E at the last byte
1382 return false;
1383 }
1384 if (chars[i] == '.') {
1385 if (hasDecPoint || hasExp) {
1386 // two decimal points or dec in exponent
1387 return false;
1388 }
1389 // single trailing decimal point after non-exponent is ok
1390 return foundDigit;
1391 }
1392 if (!allowSigns
1393 && (chars[i] == 'd'
1394 || chars[i] == 'D'
1395 || chars[i] == 'f'
1396 || chars[i] == 'F')) {
1397 return foundDigit;
1398 }
1399 if (chars[i] == 'l'
1400 || chars[i] == 'L') {
1401 // not allowing L with an exponent or decimal point
1402 return foundDigit && !hasExp && !hasDecPoint;
1403 }
1404 // last character is illegal
1405 return false;
1406 }
1407 // allowSigns is true iff the val ends in 'E'
1408 // found digit it to make sure weird stuff like '.' and '1E-' doesn't pass
1409 return !allowSigns && foundDigit;
1410 }
1411
1412 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 Extends {@link java.math} for business mathematical classes. This package is intended for business
19 mathematical use, not scientific use. See <a href="http://commons.apache.org/math/">Commons Math</a>
20 for a more complete set of mathematical classes.
21 @since 2.0
22 <p>These classes are immutable, and therefore thread-safe.</p>
23 </body>
24 </html>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.mutable;
18
19 /**
20 * Provides mutable access to a value.
21 * <p>
22 * <code>Mutable</code> is used as a generic interface to the implementations in this package.
23 * <p>
24 * A typical use case would be to enable a primitive or string to be passed to a method and allow that method to
25 * effectively change the value of the primitive/string. Another use case is to store a frequently changing primitive in
26 * a collection (for example a total in a map) without needing to create new Integer/Long wrapper objects.
27 *
28 * @since 2.1
29 * @param <T> the type to set and get
30 * @version $Id: Mutable.java 1153213 2011-08-02 17:35:39Z ggregory $
31 */
32 public interface Mutable<T> {
33
34 /**
35 * Gets the value of this mutable.
36 *
37 * @return the stored value
38 */
39 T getValue();
40
41 /**
42 * Sets the value of this mutable.
43 *
44 * @param value
45 * the value to store
46 * @throws NullPointerException
47 * if the object is null and null is invalid
48 * @throws ClassCastException
49 * if the type is invalid
50 */
51 void setValue(T value);
52
53 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.mutable;
18
19 import java.io.Serializable;
20
21 /**
22 * A mutable <code>boolean</code> wrapper.
23 *
24 * @see Boolean
25 * @since 2.2
26 * @version $Id: MutableBoolean.java 1088899 2011-04-05 05:31:27Z bayard $
27 */
28 public class MutableBoolean implements Mutable<Boolean>, Serializable, Comparable<MutableBoolean> {
29
30 /**
31 * Required for serialization support.
32 *
33 * @see java.io.Serializable
34 */
35 private static final long serialVersionUID = -4830728138360036487L;
36
37 /** The mutable value. */
38 private boolean value;
39
40 /**
41 * Constructs a new MutableBoolean with the default value of false.
42 */
43 public MutableBoolean() {
44 super();
45 }
46
47 /**
48 * Constructs a new MutableBoolean with the specified value.
49 *
50 * @param value the initial value to store
51 */
52 public MutableBoolean(boolean value) {
53 super();
54 this.value = value;
55 }
56
57 /**
58 * Constructs a new MutableBoolean with the specified value.
59 *
60 * @param value the initial value to store, not null
61 * @throws NullPointerException if the object is null
62 */
63 public MutableBoolean(Boolean value) {
64 super();
65 this.value = value.booleanValue();
66 }
67
68 //-----------------------------------------------------------------------
69 /**
70 * Gets the value as a Boolean instance.
71 *
72 * @return the value as a Boolean, never null
73 */
74 public Boolean getValue() {
75 return Boolean.valueOf(this.value);
76 }
77
78 /**
79 * Sets the value.
80 *
81 * @param value the value to set
82 */
83 public void setValue(boolean value) {
84 this.value = value;
85 }
86
87 /**
88 * Sets the value from any Boolean instance.
89 *
90 * @param value the value to set, not null
91 * @throws NullPointerException if the object is null
92 */
93 public void setValue(Boolean value) {
94 this.value = value.booleanValue();
95 }
96
97 //-----------------------------------------------------------------------
98 /**
99 * Checks if the current value is <code>true</code>.
100 *
101 * @return <code>true</code> if the current value is <code>true</code>
102 * @since 2.5
103 */
104 public boolean isTrue() {
105 return value == true;
106 }
107
108 /**
109 * Checks if the current value is <code>false</code>.
110 *
111 * @return <code>true</code> if the current value is <code>false</code>
112 * @since 2.5
113 */
114 public boolean isFalse() {
115 return value == false;
116 }
117
118 //-----------------------------------------------------------------------
119 /**
120 * Returns the value of this MutableBoolean as a boolean.
121 *
122 * @return the boolean value represented by this object.
123 */
124 public boolean booleanValue() {
125 return value;
126 }
127
128 //-----------------------------------------------------------------------
129 /**
130 * Gets this mutable as an instance of Boolean.
131 *
132 * @return a Boolean instance containing the value from this mutable, never null
133 * @since 2.5
134 */
135 public Boolean toBoolean() {
136 return Boolean.valueOf(booleanValue());
137 }
138
139 //-----------------------------------------------------------------------
140 /**
141 * Compares this object to the specified object. The result is <code>true</code> if and only if the argument is
142 * not <code>null</code> and is an <code>MutableBoolean</code> object that contains the same
143 * <code>boolean</code> value as this object.
144 *
145 * @param obj the object to compare with, null returns false
146 * @return <code>true</code> if the objects are the same; <code>false</code> otherwise.
147 */
148 @Override
149 public boolean equals(Object obj) {
150 if (obj instanceof MutableBoolean) {
151 return value == ((MutableBoolean) obj).booleanValue();
152 }
153 return false;
154 }
155
156 /**
157 * Returns a suitable hash code for this mutable.
158 *
159 * @return the hash code returned by <code>Boolean.TRUE</code> or <code>Boolean.FALSE</code>
160 */
161 @Override
162 public int hashCode() {
163 return value ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode();
164 }
165
166 //-----------------------------------------------------------------------
167 /**
168 * Compares this mutable to another in ascending order.
169 *
170 * @param other the other mutable to compare to, not null
171 * @return negative if this is less, zero if equal, positive if greater
172 * where false is less than true
173 */
174 public int compareTo(MutableBoolean other) {
175 boolean anotherVal = other.value;
176 return value == anotherVal ? 0 : (value ? 1 : -1);
177 }
178
179 //-----------------------------------------------------------------------
180 /**
181 * Returns the String value of this mutable.
182 *
183 * @return the mutable value as a string
184 */
185 @Override
186 public String toString() {
187 return String.valueOf(value);
188 }
189
190 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 /**
19 * A mutable <code>byte</code> wrapper.
20 *
21 * @see Byte
22 * @since 2.1
23 * @version $Id: MutableByte.java 1088899 2011-04-05 05:31:27Z bayard $
24 */
25 public class MutableByte extends Number implements Comparable<MutableByte>, Mutable<Number> {
26
27 /**
28 * Required for serialization support.
29 *
30 * @see java.io.Serializable
31 */
32 private static final long serialVersionUID = -1585823265L;
33
34 /** The mutable value. */
35 private byte value;
36
37 /**
38 * Constructs a new MutableByte with the default value of zero.
39 */
40 public MutableByte() {
41 super();
42 }
43
44 /**
45 * Constructs a new MutableByte with the specified value.
46 *
47 * @param value the initial value to store
48 */
49 public MutableByte(byte value) {
50 super();
51 this.value = value;
52 }
53
54 /**
55 * Constructs a new MutableByte with the specified value.
56 *
57 * @param value the initial value to store, not null
58 * @throws NullPointerException if the object is null
59 */
60 public MutableByte(Number value) {
61 super();
62 this.value = value.byteValue();
63 }
64
65 /**
66 * Constructs a new MutableByte parsing the given string.
67 *
68 * @param value the string to parse, not null
69 * @throws NumberFormatException if the string cannot be parsed into a byte
70 * @since 2.5
71 */
72 public MutableByte(String value) throws NumberFormatException {
73 super();
74 this.value = Byte.parseByte(value);
75 }
76
77 //-----------------------------------------------------------------------
78 /**
79 * Gets the value as a Byte instance.
80 *
81 * @return the value as a Byte, never null
82 */
83 public Byte getValue() {
84 return Byte.valueOf(this.value);
85 }
86
87 /**
88 * Sets the value.
89 *
90 * @param value the value to set
91 */
92 public void setValue(byte value) {
93 this.value = value;
94 }
95
96 /**
97 * Sets the value from any Number instance.
98 *
99 * @param value the value to set, not null
100 * @throws NullPointerException if the object is null
101 */
102 public void setValue(Number value) {
103 this.value = value.byteValue();
104 }
105
106 //-----------------------------------------------------------------------
107 /**
108 * Increments the value.
109 *
110 * @since Commons Lang 2.2
111 */
112 public void increment() {
113 value++;
114 }
115
116 /**
117 * Decrements the value.
118 *
119 * @since Commons Lang 2.2
120 */
121 public void decrement() {
122 value--;
123 }
124
125 //-----------------------------------------------------------------------
126 /**
127 * Adds a value to the value of this instance.
128 *
129 * @param operand the value to add, not null
130 * @since Commons Lang 2.2
131 */
132 public void add(byte operand) {
133 this.value += operand;
134 }
135
136 /**
137 * Adds a value to the value of this instance.
138 *
139 * @param operand the value to add, not null
140 * @throws NullPointerException if the object is null
141 * @since Commons Lang 2.2
142 */
143 public void add(Number operand) {
144 this.value += operand.byteValue();
145 }
146
147 /**
148 * Subtracts a value from the value of this instance.
149 *
150 * @param operand the value to subtract, not null
151 * @since Commons Lang 2.2
152 */
153 public void subtract(byte operand) {
154 this.value -= operand;
155 }
156
157 /**
158 * Subtracts a value from the value of this instance.
159 *
160 * @param operand the value to subtract, not null
161 * @throws NullPointerException if the object is null
162 * @since Commons Lang 2.2
163 */
164 public void subtract(Number operand) {
165 this.value -= operand.byteValue();
166 }
167
168 //-----------------------------------------------------------------------
169 // shortValue relies on Number implementation
170 /**
171 * Returns the value of this MutableByte as a byte.
172 *
173 * @return the numeric value represented by this object after conversion to type byte.
174 */
175 @Override
176 public byte byteValue() {
177 return value;
178 }
179
180 /**
181 * Returns the value of this MutableByte as an int.
182 *
183 * @return the numeric value represented by this object after conversion to type int.
184 */
185 @Override
186 public int intValue() {
187 return value;
188 }
189
190 /**
191 * Returns the value of this MutableByte as a long.
192 *
193 * @return the numeric value represented by this object after conversion to type long.
194 */
195 @Override
196 public long longValue() {
197 return value;
198 }
199
200 /**
201 * Returns the value of this MutableByte as a float.
202 *
203 * @return the numeric value represented by this object after conversion to type float.
204 */
205 @Override
206 public float floatValue() {
207 return value;
208 }
209
210 /**
211 * Returns the value of this MutableByte as a double.
212 *
213 * @return the numeric value represented by this object after conversion to type double.
214 */
215 @Override
216 public double doubleValue() {
217 return value;
218 }
219
220 //-----------------------------------------------------------------------
221 /**
222 * Gets this mutable as an instance of Byte.
223 *
224 * @return a Byte instance containing the value from this mutable
225 */
226 public Byte toByte() {
227 return Byte.valueOf(byteValue());
228 }
229
230 //-----------------------------------------------------------------------
231 /**
232 * Compares this object to the specified object. The result is <code>true</code> if and only if the argument is
233 * not <code>null</code> and is a <code>MutableByte</code> object that contains the same <code>byte</code> value
234 * as this object.
235 *
236 * @param obj the object to compare with, null returns false
237 * @return <code>true</code> if the objects are the same; <code>false</code> otherwise.
238 */
239 @Override
240 public boolean equals(Object obj) {
241 if (obj instanceof MutableByte) {
242 return value == ((MutableByte) obj).byteValue();
243 }
244 return false;
245 }
246
247 /**
248 * Returns a suitable hash code for this mutable.
249 *
250 * @return a suitable hash code
251 */
252 @Override
253 public int hashCode() {
254 return value;
255 }
256
257 //-----------------------------------------------------------------------
258 /**
259 * Compares this mutable to another in ascending order.
260 *
261 * @param other the other mutable to compare to, not null
262 * @return negative if this is less, zero if equal, positive if greater
263 */
264 public int compareTo(MutableByte other) {
265 byte anotherVal = other.value;
266 return value < anotherVal ? -1 : (value == anotherVal ? 0 : 1);
267 }
268
269 //-----------------------------------------------------------------------
270 /**
271 * Returns the String value of this mutable.
272 *
273 * @return the mutable value as a string
274 */
275 @Override
276 public String toString() {
277 return String.valueOf(value);
278 }
279
280 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 /**
19 * A mutable <code>double</code> wrapper.
20 *
21 * @see Double
22 * @since 2.1
23 * @version $Id: MutableDouble.java 1153490 2011-08-03 13:53:35Z ggregory $
24 */
25 public class MutableDouble extends Number implements Comparable<MutableDouble>, Mutable<Number> {
26
27 /**
28 * Required for serialization support.
29 *
30 * @see java.io.Serializable
31 */
32 private static final long serialVersionUID = 1587163916L;
33
34 /** The mutable value. */
35 private double value;
36
37 /**
38 * Constructs a new MutableDouble with the default value of zero.
39 */
40 public MutableDouble() {
41 super();
42 }
43
44 /**
45 * Constructs a new MutableDouble with the specified value.
46 *
47 * @param value the initial value to store
48 */
49 public MutableDouble(double value) {
50 super();
51 this.value = value;
52 }
53
54 /**
55 * Constructs a new MutableDouble with the specified value.
56 *
57 * @param value the initial value to store, not null
58 * @throws NullPointerException if the object is null
59 */
60 public MutableDouble(Number value) {
61 super();
62 this.value = value.doubleValue();
63 }
64
65 /**
66 * Constructs a new MutableDouble parsing the given string.
67 *
68 * @param value the string to parse, not null
69 * @throws NumberFormatException if the string cannot be parsed into a double
70 * @since 2.5
71 */
72 public MutableDouble(String value) throws NumberFormatException {
73 super();
74 this.value = Double.parseDouble(value);
75 }
76
77 //-----------------------------------------------------------------------
78 /**
79 * Gets the value as a Double instance.
80 *
81 * @return the value as a Double, never null
82 */
83 public Double getValue() {
84 return Double.valueOf(this.value);
85 }
86
87 /**
88 * Sets the value.
89 *
90 * @param value the value to set
91 */
92 public void setValue(double value) {
93 this.value = value;
94 }
95
96 /**
97 * Sets the value from any Number instance.
98 *
99 * @param value the value to set, not null
100 * @throws NullPointerException if the object is null
101 */
102 public void setValue(Number value) {
103 this.value = value.doubleValue();
104 }
105
106 //-----------------------------------------------------------------------
107 /**
108 * Checks whether the double value is the special NaN value.
109 *
110 * @return true if NaN
111 */
112 public boolean isNaN() {
113 return Double.isNaN(value);
114 }
115
116 /**
117 * Checks whether the double value is infinite.
118 *
119 * @return true if infinite
120 */
121 public boolean isInfinite() {
122 return Double.isInfinite(value);
123 }
124
125 //-----------------------------------------------------------------------
126 /**
127 * Increments the value.
128 *
129 * @since Commons Lang 2.2
130 */
131 public void increment() {
132 value++;
133 }
134
135 /**
136 * Decrements the value.
137 *
138 * @since Commons Lang 2.2
139 */
140 public void decrement() {
141 value--;
142 }
143
144 //-----------------------------------------------------------------------
145 /**
146 * Adds a value to the value of this instance.
147 *
148 * @param operand the value to add
149 * @since Commons Lang 2.2
150 */
151 public void add(double operand) {
152 this.value += operand;
153 }
154
155 /**
156 * Adds a value to the value of this instance.
157 *
158 * @param operand the value to add, not null
159 * @throws NullPointerException if the object is null
160 * @since Commons Lang 2.2
161 */
162 public void add(Number operand) {
163 this.value += operand.doubleValue();
164 }
165
166 /**
167 * Subtracts a value from the value of this instance.
168 *
169 * @param operand the value to subtract, not null
170 * @since Commons Lang 2.2
171 */
172 public void subtract(double operand) {
173 this.value -= operand;
174 }
175
176 /**
177 * Subtracts a value from the value of this instance.
178 *
179 * @param operand the value to subtract, not null
180 * @throws NullPointerException if the object is null
181 * @since Commons Lang 2.2
182 */
183 public void subtract(Number operand) {
184 this.value -= operand.doubleValue();
185 }
186
187 //-----------------------------------------------------------------------
188 // shortValue and byteValue rely on Number implementation
189 /**
190 * Returns the value of this MutableDouble as an int.
191 *
192 * @return the numeric value represented by this object after conversion to type int.
193 */
194 @Override
195 public int intValue() {
196 return (int) value;
197 }
198
199 /**
200 * Returns the value of this MutableDouble as a long.
201 *
202 * @return the numeric value represented by this object after conversion to type long.
203 */
204 @Override
205 public long longValue() {
206 return (long) value;
207 }
208
209 /**
210 * Returns the value of this MutableDouble as a float.
211 *
212 * @return the numeric value represented by this object after conversion to type float.
213 */
214 @Override
215 public float floatValue() {
216 return (float) value;
217 }
218
219 /**
220 * Returns the value of this MutableDouble as a double.
221 *
222 * @return the numeric value represented by this object after conversion to type double.
223 */
224 @Override
225 public double doubleValue() {
226 return value;
227 }
228
229 //-----------------------------------------------------------------------
230 /**
231 * Gets this mutable as an instance of Double.
232 *
233 * @return a Double instance containing the value from this mutable, never null
234 */
235 public Double toDouble() {
236 return Double.valueOf(doubleValue());
237 }
238
239 //-----------------------------------------------------------------------
240 /**
241 * Compares this object against the specified object. The result is <code>true</code> if and only if the argument
242 * is not <code>null</code> and is a <code>Double</code> object that represents a double that has the identical
243 * bit pattern to the bit pattern of the double represented by this object. For this purpose, two
244 * <code>double</code> values are considered to be the same if and only if the method
245 * {@link Double#doubleToLongBits(double)}returns the same long value when applied to each.
246 * <p>
247 * Note that in most cases, for two instances of class <code>Double</code>,<code>d1</code> and <code>d2</code>,
248 * the value of <code>d1.equals(d2)</code> is <code>true</code> if and only if <blockquote>
249 *
250 * <pre>
251 * d1.doubleValue()&nbsp;== d2.doubleValue()
252 * </pre>
253 *
254 * </blockquote>
255 * <p>
256 * also has the value <code>true</code>. However, there are two exceptions:
257 * <ul>
258 * <li>If <code>d1</code> and <code>d2</code> both represent <code>Double.NaN</code>, then the
259 * <code>equals</code> method returns <code>true</code>, even though <code>Double.NaN==Double.NaN</code> has
260 * the value <code>false</code>.
261 * <li>If <code>d1</code> represents <code>+0.0</code> while <code>d2</code> represents <code>-0.0</code>,
262 * or vice versa, the <code>equal</code> test has the value <code>false</code>, even though
263 * <code>+0.0==-0.0</code> has the value <code>true</code>. This allows hashtables to operate properly.
264 * </ul>
265 *
266 * @param obj the object to compare with, null returns false
267 * @return <code>true</code> if the objects are the same; <code>false</code> otherwise.
268 */
269 @Override
270 public boolean equals(Object obj) {
271 return (obj instanceof MutableDouble)
272 && (Double.doubleToLongBits(((MutableDouble) obj).value) == Double.doubleToLongBits(value));
273 }
274
275 /**
276 * Returns a suitable hash code for this mutable.
277 *
278 * @return a suitable hash code
279 */
280 @Override
281 public int hashCode() {
282 long bits = Double.doubleToLongBits(value);
283 return (int) (bits ^ (bits >>> 32));
284 }
285
286 //-----------------------------------------------------------------------
287 /**
288 * Compares this mutable to another in ascending order.
289 *
290 * @param other the other mutable to compare to, not null
291 * @return negative if this is less, zero if equal, positive if greater
292 */
293 public int compareTo(MutableDouble other) {
294 double anotherVal = other.value;
295 return Double.compare(value, anotherVal);
296 }
297
298 //-----------------------------------------------------------------------
299 /**
300 * Returns the String value of this mutable.
301 *
302 * @return the mutable value as a string
303 */
304 @Override
305 public String toString() {
306 return String.valueOf(value);
307 }
308
309 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 /**
19 * A mutable <code>float</code> wrapper.
20 *
21 * @see Float
22 * @since 2.1
23 * @version $Id: MutableFloat.java 1153490 2011-08-03 13:53:35Z ggregory $
24 */
25 public class MutableFloat extends Number implements Comparable<MutableFloat>, Mutable<Number> {
26
27 /**
28 * Required for serialization support.
29 *
30 * @see java.io.Serializable
31 */
32 private static final long serialVersionUID = 5787169186L;
33
34 /** The mutable value. */
35 private float value;
36
37 /**
38 * Constructs a new MutableFloat with the default value of zero.
39 */
40 public MutableFloat() {
41 super();
42 }
43
44 /**
45 * Constructs a new MutableFloat with the specified value.
46 *
47 * @param value the initial value to store
48 */
49 public MutableFloat(float value) {
50 super();
51 this.value = value;
52 }
53
54 /**
55 * Constructs a new MutableFloat with the specified value.
56 *
57 * @param value the initial value to store, not null
58 * @throws NullPointerException if the object is null
59 */
60 public MutableFloat(Number value) {
61 super();
62 this.value = value.floatValue();
63 }
64
65 /**
66 * Constructs a new MutableFloat parsing the given string.
67 *
68 * @param value the string to parse, not null
69 * @throws NumberFormatException if the string cannot be parsed into a float
70 * @since 2.5
71 */
72 public MutableFloat(String value) throws NumberFormatException {
73 super();
74 this.value = Float.parseFloat(value);
75 }
76
77 //-----------------------------------------------------------------------
78 /**
79 * Gets the value as a Float instance.
80 *
81 * @return the value as a Float, never null
82 */
83 public Float getValue() {
84 return Float.valueOf(this.value);
85 }
86
87 /**
88 * Sets the value.
89 *
90 * @param value the value to set
91 */
92 public void setValue(float value) {
93 this.value = value;
94 }
95
96 /**
97 * Sets the value from any Number instance.
98 *
99 * @param value the value to set, not null
100 * @throws NullPointerException if the object is null
101 */
102 public void setValue(Number value) {
103 this.value = value.floatValue();
104 }
105
106 //-----------------------------------------------------------------------
107 /**
108 * Checks whether the float value is the special NaN value.
109 *
110 * @return true if NaN
111 */
112 public boolean isNaN() {
113 return Float.isNaN(value);
114 }
115
116 /**
117 * Checks whether the float value is infinite.
118 *
119 * @return true if infinite
120 */
121 public boolean isInfinite() {
122 return Float.isInfinite(value);
123 }
124
125 //-----------------------------------------------------------------------
126 /**
127 * Increments the value.
128 *
129 * @since Commons Lang 2.2
130 */
131 public void increment() {
132 value++;
133 }
134
135 /**
136 * Decrements the value.
137 *
138 * @since Commons Lang 2.2
139 */
140 public void decrement() {
141 value--;
142 }
143
144 //-----------------------------------------------------------------------
145 /**
146 * Adds a value to the value of this instance.
147 *
148 * @param operand the value to add, not null
149 * @since Commons Lang 2.2
150 */
151 public void add(float operand) {
152 this.value += operand;
153 }
154
155 /**
156 * Adds a value to the value of this instance.
157 *
158 * @param operand the value to add, not null
159 * @throws NullPointerException if the object is null
160 * @since Commons Lang 2.2
161 */
162 public void add(Number operand) {
163 this.value += operand.floatValue();
164 }
165
166 /**
167 * Subtracts a value from the value of this instance.
168 *
169 * @param operand the value to subtract
170 * @since Commons Lang 2.2
171 */
172 public void subtract(float operand) {
173 this.value -= operand;
174 }
175
176 /**
177 * Subtracts a value from the value of this instance.
178 *
179 * @param operand the value to subtract, not null
180 * @throws NullPointerException if the object is null
181 * @since Commons Lang 2.2
182 */
183 public void subtract(Number operand) {
184 this.value -= operand.floatValue();
185 }
186
187 //-----------------------------------------------------------------------
188 // shortValue and byteValue rely on Number implementation
189 /**
190 * Returns the value of this MutableFloat as an int.
191 *
192 * @return the numeric value represented by this object after conversion to type int.
193 */
194 @Override
195 public int intValue() {
196 return (int) value;
197 }
198
199 /**
200 * Returns the value of this MutableFloat as a long.
201 *
202 * @return the numeric value represented by this object after conversion to type long.
203 */
204 @Override
205 public long longValue() {
206 return (long) value;
207 }
208
209 /**
210 * Returns the value of this MutableFloat as a float.
211 *
212 * @return the numeric value represented by this object after conversion to type float.
213 */
214 @Override
215 public float floatValue() {
216 return value;
217 }
218
219 /**
220 * Returns the value of this MutableFloat as a double.
221 *
222 * @return the numeric value represented by this object after conversion to type double.
223 */
224 @Override
225 public double doubleValue() {
226 return value;
227 }
228
229 //-----------------------------------------------------------------------
230 /**
231 * Gets this mutable as an instance of Float.
232 *
233 * @return a Float instance containing the value from this mutable, never null
234 */
235 public Float toFloat() {
236 return Float.valueOf(floatValue());
237 }
238
239 //-----------------------------------------------------------------------
240 /**
241 * Compares this object against some other object. The result is <code>true</code> if and only if the argument is
242 * not <code>null</code> and is a <code>Float</code> object that represents a <code>float</code> that has the
243 * identical bit pattern to the bit pattern of the <code>float</code> represented by this object. For this
244 * purpose, two float values are considered to be the same if and only if the method
245 * {@link Float#floatToIntBits(float)}returns the same int value when applied to each.
246 * <p>
247 * Note that in most cases, for two instances of class <code>Float</code>,<code>f1</code> and <code>f2</code>,
248 * the value of <code>f1.equals(f2)</code> is <code>true</code> if and only if <blockquote>
249 *
250 * <pre>
251 * f1.floatValue() == f2.floatValue()
252 * </pre>
253 *
254 * </blockquote>
255 * <p>
256 * also has the value <code>true</code>. However, there are two exceptions:
257 * <ul>
258 * <li>If <code>f1</code> and <code>f2</code> both represent <code>Float.NaN</code>, then the
259 * <code>equals</code> method returns <code>true</code>, even though <code>Float.NaN==Float.NaN</code> has
260 * the value <code>false</code>.
261 * <li>If <code>f1</code> represents <code>+0.0f</code> while <code>f2</code> represents <code>-0.0f</code>,
262 * or vice versa, the <code>equal</code> test has the value <code>false</code>, even though
263 * <code>0.0f==-0.0f</code> has the value <code>true</code>.
264 * </ul>
265 * This definition allows hashtables to operate properly.
266 *
267 * @param obj the object to compare with, null returns false
268 * @return <code>true</code> if the objects are the same; <code>false</code> otherwise.
269 * @see java.lang.Float#floatToIntBits(float)
270 */
271 @Override
272 public boolean equals(Object obj) {
273 return (obj instanceof MutableFloat)
274 && (Float.floatToIntBits(((MutableFloat) obj).value) == Float.floatToIntBits(value));
275 }
276
277 /**
278 * Returns a suitable hash code for this mutable.
279 *
280 * @return a suitable hash code
281 */
282 @Override
283 public int hashCode() {
284 return Float.floatToIntBits(value);
285 }
286
287 //-----------------------------------------------------------------------
288 /**
289 * Compares this mutable to another in ascending order.
290 *
291 * @param other the other mutable to compare to, not null
292 * @return negative if this is less, zero if equal, positive if greater
293 */
294 public int compareTo(MutableFloat other) {
295 float anotherVal = other.value;
296 return Float.compare(value, anotherVal);
297 }
298
299 //-----------------------------------------------------------------------
300 /**
301 * Returns the String value of this mutable.
302 *
303 * @return the mutable value as a string
304 */
305 @Override
306 public String toString() {
307 return String.valueOf(value);
308 }
309
310 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 /**
19 * A mutable <code>int</code> wrapper.
20 *
21 * @see Integer
22 * @since 2.1
23 * @version $Id: MutableInt.java 1153484 2011-08-03 13:39:42Z ggregory $
24 */
25 public class MutableInt extends Number implements Comparable<MutableInt>, Mutable<Number> {
26
27 /**
28 * Required for serialization support.
29 *
30 * @see java.io.Serializable
31 */
32 private static final long serialVersionUID = 512176391864L;
33
34 /** The mutable value. */
35 private int value;
36
37 /**
38 * Constructs a new MutableInt with the default value of zero.
39 */
40 public MutableInt() {
41 super();
42 }
43
44 /**
45 * Constructs a new MutableInt with the specified value.
46 *
47 * @param value the initial value to store
48 */
49 public MutableInt(int value) {
50 super();
51 this.value = value;
52 }
53
54 /**
55 * Constructs a new MutableInt with the specified value.
56 *
57 * @param value the initial value to store, not null
58 * @throws NullPointerException if the object is null
59 */
60 public MutableInt(Number value) {
61 super();
62 this.value = value.intValue();
63 }
64
65 /**
66 * Constructs a new MutableInt parsing the given string.
67 *
68 * @param value the string to parse, not null
69 * @throws NumberFormatException if the string cannot be parsed into an int
70 * @since 2.5
71 */
72 public MutableInt(String value) throws NumberFormatException {
73 super();
74 this.value = Integer.parseInt(value);
75 }
76
77 //-----------------------------------------------------------------------
78 /**
79 * Gets the value as a Integer instance.
80 *
81 * @return the value as a Integer, never null
82 */
83 public Integer getValue() {
84 return Integer.valueOf(this.value);
85 }
86
87 /**
88 * Sets the value.
89 *
90 * @param value the value to set
91 */
92 public void setValue(int value) {
93 this.value = value;
94 }
95
96 /**
97 * Sets the value from any Number instance.
98 *
99 * @param value the value to set, not null
100 * @throws NullPointerException if the object is null
101 */
102 public void setValue(Number value) {
103 this.value = value.intValue();
104 }
105
106 //-----------------------------------------------------------------------
107 /**
108 * Increments the value.
109 *
110 * @since Commons Lang 2.2
111 */
112 public void increment() {
113 value++;
114 }
115
116 /**
117 * Decrements the value.
118 *
119 * @since Commons Lang 2.2
120 */
121 public void decrement() {
122 value--;
123 }
124
125 //-----------------------------------------------------------------------
126 /**
127 * Adds a value to the value of this instance.
128 *
129 * @param operand the value to add, not null
130 * @since Commons Lang 2.2
131 */
132 public void add(int operand) {
133 this.value += operand;
134 }
135
136 /**
137 * Adds a value to the value of this instance.
138 *
139 * @param operand the value to add, not null
140 * @throws NullPointerException if the object is null
141 * @since Commons Lang 2.2
142 */
143 public void add(Number operand) {
144 this.value += operand.intValue();
145 }
146
147 /**
148 * Subtracts a value from the value of this instance.
149 *
150 * @param operand the value to subtract, not null
151 * @since Commons Lang 2.2
152 */
153 public void subtract(int operand) {
154 this.value -= operand;
155 }
156
157 /**
158 * Subtracts a value from the value of this instance.
159 *
160 * @param operand the value to subtract, not null
161 * @throws NullPointerException if the object is null
162 * @since Commons Lang 2.2
163 */
164 public void subtract(Number operand) {
165 this.value -= operand.intValue();
166 }
167
168 //-----------------------------------------------------------------------
169 // shortValue and byteValue rely on Number implementation
170 /**
171 * Returns the value of this MutableInt as an int.
172 *
173 * @return the numeric value represented by this object after conversion to type int.
174 */
175 @Override
176 public int intValue() {
177 return value;
178 }
179
180 /**
181 * Returns the value of this MutableInt as a long.
182 *
183 * @return the numeric value represented by this object after conversion to type long.
184 */
185 @Override
186 public long longValue() {
187 return value;
188 }
189
190 /**
191 * Returns the value of this MutableInt as a float.
192 *
193 * @return the numeric value represented by this object after conversion to type float.
194 */
195 @Override
196 public float floatValue() {
197 return value;
198 }
199
200 /**
201 * Returns the value of this MutableInt as a double.
202 *
203 * @return the numeric value represented by this object after conversion to type double.
204 */
205 @Override
206 public double doubleValue() {
207 return value;
208 }
209
210 //-----------------------------------------------------------------------
211 /**
212 * Gets this mutable as an instance of Integer.
213 *
214 * @return a Integer instance containing the value from this mutable, never null
215 */
216 public Integer toInteger() {
217 return Integer.valueOf(intValue());
218 }
219
220 //-----------------------------------------------------------------------
221 /**
222 * Compares this object to the specified object. The result is <code>true</code> if and only if the argument is
223 * not <code>null</code> and is a <code>MutableInt</code> object that contains the same <code>int</code> value
224 * as this object.
225 *
226 * @param obj the object to compare with, null returns false
227 * @return <code>true</code> if the objects are the same; <code>false</code> otherwise.
228 */
229 @Override
230 public boolean equals(Object obj) {
231 if (obj instanceof MutableInt) {
232 return value == ((MutableInt) obj).intValue();
233 }
234 return false;
235 }
236
237 /**
238 * Returns a suitable hash code for this mutable.
239 *
240 * @return a suitable hash code
241 */
242 @Override
243 public int hashCode() {
244 return value;
245 }
246
247 //-----------------------------------------------------------------------
248 /**
249 * Compares this mutable to another in ascending order.
250 *
251 * @param other the other mutable to compare to, not null
252 * @return negative if this is less, zero if equal, positive if greater
253 */
254 public int compareTo(MutableInt other) {
255 int anotherVal = other.value;
256 return value < anotherVal ? -1 : (value == anotherVal ? 0 : 1);
257 }
258
259 //-----------------------------------------------------------------------
260 /**
261 * Returns the String value of this mutable.
262 *
263 * @return the mutable value as a string
264 */
265 @Override
266 public String toString() {
267 return String.valueOf(value);
268 }
269
270 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 /**
19 * A mutable <code>long</code> wrapper.
20 *
21 * @see Long
22 * @since 2.1
23 * @version $Id: MutableLong.java 1153487 2011-08-03 13:44:51Z ggregory $
24 */
25 public class MutableLong extends Number implements Comparable<MutableLong>, Mutable<Number> {
26
27 /**
28 * Required for serialization support.
29 *
30 * @see java.io.Serializable
31 */
32 private static final long serialVersionUID = 62986528375L;
33
34 /** The mutable value. */
35 private long value;
36
37 /**
38 * Constructs a new MutableLong with the default value of zero.
39 */
40 public MutableLong() {
41 super();
42 }
43
44 /**
45 * Constructs a new MutableLong with the specified value.
46 *
47 * @param value the initial value to store
48 */
49 public MutableLong(long value) {
50 super();
51 this.value = value;
52 }
53
54 /**
55 * Constructs a new MutableLong with the specified value.
56 *
57 * @param value the initial value to store, not null
58 * @throws NullPointerException if the object is null
59 */
60 public MutableLong(Number value) {
61 super();
62 this.value = value.longValue();
63 }
64
65 /**
66 * Constructs a new MutableLong parsing the given string.
67 *
68 * @param value the string to parse, not null
69 * @throws NumberFormatException if the string cannot be parsed into a long
70 * @since 2.5
71 */
72 public MutableLong(String value) throws NumberFormatException {
73 super();
74 this.value = Long.parseLong(value);
75 }
76
77 //-----------------------------------------------------------------------
78 /**
79 * Gets the value as a Long instance.
80 *
81 * @return the value as a Long, never null
82 */
83 public Long getValue() {
84 return Long.valueOf(this.value);
85 }
86
87 /**
88 * Sets the value.
89 *
90 * @param value the value to set
91 */
92 public void setValue(long value) {
93 this.value = value;
94 }
95
96 /**
97 * Sets the value from any Number instance.
98 *
99 * @param value the value to set, not null
100 * @throws NullPointerException if the object is null
101 */
102 public void setValue(Number value) {
103 this.value = value.longValue();
104 }
105
106 //-----------------------------------------------------------------------
107 /**
108 * Increments the value.
109 *
110 * @since Commons Lang 2.2
111 */
112 public void increment() {
113 value++;
114 }
115
116 /**
117 * Decrements the value.
118 *
119 * @since Commons Lang 2.2
120 */
121 public void decrement() {
122 value--;
123 }
124
125 //-----------------------------------------------------------------------
126 /**
127 * Adds a value to the value of this instance.
128 *
129 * @param operand the value to add, not null
130 * @since Commons Lang 2.2
131 */
132 public void add(long operand) {
133 this.value += operand;
134 }
135
136 /**
137 * Adds a value to the value of this instance.
138 *
139 * @param operand the value to add, not null
140 * @throws NullPointerException if the object is null
141 * @since Commons Lang 2.2
142 */
143 public void add(Number operand) {
144 this.value += operand.longValue();
145 }
146
147 /**
148 * Subtracts a value from the value of this instance.
149 *
150 * @param operand the value to subtract, not null
151 * @since Commons Lang 2.2
152 */
153 public void subtract(long operand) {
154 this.value -= operand;
155 }
156
157 /**
158 * Subtracts a value from the value of this instance.
159 *
160 * @param operand the value to subtract, not null
161 * @throws NullPointerException if the object is null
162 * @since Commons Lang 2.2
163 */
164 public void subtract(Number operand) {
165 this.value -= operand.longValue();
166 }
167
168 //-----------------------------------------------------------------------
169 // shortValue and byteValue rely on Number implementation
170 /**
171 * Returns the value of this MutableLong as an int.
172 *
173 * @return the numeric value represented by this object after conversion to type int.
174 */
175 @Override
176 public int intValue() {
177 return (int) value;
178 }
179
180 /**
181 * Returns the value of this MutableLong as a long.
182 *
183 * @return the numeric value represented by this object after conversion to type long.
184 */
185 @Override
186 public long longValue() {
187 return value;
188 }
189
190 /**
191 * Returns the value of this MutableLong as a float.
192 *
193 * @return the numeric value represented by this object after conversion to type float.
194 */
195 @Override
196 public float floatValue() {
197 return value;
198 }
199
200 /**
201 * Returns the value of this MutableLong as a double.
202 *
203 * @return the numeric value represented by this object after conversion to type double.
204 */
205 @Override
206 public double doubleValue() {
207 return value;
208 }
209
210 //-----------------------------------------------------------------------
211 /**
212 * Gets this mutable as an instance of Long.
213 *
214 * @return a Long instance containing the value from this mutable, never null
215 */
216 public Long toLong() {
217 return Long.valueOf(longValue());
218 }
219
220 //-----------------------------------------------------------------------
221 /**
222 * Compares this object to the specified object. The result is <code>true</code> if and only if the argument
223 * is not <code>null</code> and is a <code>MutableLong</code> object that contains the same <code>long</code>
224 * value as this object.
225 *
226 * @param obj the object to compare with, null returns false
227 * @return <code>true</code> if the objects are the same; <code>false</code> otherwise.
228 */
229 @Override
230 public boolean equals(Object obj) {
231 if (obj instanceof MutableLong) {
232 return value == ((MutableLong) obj).longValue();
233 }
234 return false;
235 }
236
237 /**
238 * Returns a suitable hash code for this mutable.
239 *
240 * @return a suitable hash code
241 */
242 @Override
243 public int hashCode() {
244 return (int) (value ^ (value >>> 32));
245 }
246
247 //-----------------------------------------------------------------------
248 /**
249 * Compares this mutable to another in ascending order.
250 *
251 * @param other the other mutable to compare to, not null
252 * @return negative if this is less, zero if equal, positive if greater
253 */
254 public int compareTo(MutableLong other) {
255 long anotherVal = other.value;
256 return value < anotherVal ? -1 : (value == anotherVal ? 0 : 1);
257 }
258
259 //-----------------------------------------------------------------------
260 /**
261 * Returns the String value of this mutable.
262 *
263 * @return the mutable value as a string
264 */
265 @Override
266 public String toString() {
267 return String.valueOf(value);
268 }
269
270 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.mutable;
18
19 import java.io.Serializable;
20
21 /**
22 * A mutable <code>Object</code> wrapper.
23 *
24 * @since 2.1
25 * @version $Id: MutableObject.java 1088899 2011-04-05 05:31:27Z bayard $
26 */
27 public class MutableObject<T> implements Mutable<T>, Serializable {
28
29 /**
30 * Required for serialization support.
31 *
32 * @see java.io.Serializable
33 */
34 private static final long serialVersionUID = 86241875189L;
35
36 /** The mutable value. */
37 private T value;
38
39 /**
40 * Constructs a new MutableObject with the default value of <code>null</code>.
41 */
42 public MutableObject() {
43 super();
44 }
45
46 /**
47 * Constructs a new MutableObject with the specified value.
48 *
49 * @param value the initial value to store
50 */
51 public MutableObject(T value) {
52 super();
53 this.value = value;
54 }
55
56 //-----------------------------------------------------------------------
57 /**
58 * Gets the value.
59 *
60 * @return the value, may be null
61 */
62 public T getValue() {
63 return this.value;
64 }
65
66 /**
67 * Sets the value.
68 *
69 * @param value the value to set
70 */
71 public void setValue(T value) {
72 this.value = value;
73 }
74
75 //-----------------------------------------------------------------------
76 /**
77 * <p>
78 * Compares this object against the specified object. The result is <code>true</code> if and only if the argument
79 * is not <code>null</code> and is a <code>MutableObject</code> object that contains the same <code>T</code>
80 * value as this object.
81 * </p>
82 *
83 * @param obj the object to compare with, <code>null</code> returns <code>false</code>
84 * @return <code>true</code> if the objects are the same;
85 * <code>true</code> if the objects have equivalent <code>value</code> fields;
86 * <code>false</code> otherwise.
87 */
88 @Override
89 public boolean equals(Object obj) {
90 if (obj == null) {
91 return false;
92 }
93 if (this == obj) {
94 return true;
95 }
96 if (this.getClass() == obj.getClass()) {
97 MutableObject<?> that = (MutableObject<?>) obj;
98 return this.value.equals(that.value);
99 } else {
100 return false;
101 }
102 }
103
104 /**
105 * Returns the value's hash code or <code>0</code> if the value is <code>null</code>.
106 *
107 * @return the value's hash code or <code>0</code> if the value is <code>null</code>.
108 */
109 @Override
110 public int hashCode() {
111 return value == null ? 0 : value.hashCode();
112 }
113
114 //-----------------------------------------------------------------------
115 /**
116 * Returns the String value of this mutable.
117 *
118 * @return the mutable value as a string
119 */
120 @Override
121 public String toString() {
122 return value == null ? "null" : value.toString();
123 }
124
125 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 /**
19 * A mutable <code>short</code> wrapper.
20 *
21 * @see Short
22 * @since 2.1
23 * @version $Id: MutableShort.java 1153488 2011-08-03 13:47:49Z ggregory $
24 */
25 public class MutableShort extends Number implements Comparable<MutableShort>, Mutable<Number> {
26
27 /**
28 * Required for serialization support.
29 *
30 * @see java.io.Serializable
31 */
32 private static final long serialVersionUID = -2135791679L;
33
34 /** The mutable value. */
35 private short value;
36
37 /**
38 * Constructs a new MutableShort with the default value of zero.
39 */
40 public MutableShort() {
41 super();
42 }
43
44 /**
45 * Constructs a new MutableShort with the specified value.
46 *
47 * @param value the initial value to store
48 */
49 public MutableShort(short value) {
50 super();
51 this.value = value;
52 }
53
54 /**
55 * Constructs a new MutableShort with the specified value.
56 *
57 * @param value the initial value to store, not null
58 * @throws NullPointerException if the object is null
59 */
60 public MutableShort(Number value) {
61 super();
62 this.value = value.shortValue();
63 }
64
65 /**
66 * Constructs a new MutableShort parsing the given string.
67 *
68 * @param value the string to parse, not null
69 * @throws NumberFormatException if the string cannot be parsed into a short
70 * @since 2.5
71 */
72 public MutableShort(String value) throws NumberFormatException {
73 super();
74 this.value = Short.parseShort(value);
75 }
76
77 //-----------------------------------------------------------------------
78 /**
79 * Gets the value as a Short instance.
80 *
81 * @return the value as a Short, never null
82 */
83 public Short getValue() {
84 return Short.valueOf(this.value);
85 }
86
87 /**
88 * Sets the value.
89 *
90 * @param value the value to set
91 */
92 public void setValue(short value) {
93 this.value = value;
94 }
95
96 /**
97 * Sets the value from any Number instance.
98 *
99 * @param value the value to set, not null
100 * @throws NullPointerException if the object is null
101 */
102 public void setValue(Number value) {
103 this.value = value.shortValue();
104 }
105
106 //-----------------------------------------------------------------------
107 /**
108 * Increments the value.
109 *
110 * @since Commons Lang 2.2
111 */
112 public void increment() {
113 value++;
114 }
115
116 /**
117 * Decrements the value.
118 *
119 * @since Commons Lang 2.2
120 */
121 public void decrement() {
122 value--;
123 }
124
125 //-----------------------------------------------------------------------
126 /**
127 * Adds a value to the value of this instance.
128 *
129 * @param operand the value to add, not null
130 * @since Commons Lang 2.2
131 */
132 public void add(short operand) {
133 this.value += operand;
134 }
135
136 /**
137 * Adds a value to the value of this instance.
138 *
139 * @param operand the value to add, not null
140 * @throws NullPointerException if the object is null
141 * @since Commons Lang 2.2
142 */
143 public void add(Number operand) {
144 this.value += operand.shortValue();
145 }
146
147 /**
148 * Subtracts a value from the value of this instance.
149 *
150 * @param operand the value to subtract, not null
151 * @since Commons Lang 2.2
152 */
153 public void subtract(short operand) {
154 this.value -= operand;
155 }
156
157 /**
158 * Subtracts a value from the value of this instance.
159 *
160 * @param operand the value to subtract, not null
161 * @throws NullPointerException if the object is null
162 * @since Commons Lang 2.2
163 */
164 public void subtract(Number operand) {
165 this.value -= operand.shortValue();
166 }
167
168 //-----------------------------------------------------------------------
169 // byteValue relies on Number implementation
170 /**
171 * Returns the value of this MutableShort as a short.
172 *
173 * @return the numeric value represented by this object after conversion to type short.
174 */
175 @Override
176 public short shortValue() {
177 return value;
178 }
179
180 /**
181 * Returns the value of this MutableShort as an int.
182 *
183 * @return the numeric value represented by this object after conversion to type int.
184 */
185 @Override
186 public int intValue() {
187 return value;
188 }
189
190 /**
191 * Returns the value of this MutableShort as a long.
192 *
193 * @return the numeric value represented by this object after conversion to type long.
194 */
195 @Override
196 public long longValue() {
197 return value;
198 }
199
200 /**
201 * Returns the value of this MutableShort as a float.
202 *
203 * @return the numeric value represented by this object after conversion to type float.
204 */
205 @Override
206 public float floatValue() {
207 return value;
208 }
209
210 /**
211 * Returns the value of this MutableShort as a double.
212 *
213 * @return the numeric value represented by this object after conversion to type double.
214 */
215 @Override
216 public double doubleValue() {
217 return value;
218 }
219
220 //-----------------------------------------------------------------------
221 /**
222 * Gets this mutable as an instance of Short.
223 *
224 * @return a Short instance containing the value from this mutable, never null
225 */
226 public Short toShort() {
227 return Short.valueOf(shortValue());
228 }
229
230 //-----------------------------------------------------------------------
231 /**
232 * Compares this object to the specified object. The result is <code>true</code> if and only if the argument
233 * is not <code>null</code> and is a <code>MutableShort</code> object that contains the same <code>short</code>
234 * value as this object.
235 *
236 * @param obj the object to compare with, null returns false
237 * @return <code>true</code> if the objects are the same; <code>false</code> otherwise.
238 */
239 @Override
240 public boolean equals(Object obj) {
241 if (obj instanceof MutableShort) {
242 return value == ((MutableShort) obj).shortValue();
243 }
244 return false;
245 }
246
247 /**
248 * Returns a suitable hash code for this mutable.
249 *
250 * @return a suitable hash code
251 */
252 @Override
253 public int hashCode() {
254 return value;
255 }
256
257 //-----------------------------------------------------------------------
258 /**
259 * Compares this mutable to another in ascending order.
260 *
261 * @param other the other mutable to compare to, not null
262 * @return negative if this is less, zero if equal, positive if greater
263 */
264 public int compareTo(MutableShort other) {
265 short anotherVal = other.value;
266 return value < anotherVal ? -1 : (value == anotherVal ? 0 : 1);
267 }
268
269 //-----------------------------------------------------------------------
270 /**
271 * Returns the String value of this mutable.
272 *
273 * @return the mutable value as a string
274 */
275 @Override
276 public String toString() {
277 return String.valueOf(value);
278 }
279
280 }
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <!--
4 Licensed to the Apache Software Foundation (ASF) under one
5 or more contributor license agreements. See the NOTICE file
6 distributed with this work for additional information
7 regarding copyright ownership. The ASF licenses this file
8 to you under the Apache License, Version 2.0 (the
9 "License"); you may not use this file except in compliance
10 with the License. You may obtain a copy of the License at
11
12 http://www.apache.org/licenses/LICENSE-2.0
13
14 Unless required by applicable law or agreed to in writing,
15 software distributed under the License is distributed on an
16 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 KIND, either express or implied. See the License for the
18 specific language governing permissions and limitations
19 under the License.
20 -->
21 <title></title>
22 </head>
23 <body>
24 Provides typed mutable wrappers to primitive values and Object.
25 @since 2.1
26 <p>These classes are not thread-safe.</p>
27 </body>
28 </html>
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 <p>
19 This document is the API specification for the Apache Commons Lang library.
20 </p>
21 </body>
22 </html>
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 Provides highly reusable static utility methods, chiefly concerned
19 with adding value to the {@link java.lang} classes.
20 @since 1.0
21 <p>Most of these classes are immutable and thus thread-safe.
22 However Charset is not currently guaranteed thread-safe under all circumstances.</p>
23 </body>
24 </html>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Modifier;
21
22 import org.apache.commons.lang3.ArrayUtils;
23 import org.apache.commons.lang3.ClassUtils;
24
25 /**
26 * <p> Utility reflection methods focused on constructors, modeled after
27 * {@link MethodUtils}. </p>
28 *
29 * <h3>Known Limitations</h3> <h4>Accessing Public Constructors In A Default
30 * Access Superclass</h4> <p>There is an issue when invoking public constructors
31 * contained in a default access superclass. Reflection locates these
32 * constructors fine and correctly assigns them as public. However, an
33 * <code>IllegalAccessException</code> is thrown if the constructors is
34 * invoked.</p>
35 *
36 * <p><code>ConstructorUtils</code> contains a workaround for this situation. It
37 * will attempt to call <code>setAccessible</code> on this constructor. If this
38 * call succeeds, then the method can be invoked as normal. This call will only
39 * succeed when the application has sufficient security privileges. If this call
40 * fails then a warning will be logged and the method may fail.</p>
41 *
42 * @since 2.5
43 * @version $Id: ConstructorUtils.java 1144010 2011-07-07 20:02:10Z joehni $
44 */
45 public class ConstructorUtils {
46
47 /**
48 * <p>ConstructorUtils instances should NOT be constructed in standard
49 * programming. Instead, the class should be used as
50 * <code>ConstructorUtils.invokeConstructor(cls, args)</code>.</p>
51 *
52 * <p>This constructor is public to permit tools that require a JavaBean
53 * instance to operate.</p>
54 */
55 public ConstructorUtils() {
56 super();
57 }
58
59 /**
60 * <p>Returns a new instance of the specified class inferring the right constructor
61 * from the types of the arguments.</p>
62 *
63 * <p>This locates and calls a constructor.
64 * The constructor signature must match the argument types by assignment compatibility.</p>
65 *
66 * @param <T> the type to be constructed
67 * @param cls the class to be constructed, not null
68 * @param args the array of arguments, null treated as empty
69 * @return new instance of <code>cls</code>, not null
70 *
71 * @throws NoSuchMethodException if a matching constructor cannot be found
72 * @throws IllegalAccessException if invocation is not permitted by security
73 * @throws InvocationTargetException if an error occurs on invocation
74 * @throws InstantiationException if an error occurs on instantiation
75 * @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
76 */
77 public static <T> T invokeConstructor(Class<T> cls, Object... args)
78 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
79 InstantiationException {
80 if (args == null) {
81 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
82 }
83 Class<?> parameterTypes[] = new Class[args.length];
84 for (int i = 0; i < args.length; i++) {
85 parameterTypes[i] = args[i].getClass();
86 }
87 return invokeConstructor(cls, args, parameterTypes);
88 }
89
90 /**
91 * <p>Returns a new instance of the specified class choosing the right constructor
92 * from the list of parameter types.</p>
93 *
94 * <p>This locates and calls a constructor.
95 * The constructor signature must match the parameter types by assignment compatibility.</p>
96 *
97 * @param <T> the type to be constructed
98 * @param cls the class to be constructed, not null
99 * @param args the array of arguments, null treated as empty
100 * @param parameterTypes the array of parameter types, null treated as empty
101 * @return new instance of <code>cls</code>, not null
102 *
103 * @throws NoSuchMethodException if a matching constructor cannot be found
104 * @throws IllegalAccessException if invocation is not permitted by security
105 * @throws InvocationTargetException if an error occurs on invocation
106 * @throws InstantiationException if an error occurs on instantiation
107 * @see Constructor#newInstance
108 */
109 public static <T> T invokeConstructor(Class<T> cls, Object[] args, Class<?>[] parameterTypes)
110 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
111 InstantiationException {
112 if (parameterTypes == null) {
113 parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
114 }
115 if (args == null) {
116 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
117 }
118 Constructor<T> ctor = getMatchingAccessibleConstructor(cls, parameterTypes);
119 if (ctor == null) {
120 throw new NoSuchMethodException(
121 "No such accessible constructor on object: " + cls.getName());
122 }
123 return ctor.newInstance(args);
124 }
125
126 /**
127 * <p>Returns a new instance of the specified class inferring the right constructor
128 * from the types of the arguments.</p>
129 *
130 * <p>This locates and calls a constructor.
131 * The constructor signature must match the argument types exactly.</p>
132 *
133 * @param <T> the type to be constructed
134 * @param cls the class to be constructed, not null
135 * @param args the array of arguments, null treated as empty
136 * @return new instance of <code>cls</code>, not null
137 *
138 * @throws NoSuchMethodException if a matching constructor cannot be found
139 * @throws IllegalAccessException if invocation is not permitted by security
140 * @throws InvocationTargetException if an error occurs on invocation
141 * @throws InstantiationException if an error occurs on instantiation
142 * @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
143 */
144 public static <T> T invokeExactConstructor(Class<T> cls, Object... args)
145 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
146 InstantiationException {
147 if (args == null) {
148 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
149 }
150 int arguments = args.length;
151 Class<?> parameterTypes[] = new Class[arguments];
152 for (int i = 0; i < arguments; i++) {
153 parameterTypes[i] = args[i].getClass();
154 }
155 return invokeExactConstructor(cls, args, parameterTypes);
156 }
157
158 /**
159 * <p>Returns a new instance of the specified class choosing the right constructor
160 * from the list of parameter types.</p>
161 *
162 * <p>This locates and calls a constructor.
163 * The constructor signature must match the parameter types exactly.</p>
164 *
165 * @param <T> the type to be constructed
166 * @param cls the class to be constructed, not null
167 * @param args the array of arguments, null treated as empty
168 * @param parameterTypes the array of parameter types, null treated as empty
169 * @return new instance of <code>cls</code>, not null
170 *
171 * @throws NoSuchMethodException if a matching constructor cannot be found
172 * @throws IllegalAccessException if invocation is not permitted by security
173 * @throws InvocationTargetException if an error occurs on invocation
174 * @throws InstantiationException if an error occurs on instantiation
175 * @see Constructor#newInstance
176 */
177 public static <T> T invokeExactConstructor(Class<T> cls, Object[] args,
178 Class<?>[] parameterTypes) throws NoSuchMethodException, IllegalAccessException,
179 InvocationTargetException, InstantiationException {
180 if (args == null) {
181 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
182 }
183 if (parameterTypes == null) {
184 parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
185 }
186 Constructor<T> ctor = getAccessibleConstructor(cls, parameterTypes);
187 if (ctor == null) {
188 throw new NoSuchMethodException(
189 "No such accessible constructor on object: "+ cls.getName());
190 }
191 return ctor.newInstance(args);
192 }
193
194 //-----------------------------------------------------------------------
195 /**
196 * <p>Finds a constructor given a class and signature, checking accessibility.</p>
197 *
198 * <p>This finds the constructor and ensures that it is accessible.
199 * The constructor signature must match the parameter types exactly.</p>
200 *
201 * @param <T> the constructor type
202 * @param cls the class to find a constructor for, not null
203 * @param parameterTypes the array of parameter types, null treated as empty
204 * @return the constructor, null if no matching accessible constructor found
205 * @see Class#getConstructor
206 * @see #getAccessibleConstructor(java.lang.reflect.Constructor)
207 */
208 public static <T> Constructor<T> getAccessibleConstructor(Class<T> cls,
209 Class<?>... parameterTypes) {
210 try {
211 return getAccessibleConstructor(cls.getConstructor(parameterTypes));
212 } catch (NoSuchMethodException e) {
213 return null;
214 }
215 }
216
217 /**
218 * <p>Checks if the specified constructor is accessible.</p>
219 *
220 * <p>This simply ensures that the constructor is accessible.</p>
221 *
222 * @param <T> the constructor type
223 * @param ctor the prototype constructor object, not null
224 * @return the constructor, null if no matching accessible constructor found
225 * @see java.lang.SecurityManager
226 */
227 public static <T> Constructor<T> getAccessibleConstructor(Constructor<T> ctor) {
228 return MemberUtils.isAccessible(ctor)
229 && Modifier.isPublic(ctor.getDeclaringClass().getModifiers()) ? ctor : null;
230 }
231
232 /**
233 * <p>Finds an accessible constructor with compatible parameters.</p>
234 *
235 * <p>This checks all the constructor and finds one with compatible parameters
236 * This requires that every parameter is assignable from the given parameter types.
237 * This is a more flexible search than the normal exact matching algorithm.</p>
238 *
239 * <p>First it checks if there is a constructor matching the exact signature.
240 * If not then all the constructors of the class are checked to see if their
241 * signatures are assignment compatible with the parameter types.
242 * The first assignment compatible matching constructor is returned.</p>
243 *
244 * @param <T> the constructor type
245 * @param cls the class to find a constructor for, not null
246 * @param parameterTypes find method with compatible parameters
247 * @return the constructor, null if no matching accessible constructor found
248 */
249 public static <T> Constructor<T> getMatchingAccessibleConstructor(Class<T> cls,
250 Class<?>... parameterTypes) {
251 // see if we can find the constructor directly
252 // most of the time this works and it's much faster
253 try {
254 Constructor<T> ctor = cls.getConstructor(parameterTypes);
255 MemberUtils.setAccessibleWorkaround(ctor);
256 return ctor;
257 } catch (NoSuchMethodException e) { // NOPMD - Swallow
258 }
259 Constructor<T> result = null;
260 /*
261 * (1) Class.getConstructors() is documented to return Constructor<T> so as
262 * long as the array is not subsequently modified, everything's fine.
263 */
264 Constructor<?>[] ctors = cls.getConstructors();
265
266 // return best match:
267 for (Constructor<?> ctor : ctors) {
268 // compare parameters
269 if (ClassUtils.isAssignable(parameterTypes, ctor.getParameterTypes(), true)) {
270 // get accessible version of constructor
271 ctor = getAccessibleConstructor(ctor);
272 if (ctor != null) {
273 MemberUtils.setAccessibleWorkaround(ctor);
274 if (result == null
275 || MemberUtils.compareParameterTypes(ctor.getParameterTypes(), result
276 .getParameterTypes(), parameterTypes) < 0) {
277 // temporary variable for annotation, see comment above (1)
278 @SuppressWarnings("unchecked")
279 Constructor<T> constructor = (Constructor<T>)ctor;
280 result = constructor;
281 }
282 }
283 }
284 }
285 return result;
286 }
287
288 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect;
17
18 import java.lang.reflect.Field;
19 import java.lang.reflect.Modifier;
20
21 import org.apache.commons.lang3.ClassUtils;
22
23 /**
24 * Utilities for working with fields by reflection. Adapted and refactored
25 * from the dormant [reflect] Commons sandbox component.
26 * <p>
27 * The ability is provided to break the scoping restrictions coded by the
28 * programmer. This can allow fields to be changed that shouldn't be. This
29 * facility should be used with care.
30 *
31 * @since 2.5
32 * @version $Id: FieldUtils.java 1144929 2011-07-10 18:26:16Z ggregory $
33 */
34 public class FieldUtils {
35
36 /**
37 * FieldUtils instances should NOT be constructed in standard programming.
38 * <p>
39 * This constructor is public to permit tools that require a JavaBean instance
40 * to operate.
41 */
42 public FieldUtils() {
43 super();
44 }
45
46 /**
47 * Gets an accessible <code>Field</code> by name respecting scope.
48 * Superclasses/interfaces will be considered.
49 *
50 * @param cls the class to reflect, must not be null
51 * @param fieldName the field name to obtain
52 * @return the Field object
53 * @throws IllegalArgumentException if the class or field name is null
54 */
55 public static Field getField(Class<?> cls, String fieldName) {
56 Field field = getField(cls, fieldName, false);
57 MemberUtils.setAccessibleWorkaround(field);
58 return field;
59 }
60
61 /**
62 * Gets an accessible <code>Field</code> by name breaking scope
63 * if requested. Superclasses/interfaces will be considered.
64 *
65 * @param cls the class to reflect, must not be null
66 * @param fieldName the field name to obtain
67 * @param forceAccess whether to break scope restrictions using the
68 * <code>setAccessible</code> method. <code>False</code> will only
69 * match public fields.
70 * @return the Field object
71 * @throws IllegalArgumentException if the class or field name is null
72 */
73 public static Field getField(final Class<?> cls, String fieldName, boolean forceAccess) {
74 if (cls == null) {
75 throw new IllegalArgumentException("The class must not be null");
76 }
77 if (fieldName == null) {
78 throw new IllegalArgumentException("The field name must not be null");
79 }
80 // Sun Java 1.3 has a bugged implementation of getField hence we write the
81 // code ourselves
82
83 // getField() will return the Field object with the declaring class
84 // set correctly to the class that declares the field. Thus requesting the
85 // field on a subclass will return the field from the superclass.
86 //
87 // priority order for lookup:
88 // searchclass private/protected/package/public
89 // superclass protected/package/public
90 // private/different package blocks access to further superclasses
91 // implementedinterface public
92
93 // check up the superclass hierarchy
94 for (Class<?> acls = cls; acls != null; acls = acls.getSuperclass()) {
95 try {
96 Field field = acls.getDeclaredField(fieldName);
97 // getDeclaredField checks for non-public scopes as well
98 // and it returns accurate results
99 if (!Modifier.isPublic(field.getModifiers())) {
100 if (forceAccess) {
101 field.setAccessible(true);
102 } else {
103 continue;
104 }
105 }
106 return field;
107 } catch (NoSuchFieldException ex) { // NOPMD
108 // ignore
109 }
110 }
111 // check the public interface case. This must be manually searched for
112 // incase there is a public supersuperclass field hidden by a private/package
113 // superclass field.
114 Field match = null;
115 for (Class<?> class1 : ClassUtils.getAllInterfaces(cls)) {
116 try {
117 Field test = ((Class<?>) class1).getField(fieldName);
118 if (match != null) {
119 throw new IllegalArgumentException("Reference to field " + fieldName + " is ambiguous relative to " + cls
120 + "; a matching field exists on two or more implemented interfaces.");
121 }
122 match = test;
123 } catch (NoSuchFieldException ex) { // NOPMD
124 // ignore
125 }
126 }
127 return match;
128 }
129
130 /**
131 * Gets an accessible <code>Field</code> by name respecting scope.
132 * Only the specified class will be considered.
133 *
134 * @param cls the class to reflect, must not be null
135 * @param fieldName the field name to obtain
136 * @return the Field object
137 * @throws IllegalArgumentException if the class or field name is null
138 */
139 public static Field getDeclaredField(Class<?> cls, String fieldName) {
140 return getDeclaredField(cls, fieldName, false);
141 }
142
143 /**
144 * Gets an accessible <code>Field</code> by name breaking scope
145 * if requested. Only the specified class will be considered.
146 *
147 * @param cls the class to reflect, must not be null
148 * @param fieldName the field name to obtain
149 * @param forceAccess whether to break scope restrictions using the
150 * <code>setAccessible</code> method. False will only match public fields.
151 * @return the Field object
152 * @throws IllegalArgumentException if the class or field name is null
153 */
154 public static Field getDeclaredField(Class<?> cls, String fieldName, boolean forceAccess) {
155 if (cls == null) {
156 throw new IllegalArgumentException("The class must not be null");
157 }
158 if (fieldName == null) {
159 throw new IllegalArgumentException("The field name must not be null");
160 }
161 try {
162 // only consider the specified class by using getDeclaredField()
163 Field field = cls.getDeclaredField(fieldName);
164 if (!MemberUtils.isAccessible(field)) {
165 if (forceAccess) {
166 field.setAccessible(true);
167 } else {
168 return null;
169 }
170 }
171 return field;
172 } catch (NoSuchFieldException e) { // NOPMD
173 // ignore
174 }
175 return null;
176 }
177
178 /**
179 * Reads an accessible static Field.
180 * @param field to read
181 * @return the field value
182 * @throws IllegalArgumentException if the field is null or not static
183 * @throws IllegalAccessException if the field is not accessible
184 */
185 public static Object readStaticField(Field field) throws IllegalAccessException {
186 return readStaticField(field, false);
187 }
188
189 /**
190 * Reads a static Field.
191 * @param field to read
192 * @param forceAccess whether to break scope restrictions using the
193 * <code>setAccessible</code> method.
194 * @return the field value
195 * @throws IllegalArgumentException if the field is null or not static
196 * @throws IllegalAccessException if the field is not made accessible
197 */
198 public static Object readStaticField(Field field, boolean forceAccess) throws IllegalAccessException {
199 if (field == null) {
200 throw new IllegalArgumentException("The field must not be null");
201 }
202 if (!Modifier.isStatic(field.getModifiers())) {
203 throw new IllegalArgumentException("The field '" + field.getName() + "' is not static");
204 }
205 return readField(field, (Object) null, forceAccess);
206 }
207
208 /**
209 * Reads the named public static field. Superclasses will be considered.
210 * @param cls the class to reflect, must not be null
211 * @param fieldName the field name to obtain
212 * @return the value of the field
213 * @throws IllegalArgumentException if the class is null, the field name is null or if the field could not be found
214 * @throws IllegalAccessException if the field is not accessible
215 */
216 public static Object readStaticField(Class<?> cls, String fieldName) throws IllegalAccessException {
217 return readStaticField(cls, fieldName, false);
218 }
219
220 /**
221 * Reads the named static field. Superclasses will be considered.
222 * @param cls the class to reflect, must not be null
223 * @param fieldName the field name to obtain
224 * @param forceAccess whether to break scope restrictions using the
225 * <code>setAccessible</code> method. <code>False</code> will only
226 * match public fields.
227 * @return the Field object
228 * @throws IllegalArgumentException if the class is null, the field name is null or if the field could not be found
229 * @throws IllegalAccessException if the field is not made accessible
230 */
231 public static Object readStaticField(Class<?> cls, String fieldName, boolean forceAccess)
232 throws IllegalAccessException {
233 Field field = getField(cls, fieldName, forceAccess);
234 if (field == null) {
235 throw new IllegalArgumentException("Cannot locate field " + fieldName + " on " + cls);
236 }
237 //already forced access above, don't repeat it here:
238 return readStaticField(field, false);
239 }
240
241 /**
242 * Gets a static Field value by name. The field must be public.
243 * Only the specified class will be considered.
244 *
245 * @param cls the class to reflect, must not be null
246 * @param fieldName the field name to obtain
247 * @return the value of the field
248 * @throws IllegalArgumentException if the class is null, the field name is null or if the field could not be found
249 * @throws IllegalAccessException if the field is not accessible
250 */
251 public static Object readDeclaredStaticField(Class<?> cls, String fieldName) throws IllegalAccessException {
252 return readDeclaredStaticField(cls, fieldName, false);
253 }
254
255 /**
256 * Gets a static Field value by name. Only the specified class will
257 * be considered.
258 *
259 * @param cls the class to reflect, must not be null
260 * @param fieldName the field name to obtain
261 * @param forceAccess whether to break scope restrictions using the
262 * <code>setAccessible</code> method. <code>False</code> will only
263 * match public fields.
264 * @return the Field object
265 * @throws IllegalArgumentException if the class is null, the field name is null or if the field could not be found
266 * @throws IllegalAccessException if the field is not made accessible
267 */
268 public static Object readDeclaredStaticField(Class<?> cls, String fieldName, boolean forceAccess)
269 throws IllegalAccessException {
270 Field field = getDeclaredField(cls, fieldName, forceAccess);
271 if (field == null) {
272 throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
273 }
274 //already forced access above, don't repeat it here:
275 return readStaticField(field, false);
276 }
277
278 /**
279 * Reads an accessible Field.
280 * @param field the field to use
281 * @param target the object to call on, may be null for static fields
282 * @return the field value
283 * @throws IllegalArgumentException if the field is null
284 * @throws IllegalAccessException if the field is not accessible
285 */
286 public static Object readField(Field field, Object target) throws IllegalAccessException {
287 return readField(field, target, false);
288 }
289
290 /**
291 * Reads a Field.
292 * @param field the field to use
293 * @param target the object to call on, may be null for static fields
294 * @param forceAccess whether to break scope restrictions using the
295 * <code>setAccessible</code> method.
296 * @return the field value
297 * @throws IllegalArgumentException if the field is null
298 * @throws IllegalAccessException if the field is not made accessible
299 */
300 public static Object readField(Field field, Object target, boolean forceAccess) throws IllegalAccessException {
301 if (field == null) {
302 throw new IllegalArgumentException("The field must not be null");
303 }
304 if (forceAccess && !field.isAccessible()) {
305 field.setAccessible(true);
306 } else {
307 MemberUtils.setAccessibleWorkaround(field);
308 }
309 return field.get(target);
310 }
311
312 /**
313 * Reads the named public field. Superclasses will be considered.
314 * @param target the object to reflect, must not be null
315 * @param fieldName the field name to obtain
316 * @return the value of the field
317 * @throws IllegalArgumentException if the class or field name is null
318 * @throws IllegalAccessException if the named field is not public
319 */
320 public static Object readField(Object target, String fieldName) throws IllegalAccessException {
321 return readField(target, fieldName, false);
322 }
323
324 /**
325 * Reads the named field. Superclasses will be considered.
326 * @param target the object to reflect, must not be null
327 * @param fieldName the field name to obtain
328 * @param forceAccess whether to break scope restrictions using the
329 * <code>setAccessible</code> method. <code>False</code> will only
330 * match public fields.
331 * @return the field value
332 * @throws IllegalArgumentException if the class or field name is null
333 * @throws IllegalAccessException if the named field is not made accessible
334 */
335 public static Object readField(Object target, String fieldName, boolean forceAccess) throws IllegalAccessException {
336 if (target == null) {
337 throw new IllegalArgumentException("target object must not be null");
338 }
339 Class<?> cls = target.getClass();
340 Field field = getField(cls, fieldName, forceAccess);
341 if (field == null) {
342 throw new IllegalArgumentException("Cannot locate field " + fieldName + " on " + cls);
343 }
344 //already forced access above, don't repeat it here:
345 return readField(field, target);
346 }
347
348 /**
349 * Reads the named public field. Only the class of the specified object will be considered.
350 * @param target the object to reflect, must not be null
351 * @param fieldName the field name to obtain
352 * @return the value of the field
353 * @throws IllegalArgumentException if the class or field name is null
354 * @throws IllegalAccessException if the named field is not public
355 */
356 public static Object readDeclaredField(Object target, String fieldName) throws IllegalAccessException {
357 return readDeclaredField(target, fieldName, false);
358 }
359
360 /**
361 * <p<>Gets a Field value by name. Only the class of the specified
362 * object will be considered.
363 *
364 * @param target the object to reflect, must not be null
365 * @param fieldName the field name to obtain
366 * @param forceAccess whether to break scope restrictions using the
367 * <code>setAccessible</code> method. <code>False</code> will only
368 * match public fields.
369 * @return the Field object
370 * @throws IllegalArgumentException if <code>target</code> or <code>fieldName</code> is null
371 * @throws IllegalAccessException if the field is not made accessible
372 */
373 public static Object readDeclaredField(Object target, String fieldName, boolean forceAccess)
374 throws IllegalAccessException {
375 if (target == null) {
376 throw new IllegalArgumentException("target object must not be null");
377 }
378 Class<?> cls = target.getClass();
379 Field field = getDeclaredField(cls, fieldName, forceAccess);
380 if (field == null) {
381 throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
382 }
383 //already forced access above, don't repeat it here:
384 return readField(field, target);
385 }
386
387 /**
388 * Writes a public static Field.
389 * @param field to write
390 * @param value to set
391 * @throws IllegalArgumentException if the field is null or not static
392 * @throws IllegalAccessException if the field is not public or is final
393 */
394 public static void writeStaticField(Field field, Object value) throws IllegalAccessException {
395 writeStaticField(field, value, false);
396 }
397
398 /**
399 * Writes a static Field.
400 * @param field to write
401 * @param value to set
402 * @param forceAccess whether to break scope restrictions using the
403 * <code>setAccessible</code> method. <code>False</code> will only
404 * match public fields.
405 * @throws IllegalArgumentException if the field is null or not static
406 * @throws IllegalAccessException if the field is not made accessible or is final
407 */
408 public static void writeStaticField(Field field, Object value, boolean forceAccess) throws IllegalAccessException {
409 if (field == null) {
410 throw new IllegalArgumentException("The field must not be null");
411 }
412 if (!Modifier.isStatic(field.getModifiers())) {
413 throw new IllegalArgumentException("The field '" + field.getName() + "' is not static");
414 }
415 writeField(field, (Object) null, value, forceAccess);
416 }
417
418 /**
419 * Writes a named public static Field. Superclasses will be considered.
420 * @param cls Class on which the Field is to be found
421 * @param fieldName to write
422 * @param value to set
423 * @throws IllegalArgumentException if the field cannot be located or is not static
424 * @throws IllegalAccessException if the field is not public or is final
425 */
426 public static void writeStaticField(Class<?> cls, String fieldName, Object value) throws IllegalAccessException {
427 writeStaticField(cls, fieldName, value, false);
428 }
429
430 /**
431 * Writes a named static Field. Superclasses will be considered.
432 * @param cls Class on which the Field is to be found
433 * @param fieldName to write
434 * @param value to set
435 * @param forceAccess whether to break scope restrictions using the
436 * <code>setAccessible</code> method. <code>False</code> will only
437 * match public fields.
438 * @throws IllegalArgumentException if the field cannot be located or is not static
439 * @throws IllegalAccessException if the field is not made accessible or is final
440 */
441 public static void writeStaticField(Class<?> cls, String fieldName, Object value, boolean forceAccess)
442 throws IllegalAccessException {
443 Field field = getField(cls, fieldName, forceAccess);
444 if (field == null) {
445 throw new IllegalArgumentException("Cannot locate field " + fieldName + " on " + cls);
446 }
447 //already forced access above, don't repeat it here:
448 writeStaticField(field, value);
449 }
450
451 /**
452 * Writes a named public static Field. Only the specified class will be considered.
453 * @param cls Class on which the Field is to be found
454 * @param fieldName to write
455 * @param value to set
456 * @throws IllegalArgumentException if the field cannot be located or is not static
457 * @throws IllegalAccessException if the field is not public or is final
458 */
459 public static void writeDeclaredStaticField(Class<?> cls, String fieldName, Object value)
460 throws IllegalAccessException {
461 writeDeclaredStaticField(cls, fieldName, value, false);
462 }
463
464 /**
465 * Writes a named static Field. Only the specified class will be considered.
466 * @param cls Class on which the Field is to be found
467 * @param fieldName to write
468 * @param value to set
469 * @param forceAccess whether to break scope restrictions using the
470 * <code>setAccessible</code> method. <code>False</code> will only
471 * match public fields.
472 * @throws IllegalArgumentException if the field cannot be located or is not static
473 * @throws IllegalAccessException if the field is not made accessible or is final
474 */
475 public static void writeDeclaredStaticField(Class<?> cls, String fieldName, Object value, boolean forceAccess)
476 throws IllegalAccessException {
477 Field field = getDeclaredField(cls, fieldName, forceAccess);
478 if (field == null) {
479 throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
480 }
481 //already forced access above, don't repeat it here:
482 writeField(field, (Object) null, value);
483 }
484
485 /**
486 * Writes an accessible field.
487 * @param field to write
488 * @param target the object to call on, may be null for static fields
489 * @param value to set
490 * @throws IllegalArgumentException if the field is null
491 * @throws IllegalAccessException if the field is not accessible or is final
492 */
493 public static void writeField(Field field, Object target, Object value) throws IllegalAccessException {
494 writeField(field, target, value, false);
495 }
496
497 /**
498 * Writes a field.
499 * @param field to write
500 * @param target the object to call on, may be null for static fields
501 * @param value to set
502 * @param forceAccess whether to break scope restrictions using the
503 * <code>setAccessible</code> method. <code>False</code> will only
504 * match public fields.
505 * @throws IllegalArgumentException if the field is null
506 * @throws IllegalAccessException if the field is not made accessible or is final
507 */
508 public static void writeField(Field field, Object target, Object value, boolean forceAccess)
509 throws IllegalAccessException {
510 if (field == null) {
511 throw new IllegalArgumentException("The field must not be null");
512 }
513 if (forceAccess && !field.isAccessible()) {
514 field.setAccessible(true);
515 } else {
516 MemberUtils.setAccessibleWorkaround(field);
517 }
518 field.set(target, value);
519 }
520
521 /**
522 * Writes a public field. Superclasses will be considered.
523 * @param target the object to reflect, must not be null
524 * @param fieldName the field name to obtain
525 * @param value to set
526 * @throws IllegalArgumentException if <code>target</code> or <code>fieldName</code> is null
527 * @throws IllegalAccessException if the field is not accessible
528 */
529 public static void writeField(Object target, String fieldName, Object value) throws IllegalAccessException {
530 writeField(target, fieldName, value, false);
531 }
532
533 /**
534 * Writes a field. Superclasses will be considered.
535 * @param target the object to reflect, must not be null
536 * @param fieldName the field name to obtain
537 * @param value to set
538 * @param forceAccess whether to break scope restrictions using the
539 * <code>setAccessible</code> method. <code>False</code> will only
540 * match public fields.
541 * @throws IllegalArgumentException if <code>target</code> or <code>fieldName</code> is null
542 * @throws IllegalAccessException if the field is not made accessible
543 */
544 public static void writeField(Object target, String fieldName, Object value, boolean forceAccess)
545 throws IllegalAccessException {
546 if (target == null) {
547 throw new IllegalArgumentException("target object must not be null");
548 }
549 Class<?> cls = target.getClass();
550 Field field = getField(cls, fieldName, forceAccess);
551 if (field == null) {
552 throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
553 }
554 //already forced access above, don't repeat it here:
555 writeField(field, target, value);
556 }
557
558 /**
559 * Writes a public field. Only the specified class will be considered.
560 * @param target the object to reflect, must not be null
561 * @param fieldName the field name to obtain
562 * @param value to set
563 * @throws IllegalArgumentException if <code>target</code> or <code>fieldName</code> is null
564 * @throws IllegalAccessException if the field is not made accessible
565 */
566 public static void writeDeclaredField(Object target, String fieldName, Object value) throws IllegalAccessException {
567 writeDeclaredField(target, fieldName, value, false);
568 }
569
570 /**
571 * Writes a public field. Only the specified class will be considered.
572 * @param target the object to reflect, must not be null
573 * @param fieldName the field name to obtain
574 * @param value to set
575 * @param forceAccess whether to break scope restrictions using the
576 * <code>setAccessible</code> method. <code>False</code> will only
577 * match public fields.
578 * @throws IllegalArgumentException if <code>target</code> or <code>fieldName</code> is null
579 * @throws IllegalAccessException if the field is not made accessible
580 */
581 public static void writeDeclaredField(Object target, String fieldName, Object value, boolean forceAccess)
582 throws IllegalAccessException {
583 if (target == null) {
584 throw new IllegalArgumentException("target object must not be null");
585 }
586 Class<?> cls = target.getClass();
587 Field field = getDeclaredField(cls, fieldName, forceAccess);
588 if (field == null) {
589 throw new IllegalArgumentException("Cannot locate declared field " + cls.getName() + "." + fieldName);
590 }
591 //already forced access above, don't repeat it here:
592 writeField(field, target, value);
593 }
594 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect;
17
18 import java.lang.reflect.AccessibleObject;
19 import java.lang.reflect.Member;
20 import java.lang.reflect.Modifier;
21
22 import org.apache.commons.lang3.ClassUtils;
23
24 /**
25 * Contains common code for working with Methods/Constructors, extracted and
26 * refactored from <code>MethodUtils</code> when it was imported from Commons
27 * BeanUtils.
28 *
29 * @since 2.5
30 * @version $Id: MemberUtils.java 1143537 2011-07-06 19:30:22Z joehni $
31 */
32 abstract class MemberUtils {
33 // TODO extract an interface to implement compareParameterSets(...)?
34
35 private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
36
37 /** Array of primitive number types ordered by "promotability" */
38 private static final Class<?>[] ORDERED_PRIMITIVE_TYPES = { Byte.TYPE, Short.TYPE,
39 Character.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE };
40
41 /**
42 * XXX Default access superclass workaround
43 *
44 * When a public class has a default access superclass with public members,
45 * these members are accessible. Calling them from compiled code works fine.
46 * Unfortunately, on some JVMs, using reflection to invoke these members
47 * seems to (wrongly) prevent access even when the modifier is public.
48 * Calling setAccessible(true) solves the problem but will only work from
49 * sufficiently privileged code. Better workarounds would be gratefully
50 * accepted.
51 * @param o the AccessibleObject to set as accessible
52 */
53 static void setAccessibleWorkaround(AccessibleObject o) {
54 if (o == null || o.isAccessible()) {
55 return;
56 }
57 Member m = (Member) o;
58 if (Modifier.isPublic(m.getModifiers())
59 && isPackageAccess(m.getDeclaringClass().getModifiers())) {
60 try {
61 o.setAccessible(true);
62 } catch (SecurityException e) { // NOPMD
63 // ignore in favor of subsequent IllegalAccessException
64 }
65 }
66 }
67
68 /**
69 * Returns whether a given set of modifiers implies package access.
70 * @param modifiers to test
71 * @return true unless package/protected/private modifier detected
72 */
73 static boolean isPackageAccess(int modifiers) {
74 return (modifiers & ACCESS_TEST) == 0;
75 }
76
77 /**
78 * Returns whether a Member is accessible.
79 * @param m Member to check
80 * @return true if <code>m</code> is accessible
81 */
82 static boolean isAccessible(Member m) {
83 return m != null && Modifier.isPublic(m.getModifiers()) && !m.isSynthetic();
84 }
85
86 /**
87 * Compares the relative fitness of two sets of parameter types in terms of
88 * matching a third set of runtime parameter types, such that a list ordered
89 * by the results of the comparison would return the best match first
90 * (least).
91 *
92 * @param left the "left" parameter set
93 * @param right the "right" parameter set
94 * @param actual the runtime parameter types to match against
95 * <code>left</code>/<code>right</code>
96 * @return int consistent with <code>compare</code> semantics
97 */
98 static int compareParameterTypes(Class<?>[] left, Class<?>[] right, Class<?>[] actual) {
99 float leftCost = getTotalTransformationCost(actual, left);
100 float rightCost = getTotalTransformationCost(actual, right);
101 return leftCost < rightCost ? -1 : rightCost < leftCost ? 1 : 0;
102 }
103
104 /**
105 * Returns the sum of the object transformation cost for each class in the
106 * source argument list.
107 * @param srcArgs The source arguments
108 * @param destArgs The destination arguments
109 * @return The total transformation cost
110 */
111 private static float getTotalTransformationCost(Class<?>[] srcArgs, Class<?>[] destArgs) {
112 float totalCost = 0.0f;
113 for (int i = 0; i < srcArgs.length; i++) {
114 Class<?> srcClass, destClass;
115 srcClass = srcArgs[i];
116 destClass = destArgs[i];
117 totalCost += getObjectTransformationCost(srcClass, destClass);
118 }
119 return totalCost;
120 }
121
122 /**
123 * Gets the number of steps required needed to turn the source class into
124 * the destination class. This represents the number of steps in the object
125 * hierarchy graph.
126 * @param srcClass The source class
127 * @param destClass The destination class
128 * @return The cost of transforming an object
129 */
130 private static float getObjectTransformationCost(Class<?> srcClass, Class<?> destClass) {
131 if (destClass.isPrimitive()) {
132 return getPrimitivePromotionCost(srcClass, destClass);
133 }
134 float cost = 0.0f;
135 while (srcClass != null && !destClass.equals(srcClass)) {
136 if (destClass.isInterface() && ClassUtils.isAssignable(srcClass, destClass)) {
137 // slight penalty for interface match.
138 // we still want an exact match to override an interface match,
139 // but
140 // an interface match should override anything where we have to
141 // get a superclass.
142 cost += 0.25f;
143 break;
144 }
145 cost++;
146 srcClass = srcClass.getSuperclass();
147 }
148 /*
149 * If the destination class is null, we've travelled all the way up to
150 * an Object match. We'll penalize this by adding 1.5 to the cost.
151 */
152 if (srcClass == null) {
153 cost += 1.5f;
154 }
155 return cost;
156 }
157
158 /**
159 * Gets the number of steps required to promote a primitive number to another
160 * type.
161 * @param srcClass the (primitive) source class
162 * @param destClass the (primitive) destination class
163 * @return The cost of promoting the primitive
164 */
165 private static float getPrimitivePromotionCost(final Class<?> srcClass, final Class<?> destClass) {
166 float cost = 0.0f;
167 Class<?> cls = srcClass;
168 if (!cls.isPrimitive()) {
169 // slight unwrapping penalty
170 cost += 0.1f;
171 cls = ClassUtils.wrapperToPrimitive(cls);
172 }
173 for (int i = 0; cls != destClass && i < ORDERED_PRIMITIVE_TYPES.length; i++) {
174 if (cls == ORDERED_PRIMITIVE_TYPES[i]) {
175 cost += 0.1f;
176 if (i < ORDERED_PRIMITIVE_TYPES.length - 1) {
177 cls = ORDERED_PRIMITIVE_TYPES[i + 1];
178 }
179 }
180 }
181 return cost;
182 }
183
184 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect;
17
18 import java.lang.reflect.InvocationTargetException;
19 import java.lang.reflect.Method;
20 import java.lang.reflect.Modifier;
21
22 import org.apache.commons.lang3.ArrayUtils;
23 import org.apache.commons.lang3.ClassUtils;
24
25 /**
26 * <p>Utility reflection methods focused on methods, originally from Commons BeanUtils.
27 * Differences from the BeanUtils version may be noted, especially where similar functionality
28 * already existed within Lang.
29 * </p>
30 *
31 * <h3>Known Limitations</h3>
32 * <h4>Accessing Public Methods In A Default Access Superclass</h4>
33 * <p>There is an issue when invoking public methods contained in a default access superclass on JREs prior to 1.4.
34 * Reflection locates these methods fine and correctly assigns them as public.
35 * However, an <code>IllegalAccessException</code> is thrown if the method is invoked.</p>
36 *
37 * <p><code>MethodUtils</code> contains a workaround for this situation.
38 * It will attempt to call <code>setAccessible</code> on this method.
39 * If this call succeeds, then the method can be invoked as normal.
40 * This call will only succeed when the application has sufficient security privileges.
41 * If this call fails then the method may fail.</p>
42 *
43 * @since 2.5
44 * @version $Id: MethodUtils.java 1153241 2011-08-02 18:49:52Z ggregory $
45 */
46 public class MethodUtils {
47
48 /**
49 * <p>MethodUtils instances should NOT be constructed in standard programming.
50 * Instead, the class should be used as
51 * <code>MethodUtils.getAccessibleMethod(method)</code>.</p>
52 *
53 * <p>This constructor is public to permit tools that require a JavaBean
54 * instance to operate.</p>
55 */
56 public MethodUtils() {
57 super();
58 }
59
60 /**
61 * <p>Invokes a named method whose parameter type matches the object type.</p>
62 *
63 * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
64 *
65 * <p>This method supports calls to methods taking primitive parameters
66 * via passing in wrapping classes. So, for example, a <code>Boolean</code> object
67 * would match a <code>boolean</code> primitive.</p>
68 *
69 * <p>This is a convenient wrapper for
70 * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}.
71 * </p>
72 *
73 * @param object invoke method on this object
74 * @param methodName get method with this name
75 * @param args use these arguments - treat null as empty array
76 * @return The value returned by the invoked method
77 *
78 * @throws NoSuchMethodException if there is no such accessible method
79 * @throws InvocationTargetException wraps an exception thrown by the method invoked
80 * @throws IllegalAccessException if the requested method is not accessible via reflection
81 */
82 public static Object invokeMethod(Object object, String methodName,
83 Object... args) throws NoSuchMethodException,
84 IllegalAccessException, InvocationTargetException {
85 if (args == null) {
86 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
87 }
88 int arguments = args.length;
89 Class<?>[] parameterTypes = new Class[arguments];
90 for (int i = 0; i < arguments; i++) {
91 parameterTypes[i] = args[i].getClass();
92 }
93 return invokeMethod(object, methodName, args, parameterTypes);
94 }
95
96 /**
97 * <p>Invokes a named method whose parameter type matches the object type.</p>
98 *
99 * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
100 *
101 * <p>This method supports calls to methods taking primitive parameters
102 * via passing in wrapping classes. So, for example, a <code>Boolean</code> object
103 * would match a <code>boolean</code> primitive.</p>
104 *
105 * @param object invoke method on this object
106 * @param methodName get method with this name
107 * @param args use these arguments - treat null as empty array
108 * @param parameterTypes match these parameters - treat null as empty array
109 * @return The value returned by the invoked method
110 *
111 * @throws NoSuchMethodException if there is no such accessible method
112 * @throws InvocationTargetException wraps an exception thrown by the method invoked
113 * @throws IllegalAccessException if the requested method is not accessible via reflection
114 */
115 public static Object invokeMethod(Object object, String methodName,
116 Object[] args, Class<?>[] parameterTypes)
117 throws NoSuchMethodException, IllegalAccessException,
118 InvocationTargetException {
119 if (parameterTypes == null) {
120 parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
121 }
122 if (args == null) {
123 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
124 }
125 Method method = getMatchingAccessibleMethod(object.getClass(),
126 methodName, parameterTypes);
127 if (method == null) {
128 throw new NoSuchMethodException("No such accessible method: "
129 + methodName + "() on object: "
130 + object.getClass().getName());
131 }
132 return method.invoke(object, args);
133 }
134
135 /**
136 * <p>Invokes a method whose parameter types match exactly the object
137 * types.</p>
138 *
139 * <p>This uses reflection to invoke the method obtained from a call to
140 * <code>getAccessibleMethod()</code>.</p>
141 *
142 * @param object invoke method on this object
143 * @param methodName get method with this name
144 * @param args use these arguments - treat null as empty array
145 * @return The value returned by the invoked method
146 *
147 * @throws NoSuchMethodException if there is no such accessible method
148 * @throws InvocationTargetException wraps an exception thrown by the
149 * method invoked
150 * @throws IllegalAccessException if the requested method is not accessible
151 * via reflection
152 */
153 public static Object invokeExactMethod(Object object, String methodName,
154 Object... args) throws NoSuchMethodException,
155 IllegalAccessException, InvocationTargetException {
156 if (args == null) {
157 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
158 }
159 int arguments = args.length;
160 Class<?>[] parameterTypes = new Class[arguments];
161 for (int i = 0; i < arguments; i++) {
162 parameterTypes[i] = args[i].getClass();
163 }
164 return invokeExactMethod(object, methodName, args, parameterTypes);
165 }
166
167 /**
168 * <p>Invokes a method whose parameter types match exactly the parameter
169 * types given.</p>
170 *
171 * <p>This uses reflection to invoke the method obtained from a call to
172 * <code>getAccessibleMethod()</code>.</p>
173 *
174 * @param object invoke method on this object
175 * @param methodName get method with this name
176 * @param args use these arguments - treat null as empty array
177 * @param parameterTypes match these parameters - treat null as empty array
178 * @return The value returned by the invoked method
179 *
180 * @throws NoSuchMethodException if there is no such accessible method
181 * @throws InvocationTargetException wraps an exception thrown by the
182 * method invoked
183 * @throws IllegalAccessException if the requested method is not accessible
184 * via reflection
185 */
186 public static Object invokeExactMethod(Object object, String methodName,
187 Object[] args, Class<?>[] parameterTypes)
188 throws NoSuchMethodException, IllegalAccessException,
189 InvocationTargetException {
190 if (args == null) {
191 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
192 }
193 if (parameterTypes == null) {
194 parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
195 }
196 Method method = getAccessibleMethod(object.getClass(), methodName,
197 parameterTypes);
198 if (method == null) {
199 throw new NoSuchMethodException("No such accessible method: "
200 + methodName + "() on object: "
201 + object.getClass().getName());
202 }
203 return method.invoke(object, args);
204 }
205
206 /**
207 * <p>Invokes a static method whose parameter types match exactly the parameter
208 * types given.</p>
209 *
210 * <p>This uses reflection to invoke the method obtained from a call to
211 * {@link #getAccessibleMethod(Class, String, Class[])}.</p>
212 *
213 * @param cls invoke static method on this class
214 * @param methodName get method with this name
215 * @param args use these arguments - treat null as empty array
216 * @param parameterTypes match these parameters - treat null as empty array
217 * @return The value returned by the invoked method
218 *
219 * @throws NoSuchMethodException if there is no such accessible method
220 * @throws InvocationTargetException wraps an exception thrown by the
221 * method invoked
222 * @throws IllegalAccessException if the requested method is not accessible
223 * via reflection
224 */
225 public static Object invokeExactStaticMethod(Class<?> cls, String methodName,
226 Object[] args, Class<?>[] parameterTypes)
227 throws NoSuchMethodException, IllegalAccessException,
228 InvocationTargetException {
229 if (args == null) {
230 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
231 }
232 if (parameterTypes == null) {
233 parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
234 }
235 Method method = getAccessibleMethod(cls, methodName, parameterTypes);
236 if (method == null) {
237 throw new NoSuchMethodException("No such accessible method: "
238 + methodName + "() on class: " + cls.getName());
239 }
240 return method.invoke(null, args);
241 }
242
243 /**
244 * <p>Invokes a named static method whose parameter type matches the object type.</p>
245 *
246 * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
247 *
248 * <p>This method supports calls to methods taking primitive parameters
249 * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
250 * would match a <code>boolean</code> primitive.</p>
251 *
252 * <p>This is a convenient wrapper for
253 * {@link #invokeStaticMethod(Class objectClass,String methodName,Object [] args,Class[] parameterTypes)}.
254 * </p>
255 *
256 * @param cls invoke static method on this class
257 * @param methodName get method with this name
258 * @param args use these arguments - treat null as empty array
259 * @return The value returned by the invoked method
260 *
261 * @throws NoSuchMethodException if there is no such accessible method
262 * @throws InvocationTargetException wraps an exception thrown by the
263 * method invoked
264 * @throws IllegalAccessException if the requested method is not accessible
265 * via reflection
266 */
267 public static Object invokeStaticMethod(Class<?> cls, String methodName,
268 Object... args) throws NoSuchMethodException,
269 IllegalAccessException, InvocationTargetException {
270 if (args == null) {
271 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
272 }
273 int arguments = args.length;
274 Class<?>[] parameterTypes = new Class[arguments];
275 for (int i = 0; i < arguments; i++) {
276 parameterTypes[i] = args[i].getClass();
277 }
278 return invokeStaticMethod(cls, methodName, args, parameterTypes);
279 }
280
281 /**
282 * <p>Invokes a named static method whose parameter type matches the object type.</p>
283 *
284 * <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
285 *
286 * <p>This method supports calls to methods taking primitive parameters
287 * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
288 * would match a <code>boolean</code> primitive.</p>
289 *
290 *
291 * @param cls invoke static method on this class
292 * @param methodName get method with this name
293 * @param args use these arguments - treat null as empty array
294 * @param parameterTypes match these parameters - treat null as empty array
295 * @return The value returned by the invoked method
296 *
297 * @throws NoSuchMethodException if there is no such accessible method
298 * @throws InvocationTargetException wraps an exception thrown by the
299 * method invoked
300 * @throws IllegalAccessException if the requested method is not accessible
301 * via reflection
302 */
303 public static Object invokeStaticMethod(Class<?> cls, String methodName,
304 Object[] args, Class<?>[] parameterTypes)
305 throws NoSuchMethodException, IllegalAccessException,
306 InvocationTargetException {
307 if (parameterTypes == null) {
308 parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
309 }
310 if (args == null) {
311 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
312 }
313 Method method = getMatchingAccessibleMethod(cls, methodName,
314 parameterTypes);
315 if (method == null) {
316 throw new NoSuchMethodException("No such accessible method: "
317 + methodName + "() on class: " + cls.getName());
318 }
319 return method.invoke(null, args);
320 }
321
322 /**
323 * <p>Invokes a static method whose parameter types match exactly the object
324 * types.</p>
325 *
326 * <p>This uses reflection to invoke the method obtained from a call to
327 * {@link #getAccessibleMethod(Class, String, Class[])}.</p>
328 *
329 * @param cls invoke static method on this class
330 * @param methodName get method with this name
331 * @param args use these arguments - treat null as empty array
332 * @return The value returned by the invoked method
333 *
334 * @throws NoSuchMethodException if there is no such accessible method
335 * @throws InvocationTargetException wraps an exception thrown by the
336 * method invoked
337 * @throws IllegalAccessException if the requested method is not accessible
338 * via reflection
339 */
340 public static Object invokeExactStaticMethod(Class<?> cls, String methodName,
341 Object... args) throws NoSuchMethodException,
342 IllegalAccessException, InvocationTargetException {
343 if (args == null) {
344 args = ArrayUtils.EMPTY_OBJECT_ARRAY;
345 }
346 int arguments = args.length;
347 Class<?>[] parameterTypes = new Class[arguments];
348 for (int i = 0; i < arguments; i++) {
349 parameterTypes[i] = args[i].getClass();
350 }
351 return invokeExactStaticMethod(cls, methodName, args, parameterTypes);
352 }
353
354 /**
355 * <p>Returns an accessible method (that is, one that can be invoked via
356 * reflection) with given name and parameters. If no such method
357 * can be found, return <code>null</code>.
358 * This is just a convenient wrapper for
359 * {@link #getAccessibleMethod(Method method)}.</p>
360 *
361 * @param cls get method from this class
362 * @param methodName get method with this name
363 * @param parameterTypes with these parameters types
364 * @return The accessible method
365 */
366 public static Method getAccessibleMethod(Class<?> cls, String methodName,
367 Class<?>... parameterTypes) {
368 try {
369 return getAccessibleMethod(cls.getMethod(methodName,
370 parameterTypes));
371 } catch (NoSuchMethodException e) {
372 return null;
373 }
374 }
375
376 /**
377 * <p>Returns an accessible method (that is, one that can be invoked via
378 * reflection) that implements the specified Method. If no such method
379 * can be found, return <code>null</code>.</p>
380 *
381 * @param method The method that we wish to call
382 * @return The accessible method
383 */
384 public static Method getAccessibleMethod(Method method) {
385 if (!MemberUtils.isAccessible(method)) {
386 return null;
387 }
388 // If the declaring class is public, we are done
389 Class<?> cls = method.getDeclaringClass();
390 if (Modifier.isPublic(cls.getModifiers())) {
391 return method;
392 }
393 String methodName = method.getName();
394 Class<?>[] parameterTypes = method.getParameterTypes();
395
396 // Check the implemented interfaces and subinterfaces
397 method = getAccessibleMethodFromInterfaceNest(cls, methodName,
398 parameterTypes);
399
400 // Check the superclass chain
401 if (method == null) {
402 method = getAccessibleMethodFromSuperclass(cls, methodName,
403 parameterTypes);
404 }
405 return method;
406 }
407
408 /**
409 * <p>Returns an accessible method (that is, one that can be invoked via
410 * reflection) by scanning through the superclasses. If no such method
411 * can be found, return <code>null</code>.</p>
412 *
413 * @param cls Class to be checked
414 * @param methodName Method name of the method we wish to call
415 * @param parameterTypes The parameter type signatures
416 * @return the accessible method or <code>null</code> if not found
417 */
418 private static Method getAccessibleMethodFromSuperclass(Class<?> cls,
419 String methodName, Class<?>... parameterTypes) {
420 Class<?> parentClass = cls.getSuperclass();
421 while (parentClass != null) {
422 if (Modifier.isPublic(parentClass.getModifiers())) {
423 try {
424 return parentClass.getMethod(methodName, parameterTypes);
425 } catch (NoSuchMethodException e) {
426 return null;
427 }
428 }
429 parentClass = parentClass.getSuperclass();
430 }
431 return null;
432 }
433
434 /**
435 * <p>Returns an accessible method (that is, one that can be invoked via
436 * reflection) that implements the specified method, by scanning through
437 * all implemented interfaces and subinterfaces. If no such method
438 * can be found, return <code>null</code>.</p>
439 *
440 * <p>There isn't any good reason why this method must be private.
441 * It is because there doesn't seem any reason why other classes should
442 * call this rather than the higher level methods.</p>
443 *
444 * @param cls Parent class for the interfaces to be checked
445 * @param methodName Method name of the method we wish to call
446 * @param parameterTypes The parameter type signatures
447 * @return the accessible method or <code>null</code> if not found
448 */
449 private static Method getAccessibleMethodFromInterfaceNest(Class<?> cls,
450 String methodName, Class<?>... parameterTypes) {
451 Method method = null;
452
453 // Search up the superclass chain
454 for (; cls != null; cls = cls.getSuperclass()) {
455
456 // Check the implemented interfaces of the parent class
457 Class<?>[] interfaces = cls.getInterfaces();
458 for (int i = 0; i < interfaces.length; i++) {
459 // Is this interface public?
460 if (!Modifier.isPublic(interfaces[i].getModifiers())) {
461 continue;
462 }
463 // Does the method exist on this interface?
464 try {
465 method = interfaces[i].getDeclaredMethod(methodName,
466 parameterTypes);
467 } catch (NoSuchMethodException e) { // NOPMD
468 /*
469 * Swallow, if no method is found after the loop then this
470 * method returns null.
471 */
472 }
473 if (method != null) {
474 break;
475 }
476 // Recursively check our parent interfaces
477 method = getAccessibleMethodFromInterfaceNest(interfaces[i],
478 methodName, parameterTypes);
479 if (method != null) {
480 break;
481 }
482 }
483 }
484 return method;
485 }
486
487 /**
488 * <p>Finds an accessible method that matches the given name and has compatible parameters.
489 * Compatible parameters mean that every method parameter is assignable from
490 * the given parameters.
491 * In other words, it finds a method with the given name
492 * that will take the parameters given.<p>
493 *
494 * <p>This method is used by
495 * {@link
496 * #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}.
497 *
498 * <p>This method can match primitive parameter by passing in wrapper classes.
499 * For example, a <code>Boolean</code> will match a primitive <code>boolean</code>
500 * parameter.
501 *
502 * @param cls find method in this class
503 * @param methodName find method with this name
504 * @param parameterTypes find method with most compatible parameters
505 * @return The accessible method
506 */
507 public static Method getMatchingAccessibleMethod(Class<?> cls,
508 String methodName, Class<?>... parameterTypes) {
509 try {
510 Method method = cls.getMethod(methodName, parameterTypes);
511 MemberUtils.setAccessibleWorkaround(method);
512 return method;
513 } catch (NoSuchMethodException e) { // NOPMD - Swallow the exception
514 }
515 // search through all methods
516 Method bestMatch = null;
517 Method[] methods = cls.getMethods();
518 for (Method method : methods) {
519 // compare name and parameters
520 if (method.getName().equals(methodName) && ClassUtils.isAssignable(parameterTypes, method.getParameterTypes(), true)) {
521 // get accessible version of method
522 Method accessibleMethod = getAccessibleMethod(method);
523 if (accessibleMethod != null && (bestMatch == null || MemberUtils.compareParameterTypes(
524 accessibleMethod.getParameterTypes(),
525 bestMatch.getParameterTypes(),
526 parameterTypes) < 0)) {
527 bestMatch = accessibleMethod;
528 }
529 }
530 }
531 if (bestMatch != null) {
532 MemberUtils.setAccessibleWorkaround(bestMatch);
533 }
534 return bestMatch;
535 }
536 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect;
17
18 import java.lang.reflect.Array;
19 import java.lang.reflect.GenericArrayType;
20 import java.lang.reflect.ParameterizedType;
21 import java.lang.reflect.Type;
22 import java.lang.reflect.TypeVariable;
23 import java.lang.reflect.WildcardType;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30
31 import org.apache.commons.lang3.ClassUtils;
32
33 /**
34 * <p> Utility methods focusing on type inspection, particularly with regard to
35 * generics. </p>
36 *
37 * @since 3.0
38 * @version $Id: TypeUtils.java 1144929 2011-07-10 18:26:16Z ggregory $
39 */
40 public class TypeUtils {
41
42 /**
43 * <p> TypeUtils instances should NOT be constructed in standard
44 * programming. Instead, the class should be used as
45 * <code>TypeUtils.isAssignable(cls, toClass)</code>. </p> <p> This
46 * constructor is public to permit tools that require a JavaBean instance to
47 * operate. </p>
48 */
49 public TypeUtils() {
50 super();
51 }
52
53 /**
54 * <p> Checks if the subject type may be implicitly cast to the target type
55 * following the Java generics rules. If both types are {@link Class}
56 * objects, the method returns the result of
57 * {@link ClassUtils#isAssignable(Class, Class)}. </p>
58 *
59 * @param type the subject type to be assigned to the target type
60 * @param toType the target type
61 * @return <code>true</code> if <code>type</code> is assignable to <code>toType</code>.
62 */
63 public static boolean isAssignable(Type type, Type toType) {
64 return isAssignable(type, toType, null);
65 }
66
67 /**
68 * <p> Checks if the subject type may be implicitly cast to the target type
69 * following the Java generics rules. </p>
70 *
71 * @param type the subject type to be assigned to the target type
72 * @param toType the target type
73 * @param typeVarAssigns optional map of type variable assignments
74 * @return <code>true</code> if <code>type</code> is assignable to <code>toType</code>.
75 */
76 private static boolean isAssignable(Type type, Type toType,
77 Map<TypeVariable<?>, Type> typeVarAssigns) {
78 if (toType == null || toType instanceof Class<?>) {
79 return isAssignable(type, (Class<?>) toType);
80 }
81
82 if (toType instanceof ParameterizedType) {
83 return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
84 }
85
86 if (toType instanceof GenericArrayType) {
87 return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
88 }
89
90 if (toType instanceof WildcardType) {
91 return isAssignable(type, (WildcardType) toType, typeVarAssigns);
92 }
93
94 // *
95 if (toType instanceof TypeVariable<?>) {
96 return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
97 }
98 // */
99
100 throw new IllegalStateException("found an unhandled type: " + toType);
101 }
102
103 /**
104 * <p> Checks if the subject type may be implicitly cast to the target class
105 * following the Java generics rules. </p>
106 *
107 * @param type the subject type to be assigned to the target type
108 * @param toClass the target class
109 * @return true if <code>type</code> is assignable to <code>toClass</code>.
110 */
111 private static boolean isAssignable(Type type, Class<?> toClass) {
112 if (type == null) {
113 // consistency with ClassUtils.isAssignable() behavior
114 return toClass == null || !toClass.isPrimitive();
115 }
116
117 // only a null type can be assigned to null type which
118 // would have cause the previous to return true
119 if (toClass == null) {
120 return false;
121 }
122
123 // all types are assignable to themselves
124 if (toClass.equals(type)) {
125 return true;
126 }
127
128 if (type instanceof Class<?>) {
129 // just comparing two classes
130 return ClassUtils.isAssignable((Class<?>) type, toClass);
131 }
132
133 if (type instanceof ParameterizedType) {
134 // only have to compare the raw type to the class
135 return isAssignable(getRawType((ParameterizedType) type), toClass);
136 }
137
138 // *
139 if (type instanceof TypeVariable<?>) {
140 // if any of the bounds are assignable to the class, then the
141 // type is assignable to the class.
142 for (Type bound : ((TypeVariable<?>) type).getBounds()) {
143 if (isAssignable(bound, toClass)) {
144 return true;
145 }
146 }
147
148 return false;
149 }
150
151 // the only classes to which a generic array type can be assigned
152 // are class Object and array classes
153 if (type instanceof GenericArrayType) {
154 return toClass.equals(Object.class)
155 || toClass.isArray()
156 && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
157 .getComponentType());
158 }
159
160 // wildcard types are not assignable to a class (though one would think
161 // "? super Object" would be assignable to Object)
162 if (type instanceof WildcardType) {
163 return false;
164 }
165
166 throw new IllegalStateException("found an unhandled type: " + type);
167 }
168
169 /**
170 * <p> Checks if the subject type may be implicitly cast to the target
171 * parameterized type following the Java generics rules. </p>
172 *
173 * @param type the subject type to be assigned to the target type
174 * @param toParameterizedType the target parameterized type
175 * @param typeVarAssigns a map with type variables
176 * @return true if <code>type</code> is assignable to <code>toType</code>.
177 */
178 private static boolean isAssignable(Type type, ParameterizedType toParameterizedType,
179 Map<TypeVariable<?>, Type> typeVarAssigns) {
180 if (type == null) {
181 return true;
182 }
183
184 // only a null type can be assigned to null type which
185 // would have cause the previous to return true
186 if (toParameterizedType == null) {
187 return false;
188 }
189
190 // all types are assignable to themselves
191 if (toParameterizedType.equals(type)) {
192 return true;
193 }
194
195 // get the target type's raw type
196 Class<?> toClass = getRawType(toParameterizedType);
197 // get the subject type's type arguments including owner type arguments
198 // and supertype arguments up to and including the target class.
199 Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
200
201 // null means the two types are not compatible
202 if (fromTypeVarAssigns == null) {
203 return false;
204 }
205
206 // compatible types, but there's no type arguments. this is equivalent
207 // to comparing Map< ?, ? > to Map, and raw types are always assignable
208 // to parameterized types.
209 if (fromTypeVarAssigns.isEmpty()) {
210 return true;
211 }
212
213 // get the target type's type arguments including owner type arguments
214 Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
215 toClass, typeVarAssigns);
216
217 // now to check each type argument
218 for (Map.Entry<TypeVariable<?>, Type> entry : toTypeVarAssigns.entrySet()) {
219 Type toTypeArg = entry.getValue();
220 Type fromTypeArg = fromTypeVarAssigns.get(entry.getKey());
221
222 // parameters must either be absent from the subject type, within
223 // the bounds of the wildcard type, or be an exact match to the
224 // parameters of the target type.
225 if (fromTypeArg != null
226 && !toTypeArg.equals(fromTypeArg)
227 && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg,
228 typeVarAssigns))) {
229 return false;
230 }
231 }
232
233 return true;
234 }
235
236 /**
237 * <p> Checks if the subject type may be implicitly cast to the target
238 * generic array type following the Java generics rules. </p>
239 *
240 * @param type the subject type to be assigned to the target type
241 * @param toGenericArrayType the target generic array type
242 * @param typeVarAssigns a map with type variables
243 * @return true if <code>type</code> is assignable to
244 * <code>toGenericArrayType</code>.
245 */
246 private static boolean isAssignable(Type type, GenericArrayType toGenericArrayType,
247 Map<TypeVariable<?>, Type> typeVarAssigns) {
248 if (type == null) {
249 return true;
250 }
251
252 // only a null type can be assigned to null type which
253 // would have cause the previous to return true
254 if (toGenericArrayType == null) {
255 return false;
256 }
257
258 // all types are assignable to themselves
259 if (toGenericArrayType.equals(type)) {
260 return true;
261 }
262
263 Type toComponentType = toGenericArrayType.getGenericComponentType();
264
265 if (type instanceof Class<?>) {
266 Class<?> cls = (Class<?>) type;
267
268 // compare the component types
269 return cls.isArray()
270 && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
271 }
272
273 if (type instanceof GenericArrayType) {
274 // compare the component types
275 return isAssignable(((GenericArrayType) type).getGenericComponentType(),
276 toComponentType, typeVarAssigns);
277 }
278
279 if (type instanceof WildcardType) {
280 // so long as one of the upper bounds is assignable, it's good
281 for (Type bound : getImplicitUpperBounds((WildcardType) type)) {
282 if (isAssignable(bound, toGenericArrayType)) {
283 return true;
284 }
285 }
286
287 return false;
288 }
289
290 if (type instanceof TypeVariable<?>) {
291 // probably should remove the following logic and just return false.
292 // type variables cannot specify arrays as bounds.
293 for (Type bound : getImplicitBounds((TypeVariable<?>) type)) {
294 if (isAssignable(bound, toGenericArrayType)) {
295 return true;
296 }
297 }
298
299 return false;
300 }
301
302 if (type instanceof ParameterizedType) {
303 // the raw type of a parameterized type is never an array or
304 // generic array, otherwise the declaration would look like this:
305 // Collection[]< ? extends String > collection;
306 return false;
307 }
308
309 throw new IllegalStateException("found an unhandled type: " + type);
310 }
311
312 /**
313 * <p> Checks if the subject type may be implicitly cast to the target
314 * wildcard type following the Java generics rules. </p>
315 *
316 * @param type the subject type to be assigned to the target type
317 * @param toWildcardType the target wildcard type
318 * @param typeVarAssigns a map with type variables
319 * @return true if <code>type</code> is assignable to
320 * <code>toWildcardType</code>.
321 */
322 private static boolean isAssignable(Type type, WildcardType toWildcardType,
323 Map<TypeVariable<?>, Type> typeVarAssigns) {
324 if (type == null) {
325 return true;
326 }
327
328 // only a null type can be assigned to null type which
329 // would have cause the previous to return true
330 if (toWildcardType == null) {
331 return false;
332 }
333
334 // all types are assignable to themselves
335 if (toWildcardType.equals(type)) {
336 return true;
337 }
338
339 Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
340 Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
341
342 if (type instanceof WildcardType) {
343 WildcardType wildcardType = (WildcardType) type;
344 Type[] upperBounds = getImplicitUpperBounds(wildcardType);
345 Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
346
347 for (Type toBound : toUpperBounds) {
348 // if there are assignments for unresolved type variables,
349 // now's the time to substitute them.
350 toBound = substituteTypeVariables(toBound, typeVarAssigns);
351
352 // each upper bound of the subject type has to be assignable to
353 // each
354 // upper bound of the target type
355 for (Type bound : upperBounds) {
356 if (!isAssignable(bound, toBound, typeVarAssigns)) {
357 return false;
358 }
359 }
360 }
361
362 for (Type toBound : toLowerBounds) {
363 // if there are assignments for unresolved type variables,
364 // now's the time to substitute them.
365 toBound = substituteTypeVariables(toBound, typeVarAssigns);
366
367 // each lower bound of the target type has to be assignable to
368 // each
369 // lower bound of the subject type
370 for (Type bound : lowerBounds) {
371 if (!isAssignable(toBound, bound, typeVarAssigns)) {
372 return false;
373 }
374 }
375 }
376
377 return true;
378 }
379
380 for (Type toBound : toUpperBounds) {
381 // if there are assignments for unresolved type variables,
382 // now's the time to substitute them.
383 if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
384 typeVarAssigns)) {
385 return false;
386 }
387 }
388
389 for (Type toBound : toLowerBounds) {
390 // if there are assignments for unresolved type variables,
391 // now's the time to substitute them.
392 if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
393 typeVarAssigns)) {
394 return false;
395 }
396 }
397
398 return true;
399 }
400
401 /**
402 * <p> Checks if the subject type may be implicitly cast to the target type
403 * variable following the Java generics rules. </p>
404 *
405 * @param type the subject type to be assigned to the target type
406 * @param toTypeVariable the target type variable
407 * @param typeVarAssigns a map with type variables
408 * @return true if <code>type</code> is assignable to
409 * <code>toTypeVariable</code>.
410 */
411 private static boolean isAssignable(Type type, TypeVariable<?> toTypeVariable,
412 Map<TypeVariable<?>, Type> typeVarAssigns) {
413 if (type == null) {
414 return true;
415 }
416
417 // only a null type can be assigned to null type which
418 // would have cause the previous to return true
419 if (toTypeVariable == null) {
420 return false;
421 }
422
423 // all types are assignable to themselves
424 if (toTypeVariable.equals(type)) {
425 return true;
426 }
427
428 if (type instanceof TypeVariable<?>) {
429 // a type variable is assignable to another type variable, if
430 // and only if the former is the latter, extends the latter, or
431 // is otherwise a descendant of the latter.
432 Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
433
434 for (Type bound : bounds) {
435 if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
436 return true;
437 }
438 }
439 }
440
441 if (type instanceof Class<?> || type instanceof ParameterizedType
442 || type instanceof GenericArrayType || type instanceof WildcardType) {
443 return false;
444 }
445
446 throw new IllegalStateException("found an unhandled type: " + type);
447 }
448
449 /**
450 * <p> </p>
451 *
452 * @param type the type to be replaced
453 * @param typeVarAssigns the map with type variables
454 * @return the replaced type
455 * @throws IllegalArgumentException if the type cannot be substituted
456 */
457 private static Type substituteTypeVariables(Type type, Map<TypeVariable<?>, Type> typeVarAssigns) {
458 if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
459 Type replacementType = typeVarAssigns.get(type);
460
461 if (replacementType == null) {
462 throw new IllegalArgumentException("missing assignment type for type variable "
463 + type);
464 }
465
466 return replacementType;
467 }
468
469 return type;
470 }
471
472 /**
473 * <p> Retrieves all the type arguments for this parameterized type
474 * including owner hierarchy arguments such as <code>
475 * Outer<K,V>.Inner<T>.DeepInner<E></code> . The arguments are returned in a
476 * {@link Map} specifying the argument type for each {@link TypeVariable}.
477 * </p>
478 *
479 * @param type specifies the subject parameterized type from which to
480 * harvest the parameters.
481 * @return a map of the type arguments to their respective type variables.
482 */
483 public static Map<TypeVariable<?>, Type> getTypeArguments(ParameterizedType type) {
484 return getTypeArguments(type, getRawType(type), null);
485 }
486
487 /**
488 * <p> Gets the type arguments of a class/interface based on a subtype. For
489 * instance, this method will determine that both of the parameters for the
490 * interface {@link Map} are {@link Object} for the subtype
491 * {@link java.util.Properties Properties} even though the subtype does not
492 * directly implement the <code>Map</code> interface. <p> </p> This method
493 * returns <code>null</code> if <code>type</code> is not assignable to
494 * <code>toClass</code>. It returns an empty map if none of the classes or
495 * interfaces in its inheritance hierarchy specify any type arguments. </p>
496 * <p> A side-effect of this method is that it also retrieves the type
497 * arguments for the classes and interfaces that are part of the hierarchy
498 * between <code>type</code> and <code>toClass</code>. So with the above
499 * example, this method will also determine that the type arguments for
500 * {@link java.util.Hashtable Hashtable} are also both <code>Object</code>.
501 * In cases where the interface specified by <code>toClass</code> is
502 * (indirectly) implemented more than once (e.g. where <code>toClass</code>
503 * specifies the interface {@link java.lang.Iterable Iterable} and
504 * <code>type</code> specifies a parameterized type that implements both
505 * {@link java.util.Set Set} and {@link java.util.Collection Collection}),
506 * this method will look at the inheritance hierarchy of only one of the
507 * implementations/subclasses; the first interface encountered that isn't a
508 * subinterface to one of the others in the <code>type</code> to
509 * <code>toClass</code> hierarchy. </p>
510 *
511 * @param type the type from which to determine the type parameters of
512 * <code>toClass</code>
513 * @param toClass the class whose type parameters are to be determined based
514 * on the subtype <code>type</code>
515 * @return a map of the type assignments for the type variables in each type
516 * in the inheritance hierarchy from <code>type</code> to
517 * <code>toClass</code> inclusive.
518 */
519 public static Map<TypeVariable<?>, Type> getTypeArguments(Type type, Class<?> toClass) {
520 return getTypeArguments(type, toClass, null);
521 }
522
523 /**
524 * <p> Return a map of the type arguments of <code>type</code> in the context of <code>toClass</code>. </p>
525 *
526 * @param type the type in question
527 * @param toClass the class
528 * @param subtypeVarAssigns a map with type variables
529 * @return the map with type arguments
530 */
531 private static Map<TypeVariable<?>, Type> getTypeArguments(Type type, Class<?> toClass,
532 Map<TypeVariable<?>, Type> subtypeVarAssigns) {
533 if (type instanceof Class<?>) {
534 return getTypeArguments((Class<?>) type, toClass, subtypeVarAssigns);
535 }
536
537 if (type instanceof ParameterizedType) {
538 return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns);
539 }
540
541 if (type instanceof GenericArrayType) {
542 return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass
543 .isArray() ? toClass.getComponentType() : toClass, subtypeVarAssigns);
544 }
545
546 // since wildcard types are not assignable to classes, should this just
547 // return null?
548 if (type instanceof WildcardType) {
549 for (Type bound : getImplicitUpperBounds((WildcardType) type)) {
550 // find the first bound that is assignable to the target class
551 if (isAssignable(bound, toClass)) {
552 return getTypeArguments(bound, toClass, subtypeVarAssigns);
553 }
554 }
555
556 return null;
557 }
558
559 // *
560 if (type instanceof TypeVariable<?>) {
561 for (Type bound : getImplicitBounds((TypeVariable<?>) type)) {
562 // find the first bound that is assignable to the target class
563 if (isAssignable(bound, toClass)) {
564 return getTypeArguments(bound, toClass, subtypeVarAssigns);
565 }
566 }
567
568 return null;
569 }
570 // */
571
572 throw new IllegalStateException("found an unhandled type: " + type);
573 }
574
575 /**
576 * <p> Return a map of the type arguments of a parameterized type in the context of <code>toClass</code>. </p>
577 *
578 * @param parameterizedType the parameterized type
579 * @param toClass the class
580 * @param subtypeVarAssigns a map with type variables
581 * @return the map with type arguments
582 */
583 private static Map<TypeVariable<?>, Type> getTypeArguments(
584 ParameterizedType parameterizedType, Class<?> toClass,
585 Map<TypeVariable<?>, Type> subtypeVarAssigns) {
586 Class<?> cls = getRawType(parameterizedType);
587
588 // make sure they're assignable
589 if (!isAssignable(cls, toClass)) {
590 return null;
591 }
592
593 Type ownerType = parameterizedType.getOwnerType();
594 Map<TypeVariable<?>, Type> typeVarAssigns;
595
596 if (ownerType instanceof ParameterizedType) {
597 // get the owner type arguments first
598 ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
599 typeVarAssigns = getTypeArguments(parameterizedOwnerType,
600 getRawType(parameterizedOwnerType), subtypeVarAssigns);
601 } else {
602 // no owner, prep the type variable assignments map
603 typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
604 : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
605 }
606
607 // get the subject parameterized type's arguments
608 Type[] typeArgs = parameterizedType.getActualTypeArguments();
609 // and get the corresponding type variables from the raw class
610 TypeVariable<?>[] typeParams = cls.getTypeParameters();
611
612 // map the arguments to their respective type variables
613 for (int i = 0; i < typeParams.length; i++) {
614 Type typeArg = typeArgs[i];
615 typeVarAssigns.put(typeParams[i], typeVarAssigns.containsKey(typeArg) ? typeVarAssigns
616 .get(typeArg) : typeArg);
617 }
618
619 if (toClass.equals(cls)) {
620 // target class has been reached. Done.
621 return typeVarAssigns;
622 }
623
624 // walk the inheritance hierarchy until the target class is reached
625 return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
626 }
627
628 /**
629 * <p> Return a map of the type arguments of a class in the context of <code>toClass</code>. </p>
630 *
631 * @param cls the class in question
632 * @param toClass the context class
633 * @param subtypeVarAssigns a map with type variables
634 * @return the map with type arguments
635 */
636 private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, Class<?> toClass,
637 Map<TypeVariable<?>, Type> subtypeVarAssigns) {
638 // make sure they're assignable
639 if (!isAssignable(cls, toClass)) {
640 return null;
641 }
642
643 // can't work with primitives
644 if (cls.isPrimitive()) {
645 // both classes are primitives?
646 if (toClass.isPrimitive()) {
647 // dealing with widening here. No type arguments to be
648 // harvested with these two types.
649 return new HashMap<TypeVariable<?>, Type>();
650 }
651
652 // work with wrapper the wrapper class instead of the primitive
653 cls = ClassUtils.primitiveToWrapper(cls);
654 }
655
656 // create a copy of the incoming map, or an empty one if it's null
657 HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
658 : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
659
660 // no arguments for the parameters, or target class has been reached
661 if (cls.getTypeParameters().length > 0 || toClass.equals(cls)) {
662 return typeVarAssigns;
663 }
664
665 // walk the inheritance hierarchy until the target class is reached
666 return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
667 }
668
669 /**
670 * <p> Tries to determine the type arguments of a class/interface based on a
671 * super parameterized type's type arguments. This method is the inverse of
672 * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
673 * type arguments based on a subtype. It is far more limited in determining
674 * the type arguments for the subject class's type variables in that it can
675 * only determine those parameters that map from the subject {@link Class}
676 * object to the supertype. </p> <p> Example: {@link java.util.TreeSet
677 * TreeSet} sets its parameter as the parameter for
678 * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
679 * parameter of {@link java.util.SortedSet}, which in turn sets the
680 * parameter of {@link Set}, which in turn sets the parameter of
681 * {@link java.util.Collection}, which in turn sets the parameter of
682 * {@link java.lang.Iterable}. Since <code>TreeSet</code>'s parameter maps
683 * (indirectly) to <code>Iterable</code>'s parameter, it will be able to
684 * determine that based on the super type <code>Iterable<? extends
685 * Map<Integer,? extends Collection<?>>></code>, the parameter of
686 * <code>TreeSet</code> is <code>? extends Map<Integer,? extends
687 * Collection<?>></code>. </p>
688 *
689 * @param cls the class whose type parameters are to be determined
690 * @param superType the super type from which <code>cls</code>'s type
691 * arguments are to be determined
692 * @return a map of the type assignments that could be determined for the
693 * type variables in each type in the inheritance hierarchy from
694 * <code>type</code> to <code>toClass</code> inclusive.
695 */
696 public static Map<TypeVariable<?>, Type> determineTypeArguments(Class<?> cls,
697 ParameterizedType superType) {
698 Class<?> superClass = getRawType(superType);
699
700 // compatibility check
701 if (!isAssignable(cls, superClass)) {
702 return null;
703 }
704
705 if (cls.equals(superClass)) {
706 return getTypeArguments(superType, superClass, null);
707 }
708
709 // get the next class in the inheritance hierarchy
710 Type midType = getClosestParentType(cls, superClass);
711
712 // can only be a class or a parameterized type
713 if (midType instanceof Class<?>) {
714 return determineTypeArguments((Class<?>) midType, superType);
715 }
716
717 ParameterizedType midParameterizedType = (ParameterizedType) midType;
718 Class<?> midClass = getRawType(midParameterizedType);
719 // get the type variables of the mid class that map to the type
720 // arguments of the super class
721 Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
722 // map the arguments of the mid type to the class type variables
723 mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
724
725 return typeVarAssigns;
726 }
727
728 /**
729 * <p>Performs a mapping of type variables.</p>
730 *
731 * @param <T> the generic type of the class in question
732 * @param cls the class in question
733 * @param parameterizedType the parameterized type
734 * @param typeVarAssigns the map to be filled
735 */
736 private static <T> void mapTypeVariablesToArguments(Class<T> cls,
737 ParameterizedType parameterizedType, Map<TypeVariable<?>, Type> typeVarAssigns) {
738 // capture the type variables from the owner type that have assignments
739 Type ownerType = parameterizedType.getOwnerType();
740
741 if (ownerType instanceof ParameterizedType) {
742 // recursion to make sure the owner's owner type gets processed
743 mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
744 }
745
746 // parameterizedType is a generic interface/class (or it's in the owner
747 // hierarchy of said interface/class) implemented/extended by the class
748 // cls. Find out which type variables of cls are type arguments of
749 // parameterizedType:
750 Type[] typeArgs = parameterizedType.getActualTypeArguments();
751
752 // of the cls's type variables that are arguments of parameterizedType,
753 // find out which ones can be determined from the super type's arguments
754 TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
755
756 // use List view of type parameters of cls so the contains() method can be used:
757 List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
758 .getTypeParameters());
759
760 for (int i = 0; i < typeArgs.length; i++) {
761 TypeVariable<?> typeVar = typeVars[i];
762 Type typeArg = typeArgs[i];
763
764 // argument of parameterizedType is a type variable of cls
765 if (typeVarList.contains(typeArg)
766 // type variable of parameterizedType has an assignment in
767 // the super type.
768 && typeVarAssigns.containsKey(typeVar)) {
769 // map the assignment to the cls's type variable
770 typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
771 }
772 }
773 }
774
775 /**
776 * <p> Closest parent type? Closest to what? The closest parent type to the
777 * super class specified by <code>superClass</code>. </p>
778 *
779 * @param cls the class in question
780 * @param superClass the super class
781 * @return the closes parent type
782 */
783 private static Type getClosestParentType(Class<?> cls, Class<?> superClass) {
784 // only look at the interfaces if the super class is also an interface
785 if (superClass.isInterface()) {
786 // get the generic interfaces of the subject class
787 Type[] interfaceTypes = cls.getGenericInterfaces();
788 // will hold the best generic interface match found
789 Type genericInterface = null;
790
791 // find the interface closest to the super class
792 for (Type midType : interfaceTypes) {
793 Class<?> midClass = null;
794
795 if (midType instanceof ParameterizedType) {
796 midClass = getRawType((ParameterizedType) midType);
797 } else if (midType instanceof Class<?>) {
798 midClass = (Class<?>) midType;
799 } else {
800 throw new IllegalStateException("Unexpected generic"
801 + " interface type found: " + midType);
802 }
803
804 // check if this interface is further up the inheritance chain
805 // than the previously found match
806 if (isAssignable(midClass, superClass)
807 && isAssignable(genericInterface, (Type) midClass)) {
808 genericInterface = midType;
809 }
810 }
811
812 // found a match?
813 if (genericInterface != null) {
814 return genericInterface;
815 }
816 }
817
818 // none of the interfaces were descendants of the target class, so the
819 // super class has to be one, instead
820 return cls.getGenericSuperclass();
821 }
822
823 /**
824 * <p> Checks if the given value can be assigned to the target type
825 * following the Java generics rules. </p>
826 *
827 * @param value the value to be checked
828 * @param type the target type
829 * @return true of <code>value</code> is an instance of <code>type</code>.
830 */
831 public static boolean isInstance(Object value, Type type) {
832 if (type == null) {
833 return false;
834 }
835
836 return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
837 : isAssignable(value.getClass(), type, null);
838 }
839
840 /**
841 * <p> This method strips out the redundant upper bound types in type
842 * variable types and wildcard types (or it would with wildcard types if
843 * multiple upper bounds were allowed). </p> <p> Example: with the variable
844 * type declaration:
845 *
846 * <pre> &lt;K extends java.util.Collection&lt;String&gt; &amp;
847 * java.util.List&lt;String&gt;&gt; </pre>
848 *
849 * since <code>List</code> is a subinterface of <code>Collection</code>,
850 * this method will return the bounds as if the declaration had been:
851 *
852 * <pre> &lt;K extends java.util.List&lt;String&gt;&gt; </pre>
853 *
854 * </p>
855 *
856 * @param bounds an array of types representing the upper bounds of either
857 * <code>WildcardType</code> or <code>TypeVariable</code>.
858 * @return an array containing the values from <code>bounds</code> minus the
859 * redundant types.
860 */
861 public static Type[] normalizeUpperBounds(Type[] bounds) {
862 // don't bother if there's only one (or none) type
863 if (bounds.length < 2) {
864 return bounds;
865 }
866
867 Set<Type> types = new HashSet<Type>(bounds.length);
868
869 for (Type type1 : bounds) {
870 boolean subtypeFound = false;
871
872 for (Type type2 : bounds) {
873 if (type1 != type2 && isAssignable(type2, type1, null)) {
874 subtypeFound = true;
875 break;
876 }
877 }
878
879 if (!subtypeFound) {
880 types.add(type1);
881 }
882 }
883
884 return types.toArray(new Type[types.size()]);
885 }
886
887 /**
888 * <p> Returns an array containing the sole type of {@link Object} if
889 * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
890 * returns the result of <code>TypeVariable.getBounds()</code> passed into
891 * {@link #normalizeUpperBounds}. </p>
892 *
893 * @param typeVariable the subject type variable
894 * @return a non-empty array containing the bounds of the type variable.
895 */
896 public static Type[] getImplicitBounds(TypeVariable<?> typeVariable) {
897 Type[] bounds = typeVariable.getBounds();
898
899 return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
900 }
901
902 /**
903 * <p> Returns an array containing the sole value of {@link Object} if
904 * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
905 * it returns the result of <code>WildcardType.getUpperBounds()</code>
906 * passed into {@link #normalizeUpperBounds}. </p>
907 *
908 * @param wildcardType the subject wildcard type
909 * @return a non-empty array containing the upper bounds of the wildcard
910 * type.
911 */
912 public static Type[] getImplicitUpperBounds(WildcardType wildcardType) {
913 Type[] bounds = wildcardType.getUpperBounds();
914
915 return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
916 }
917
918 /**
919 * <p> Returns an array containing a single value of <code>null</code> if
920 * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
921 * it returns the result of <code>WildcardType.getLowerBounds()</code>. </p>
922 *
923 * @param wildcardType the subject wildcard type
924 * @return a non-empty array containing the lower bounds of the wildcard
925 * type.
926 */
927 public static Type[] getImplicitLowerBounds(WildcardType wildcardType) {
928 Type[] bounds = wildcardType.getLowerBounds();
929
930 return bounds.length == 0 ? new Type[] { null } : bounds;
931 }
932
933 /**
934 * <p> Determines whether or not specified types satisfy the bounds of their
935 * mapped type variables. When a type parameter extends another (such as
936 * <code><T, S extends T></code>), uses another as a type parameter (such as
937 * <code><T, S extends Comparable<T></code>), or otherwise depends on
938 * another type variable to be specified, the dependencies must be included
939 * in <code>typeVarAssigns</code>. </p>
940 *
941 * @param typeVarAssigns specifies the potential types to be assigned to the
942 * type variables.
943 * @return whether or not the types can be assigned to their respective type
944 * variables.
945 */
946 public static boolean typesSatisfyVariables(Map<TypeVariable<?>, Type> typeVarAssigns) {
947 // all types must be assignable to all the bounds of the their mapped
948 // type variable.
949 for (Map.Entry<TypeVariable<?>, Type> entry : typeVarAssigns.entrySet()) {
950 TypeVariable<?> typeVar = entry.getKey();
951 Type type = entry.getValue();
952
953 for (Type bound : getImplicitBounds(typeVar)) {
954 if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns),
955 typeVarAssigns)) {
956 return false;
957 }
958 }
959 }
960
961 return true;
962 }
963
964 /**
965 * <p> Transforms the passed in type to a {@code Class} object. Type-checking method of convenience. </p>
966 *
967 * @param parameterizedType the type to be converted
968 * @return the corresponding {@code Class} object
969 * @throws IllegalStateException if the conversion fails
970 */
971 private static Class<?> getRawType(ParameterizedType parameterizedType) {
972 Type rawType = parameterizedType.getRawType();
973
974 // check if raw type is a Class object
975 // not currently necessary, but since the return type is Type instead of
976 // Class, there's enough reason to believe that future versions of Java
977 // may return other Type implementations. And type-safety checking is
978 // rarely a bad idea.
979 if (!(rawType instanceof Class<?>)) {
980 throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
981 }
982
983 return (Class<?>) rawType;
984 }
985
986 /**
987 * <p> Get the raw type of a Java type, given its context. Primarily for use
988 * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
989 * not know the runtime type of <code>type</code>: if you know you have a
990 * {@link Class} instance, it is already raw; if you know you have a
991 * {@link ParameterizedType}, its raw type is only a method call away. </p>
992 *
993 * @param type to resolve
994 * @param assigningType type to be resolved against
995 * @return the resolved <code>Class</code> object or <code>null</code> if
996 * the type could not be resolved
997 */
998 public static Class<?> getRawType(Type type, Type assigningType) {
999 if (type instanceof Class<?>) {
1000 // it is raw, no problem
1001 return (Class<?>) type;
1002 }
1003
1004 if (type instanceof ParameterizedType) {
1005 // simple enough to get the raw type of a ParameterizedType
1006 return getRawType((ParameterizedType) type);
1007 }
1008
1009 if (type instanceof TypeVariable<?>) {
1010 if (assigningType == null) {
1011 return null;
1012 }
1013
1014 // get the entity declaring this type variable
1015 Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
1016
1017 // can't get the raw type of a method- or constructor-declared type
1018 // variable
1019 if (!(genericDeclaration instanceof Class<?>)) {
1020 return null;
1021 }
1022
1023 // get the type arguments for the declaring class/interface based
1024 // on the enclosing type
1025 Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
1026 (Class<?>) genericDeclaration);
1027
1028 // enclosingType has to be a subclass (or subinterface) of the
1029 // declaring type
1030 if (typeVarAssigns == null) {
1031 return null;
1032 }
1033
1034 // get the argument assigned to this type variable
1035 Type typeArgument = typeVarAssigns.get(type);
1036
1037 if (typeArgument == null) {
1038 return null;
1039 }
1040
1041 // get the argument for this type variable
1042 return getRawType(typeArgument, assigningType);
1043 }
1044
1045 if (type instanceof GenericArrayType) {
1046 // get raw component type
1047 Class<?> rawComponentType = getRawType(((GenericArrayType) type)
1048 .getGenericComponentType(), assigningType);
1049
1050 // create array type from raw component type and return its class
1051 return Array.newInstance(rawComponentType, 0).getClass();
1052 }
1053
1054 // (hand-waving) this is not the method you're looking for
1055 if (type instanceof WildcardType) {
1056 return null;
1057 }
1058
1059 throw new IllegalArgumentException("unknown type: " + type);
1060 }
1061
1062 /**
1063 * Learn whether the specified type denotes an array type.
1064 * @param type the type to be checked
1065 * @return <code>true</code> if <code>type</code> is an array class or a {@link GenericArrayType}.
1066 */
1067 public static boolean isArrayType(Type type) {
1068 return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
1069 }
1070
1071 /**
1072 * Get the array component type of <code>type</code>.
1073 * @param type the type to be checked
1074 * @return component type or null if type is not an array type
1075 */
1076 public static Type getArrayComponentType(Type type) {
1077 if (type instanceof Class<?>) {
1078 Class<?> clazz = (Class<?>) type;
1079 return clazz.isArray() ? clazz.getComponentType() : null;
1080 }
1081 if (type instanceof GenericArrayType) {
1082 return ((GenericArrayType) type).getGenericComponentType();
1083 }
1084 return null;
1085 }
1086
1087 }
0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <html>
2 <head>
3 <!--
4 Licensed to the Apache Software Foundation (ASF) under one
5 or more contributor license agreements. See the NOTICE file
6 distributed with this work for additional information
7 regarding copyright ownership. The ASF licenses this file
8 to you under the Apache License, Version 2.0 (the
9 "License"); you may not use this file except in compliance
10 with the License. You may obtain a copy of the License at
11
12 http://www.apache.org/licenses/LICENSE-2.0
13
14 Unless required by applicable law or agreed to in writing,
15 software distributed under the License is distributed on an
16 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 KIND, either express or implied. See the License for the
18 specific language governing permissions and limitations
19 under the License.
20 -->
21 <title></title>
22 </head>
23 <body>
24 Accumulates common high-level uses of the <code>java.lang.reflect</code> APIs.
25 @since 3.0
26 <p>These classes are immutable, and therefore thread-safe.</p>
27 </body>
28 </html>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import java.text.FieldPosition;
19 import java.text.Format;
20 import java.text.ParseException;
21 import java.text.ParsePosition;
22
23 /**
24 * Formats using one formatter and parses using a different formatter. An
25 * example of use for this would be a webapp where data is taken in one way and
26 * stored in a database another way.
27 *
28 * @version $Id: CompositeFormat.java 1088899 2011-04-05 05:31:27Z bayard $
29 */
30 public class CompositeFormat extends Format {
31
32 /**
33 * Required for serialization support.
34 *
35 * @see java.io.Serializable
36 */
37 private static final long serialVersionUID = -4329119827877627683L;
38
39 /** The parser to use. */
40 private final Format parser;
41 /** The formatter to use. */
42 private final Format formatter;
43
44 /**
45 * Create a format that points its parseObject method to one implementation
46 * and its format method to another.
47 *
48 * @param parser implementation
49 * @param formatter implementation
50 */
51 public CompositeFormat(Format parser, Format formatter) {
52 this.parser = parser;
53 this.formatter = formatter;
54 }
55
56 /**
57 * Uses the formatter Format instance.
58 *
59 * @param obj the object to format
60 * @param toAppendTo the {@link StringBuffer} to append to
61 * @param pos the FieldPosition to use (or ignore).
62 * @return <code>toAppendTo</code>
63 * @see Format#format(Object, StringBuffer, FieldPosition)
64 */
65 @Override
66 public StringBuffer format(Object obj, StringBuffer toAppendTo,
67 FieldPosition pos) {
68 return formatter.format(obj, toAppendTo, pos);
69 }
70
71 /**
72 * Uses the parser Format instance.
73 *
74 * @param source the String source
75 * @param pos the ParsePosition containing the position to parse from, will
76 * be updated according to parsing success (index) or failure
77 * (error index)
78 * @return the parsed Object
79 * @see Format#parseObject(String, ParsePosition)
80 */
81 @Override
82 public Object parseObject(String source, ParsePosition pos) {
83 return parser.parseObject(source, pos);
84 }
85
86 /**
87 * Provides access to the parser Format implementation.
88 *
89 * @return parser Format implementation
90 */
91 public Format getParser() {
92 return this.parser;
93 }
94
95 /**
96 * Provides access to the parser Format implementation.
97 *
98 * @return formatter Format implementation
99 */
100 public Format getFormatter() {
101 return this.formatter;
102 }
103
104 /**
105 * Utility method to parse and then reformat a String.
106 *
107 * @param input String to reformat
108 * @return A reformatted String
109 * @throws ParseException thrown by parseObject(String) call
110 */
111 public String reformat(String input) throws ParseException {
112 return format(parseObject(input));
113 }
114
115 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import java.text.Format;
19 import java.text.MessageFormat;
20 import java.text.ParsePosition;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Iterator;
24 import java.util.Locale;
25 import java.util.Map;
26
27 import org.apache.commons.lang3.ObjectUtils;
28 import org.apache.commons.lang3.Validate;
29
30 /**
31 * Extends <code>java.text.MessageFormat</code> to allow pluggable/additional formatting
32 * options for embedded format elements. Client code should specify a registry
33 * of <code>FormatFactory</code> instances associated with <code>String</code>
34 * format names. This registry will be consulted when the format elements are
35 * parsed from the message pattern. In this way custom patterns can be specified,
36 * and the formats supported by <code>java.text.MessageFormat</code> can be overridden
37 * at the format and/or format style level (see MessageFormat). A "format element"
38 * embedded in the message pattern is specified (<b>()?</b> signifies optionality):<br />
39 * <code>{</code><i>argument-number</i><b>(</b><code>,</code><i>format-name</i><b>
40 * (</b><code>,</code><i>format-style</i><b>)?)?</b><code>}</code>
41 *
42 * <p>
43 * <i>format-name</i> and <i>format-style</i> values are trimmed of surrounding whitespace
44 * in the manner of <code>java.text.MessageFormat</code>. If <i>format-name</i> denotes
45 * <code>FormatFactory formatFactoryInstance</code> in <code>registry</code>, a <code>Format</code>
46 * matching <i>format-name</i> and <i>format-style</i> is requested from
47 * <code>formatFactoryInstance</code>. If this is successful, the <code>Format</code>
48 * found is used for this format element.
49 * </p>
50 *
51 * <p><b>NOTICE:</b> The various subformat mutator methods are considered unnecessary; they exist on the parent
52 * class to allow the type of customization which it is the job of this class to provide in
53 * a configurable fashion. These methods have thus been disabled and will throw
54 * <code>UnsupportedOperationException</code> if called.
55 * </p>
56 *
57 * <p>Limitations inherited from <code>java.text.MessageFormat</code>:
58 * <ul>
59 * <li>When using "choice" subformats, support for nested formatting instructions is limited
60 * to that provided by the base class.</li>
61 * <li>Thread-safety of <code>Format</code>s, including <code>MessageFormat</code> and thus
62 * <code>ExtendedMessageFormat</code>, is not guaranteed.</li>
63 * </ul>
64 * </p>
65 *
66 * @since 2.4
67 * @version $Id: ExtendedMessageFormat.java 1144929 2011-07-10 18:26:16Z ggregory $
68 */
69 public class ExtendedMessageFormat extends MessageFormat {
70 private static final long serialVersionUID = -2362048321261811743L;
71 private static final int HASH_SEED = 31;
72
73 private static final String DUMMY_PATTERN = "";
74 private static final String ESCAPED_QUOTE = "''";
75 private static final char START_FMT = ',';
76 private static final char END_FE = '}';
77 private static final char START_FE = '{';
78 private static final char QUOTE = '\'';
79
80 private String toPattern;
81 private final Map<String, ? extends FormatFactory> registry;
82
83 /**
84 * Create a new ExtendedMessageFormat for the default locale.
85 *
86 * @param pattern the pattern to use, not null
87 * @throws IllegalArgumentException in case of a bad pattern.
88 */
89 public ExtendedMessageFormat(String pattern) {
90 this(pattern, Locale.getDefault());
91 }
92
93 /**
94 * Create a new ExtendedMessageFormat.
95 *
96 * @param pattern the pattern to use, not null
97 * @param locale the locale to use, not null
98 * @throws IllegalArgumentException in case of a bad pattern.
99 */
100 public ExtendedMessageFormat(String pattern, Locale locale) {
101 this(pattern, locale, null);
102 }
103
104 /**
105 * Create a new ExtendedMessageFormat for the default locale.
106 *
107 * @param pattern the pattern to use, not null
108 * @param registry the registry of format factories, may be null
109 * @throws IllegalArgumentException in case of a bad pattern.
110 */
111 public ExtendedMessageFormat(String pattern, Map<String, ? extends FormatFactory> registry) {
112 this(pattern, Locale.getDefault(), registry);
113 }
114
115 /**
116 * Create a new ExtendedMessageFormat.
117 *
118 * @param pattern the pattern to use, not null
119 * @param locale the locale to use, not null
120 * @param registry the registry of format factories, may be null
121 * @throws IllegalArgumentException in case of a bad pattern.
122 */
123 public ExtendedMessageFormat(String pattern, Locale locale, Map<String, ? extends FormatFactory> registry) {
124 super(DUMMY_PATTERN);
125 setLocale(locale);
126 this.registry = registry;
127 applyPattern(pattern);
128 }
129
130 /**
131 * {@inheritDoc}
132 */
133 @Override
134 public String toPattern() {
135 return toPattern;
136 }
137
138 /**
139 * Apply the specified pattern.
140 *
141 * @param pattern String
142 */
143 @Override
144 public final void applyPattern(String pattern) {
145 if (registry == null) {
146 super.applyPattern(pattern);
147 toPattern = super.toPattern();
148 return;
149 }
150 ArrayList<Format> foundFormats = new ArrayList<Format>();
151 ArrayList<String> foundDescriptions = new ArrayList<String>();
152 StringBuilder stripCustom = new StringBuilder(pattern.length());
153
154 ParsePosition pos = new ParsePosition(0);
155 char[] c = pattern.toCharArray();
156 int fmtCount = 0;
157 while (pos.getIndex() < pattern.length()) {
158 switch (c[pos.getIndex()]) {
159 case QUOTE:
160 appendQuotedString(pattern, pos, stripCustom, true);
161 break;
162 case START_FE:
163 fmtCount++;
164 seekNonWs(pattern, pos);
165 int start = pos.getIndex();
166 int index = readArgumentIndex(pattern, next(pos));
167 stripCustom.append(START_FE).append(index);
168 seekNonWs(pattern, pos);
169 Format format = null;
170 String formatDescription = null;
171 if (c[pos.getIndex()] == START_FMT) {
172 formatDescription = parseFormatDescription(pattern,
173 next(pos));
174 format = getFormat(formatDescription);
175 if (format == null) {
176 stripCustom.append(START_FMT).append(formatDescription);
177 }
178 }
179 foundFormats.add(format);
180 foundDescriptions.add(format == null ? null : formatDescription);
181 Validate.isTrue(foundFormats.size() == fmtCount);
182 Validate.isTrue(foundDescriptions.size() == fmtCount);
183 if (c[pos.getIndex()] != END_FE) {
184 throw new IllegalArgumentException(
185 "Unreadable format element at position " + start);
186 }
187 //$FALL-THROUGH$
188 default:
189 stripCustom.append(c[pos.getIndex()]);
190 next(pos);
191 }
192 }
193 super.applyPattern(stripCustom.toString());
194 toPattern = insertFormats(super.toPattern(), foundDescriptions);
195 if (containsElements(foundFormats)) {
196 Format[] origFormats = getFormats();
197 // only loop over what we know we have, as MessageFormat on Java 1.3
198 // seems to provide an extra format element:
199 int i = 0;
200 for (Iterator<Format> it = foundFormats.iterator(); it.hasNext(); i++) {
201 Format f = it.next();
202 if (f != null) {
203 origFormats[i] = f;
204 }
205 }
206 super.setFormats(origFormats);
207 }
208 }
209
210 /**
211 * Throws UnsupportedOperationException - see class Javadoc for details.
212 *
213 * @param formatElementIndex format element index
214 * @param newFormat the new format
215 * @throws UnsupportedOperationException
216 */
217 @Override
218 public void setFormat(int formatElementIndex, Format newFormat) {
219 throw new UnsupportedOperationException();
220 }
221
222 /**
223 * Throws UnsupportedOperationException - see class Javadoc for details.
224 *
225 * @param argumentIndex argument index
226 * @param newFormat the new format
227 * @throws UnsupportedOperationException
228 */
229 @Override
230 public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) {
231 throw new UnsupportedOperationException();
232 }
233
234 /**
235 * Throws UnsupportedOperationException - see class Javadoc for details.
236 *
237 * @param newFormats new formats
238 * @throws UnsupportedOperationException
239 */
240 @Override
241 public void setFormats(Format[] newFormats) {
242 throw new UnsupportedOperationException();
243 }
244
245 /**
246 * Throws UnsupportedOperationException - see class Javadoc for details.
247 *
248 * @param newFormats new formats
249 * @throws UnsupportedOperationException
250 */
251 @Override
252 public void setFormatsByArgumentIndex(Format[] newFormats) {
253 throw new UnsupportedOperationException();
254 }
255
256 /**
257 * Check if this extended message format is equal to another object.
258 *
259 * @param obj the object to compare to
260 * @return true if this object equals the other, otherwise false
261 */
262 @Override
263 public boolean equals(Object obj) {
264 if (obj == this) {
265 return true;
266 }
267 if (obj == null) {
268 return false;
269 }
270 if (!super.equals(obj)) {
271 return false;
272 }
273 if (ObjectUtils.notEqual(getClass(), obj.getClass())) {
274 return false;
275 }
276 ExtendedMessageFormat rhs = (ExtendedMessageFormat)obj;
277 if (ObjectUtils.notEqual(toPattern, rhs.toPattern)) {
278 return false;
279 }
280 if (ObjectUtils.notEqual(registry, rhs.registry)) {
281 return false;
282 }
283 return true;
284 }
285
286 /**
287 * Return the hashcode.
288 *
289 * @return the hashcode
290 */
291 @Override
292 public int hashCode() {
293 int result = super.hashCode();
294 result = HASH_SEED * result + ObjectUtils.hashCode(registry);
295 result = HASH_SEED * result + ObjectUtils.hashCode(toPattern);
296 return result;
297 }
298
299 /**
300 * Get a custom format from a format description.
301 *
302 * @param desc String
303 * @return Format
304 */
305 private Format getFormat(String desc) {
306 if (registry != null) {
307 String name = desc;
308 String args = null;
309 int i = desc.indexOf(START_FMT);
310 if (i > 0) {
311 name = desc.substring(0, i).trim();
312 args = desc.substring(i + 1).trim();
313 }
314 FormatFactory factory = registry.get(name);
315 if (factory != null) {
316 return factory.getFormat(name, args, getLocale());
317 }
318 }
319 return null;
320 }
321
322 /**
323 * Read the argument index from the current format element
324 *
325 * @param pattern pattern to parse
326 * @param pos current parse position
327 * @return argument index
328 */
329 private int readArgumentIndex(String pattern, ParsePosition pos) {
330 int start = pos.getIndex();
331 seekNonWs(pattern, pos);
332 StringBuffer result = new StringBuffer();
333 boolean error = false;
334 for (; !error && pos.getIndex() < pattern.length(); next(pos)) {
335 char c = pattern.charAt(pos.getIndex());
336 if (Character.isWhitespace(c)) {
337 seekNonWs(pattern, pos);
338 c = pattern.charAt(pos.getIndex());
339 if (c != START_FMT && c != END_FE) {
340 error = true;
341 continue;
342 }
343 }
344 if ((c == START_FMT || c == END_FE) && result.length() > 0) {
345 try {
346 return Integer.parseInt(result.toString());
347 } catch (NumberFormatException e) { // NOPMD
348 // we've already ensured only digits, so unless something
349 // outlandishly large was specified we should be okay.
350 }
351 }
352 error = !Character.isDigit(c);
353 result.append(c);
354 }
355 if (error) {
356 throw new IllegalArgumentException(
357 "Invalid format argument index at position " + start + ": "
358 + pattern.substring(start, pos.getIndex()));
359 }
360 throw new IllegalArgumentException(
361 "Unterminated format element at position " + start);
362 }
363
364 /**
365 * Parse the format component of a format element.
366 *
367 * @param pattern string to parse
368 * @param pos current parse position
369 * @return Format description String
370 */
371 private String parseFormatDescription(String pattern, ParsePosition pos) {
372 int start = pos.getIndex();
373 seekNonWs(pattern, pos);
374 int text = pos.getIndex();
375 int depth = 1;
376 for (; pos.getIndex() < pattern.length(); next(pos)) {
377 switch (pattern.charAt(pos.getIndex())) {
378 case START_FE:
379 depth++;
380 break;
381 case END_FE:
382 depth--;
383 if (depth == 0) {
384 return pattern.substring(text, pos.getIndex());
385 }
386 break;
387 case QUOTE:
388 getQuotedString(pattern, pos, false);
389 break;
390 }
391 }
392 throw new IllegalArgumentException(
393 "Unterminated format element at position " + start);
394 }
395
396 /**
397 * Insert formats back into the pattern for toPattern() support.
398 *
399 * @param pattern source
400 * @param customPatterns The custom patterns to re-insert, if any
401 * @return full pattern
402 */
403 private String insertFormats(String pattern, ArrayList<String> customPatterns) {
404 if (!containsElements(customPatterns)) {
405 return pattern;
406 }
407 StringBuilder sb = new StringBuilder(pattern.length() * 2);
408 ParsePosition pos = new ParsePosition(0);
409 int fe = -1;
410 int depth = 0;
411 while (pos.getIndex() < pattern.length()) {
412 char c = pattern.charAt(pos.getIndex());
413 switch (c) {
414 case QUOTE:
415 appendQuotedString(pattern, pos, sb, false);
416 break;
417 case START_FE:
418 depth++;
419 if (depth == 1) {
420 fe++;
421 sb.append(START_FE).append(
422 readArgumentIndex(pattern, next(pos)));
423 String customPattern = customPatterns.get(fe);
424 if (customPattern != null) {
425 sb.append(START_FMT).append(customPattern);
426 }
427 }
428 break;
429 case END_FE:
430 depth--;
431 //$FALL-THROUGH$
432 default:
433 sb.append(c);
434 next(pos);
435 }
436 }
437 return sb.toString();
438 }
439
440 /**
441 * Consume whitespace from the current parse position.
442 *
443 * @param pattern String to read
444 * @param pos current position
445 */
446 private void seekNonWs(String pattern, ParsePosition pos) {
447 int len = 0;
448 char[] buffer = pattern.toCharArray();
449 do {
450 len = StrMatcher.splitMatcher().isMatch(buffer, pos.getIndex());
451 pos.setIndex(pos.getIndex() + len);
452 } while (len > 0 && pos.getIndex() < pattern.length());
453 }
454
455 /**
456 * Convenience method to advance parse position by 1
457 *
458 * @param pos ParsePosition
459 * @return <code>pos</code>
460 */
461 private ParsePosition next(ParsePosition pos) {
462 pos.setIndex(pos.getIndex() + 1);
463 return pos;
464 }
465
466 /**
467 * Consume a quoted string, adding it to <code>appendTo</code> if
468 * specified.
469 *
470 * @param pattern pattern to parse
471 * @param pos current parse position
472 * @param appendTo optional StringBuffer to append
473 * @param escapingOn whether to process escaped quotes
474 * @return <code>appendTo</code>
475 */
476 private StringBuilder appendQuotedString(String pattern, ParsePosition pos,
477 StringBuilder appendTo, boolean escapingOn) {
478 int start = pos.getIndex();
479 char[] c = pattern.toCharArray();
480 if (escapingOn && c[start] == QUOTE) {
481 next(pos);
482 return appendTo == null ? null : appendTo.append(QUOTE);
483 }
484 int lastHold = start;
485 for (int i = pos.getIndex(); i < pattern.length(); i++) {
486 if (escapingOn && pattern.substring(i).startsWith(ESCAPED_QUOTE)) {
487 appendTo.append(c, lastHold, pos.getIndex() - lastHold).append(
488 QUOTE);
489 pos.setIndex(i + ESCAPED_QUOTE.length());
490 lastHold = pos.getIndex();
491 continue;
492 }
493 switch (c[pos.getIndex()]) {
494 case QUOTE:
495 next(pos);
496 return appendTo == null ? null : appendTo.append(c, lastHold,
497 pos.getIndex() - lastHold);
498 default:
499 next(pos);
500 }
501 }
502 throw new IllegalArgumentException(
503 "Unterminated quoted string at position " + start);
504 }
505
506 /**
507 * Consume quoted string only
508 *
509 * @param pattern pattern to parse
510 * @param pos current parse position
511 * @param escapingOn whether to process escaped quotes
512 */
513 private void getQuotedString(String pattern, ParsePosition pos,
514 boolean escapingOn) {
515 appendQuotedString(pattern, pos, null, escapingOn);
516 }
517
518 /**
519 * Learn whether the specified Collection contains non-null elements.
520 * @param coll to check
521 * @return <code>true</code> if some Object was found, <code>false</code> otherwise.
522 */
523 private boolean containsElements(Collection<?> coll) {
524 if (coll == null || coll.size() == 0) {
525 return false;
526 }
527 for (Object name : coll) {
528 if (name != null) {
529 return true;
530 }
531 }
532 return false;
533 }
534 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import java.text.Format;
19 import java.util.Locale;
20
21 /**
22 * Format factory.
23 *
24 * @since 2.4
25 * @version $Id: FormatFactory.java 1088899 2011-04-05 05:31:27Z bayard $
26 */
27 public interface FormatFactory {
28
29 /**
30 * Create or retrieve a format instance.
31 *
32 * @param name The format type name
33 * @param arguments Arguments used to create the format instance. This allows the
34 * <code>FormatFactory</code> to implement the "format style"
35 * concept from <code>java.text.MessageFormat</code>.
36 * @param locale The locale, may be null
37 * @return The format instance
38 */
39 Format getFormat(String name, String arguments, Locale locale);
40
41 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import static java.util.FormattableFlags.LEFT_JUSTIFY;
19
20 import java.util.Formattable;
21 import java.util.Formatter;
22
23 import org.apache.commons.lang3.ObjectUtils;
24 import org.apache.commons.lang3.StringUtils;
25 import org.apache.commons.lang3.Validate;
26
27 /**
28 * <p>Provides utilities for working with the {@code Formattable} interface.</p>
29 *
30 * <p>The {@link Formattable} interface provides basic control over formatting
31 * when using a {@code Formatter}. It is primarily concerned with numeric precision
32 * and padding, and is not designed to allow generalised alternate formats.</p>
33 *
34 * @since Lang 3.0
35 * @version $Id: FormattableUtils.java 1132390 2011-06-05 12:45:10Z sebb $
36 */
37 public class FormattableUtils {
38
39 /**
40 * A format that simply outputs the value as a string.
41 */
42 private static final String SIMPLEST_FORMAT = "%s";
43
44 /**
45 * <p>{@code FormattableUtils} instances should NOT be constructed in
46 * standard programming. Instead, the methods of the class should be invoked
47 * statically.</p>
48 *
49 * <p>This constructor is public to permit tools that require a JavaBean
50 * instance to operate.</p>
51 */
52 public FormattableUtils() {
53 super();
54 }
55
56 //-----------------------------------------------------------------------
57 /**
58 * Get the default formatted representation of the specified
59 * {@code Formattable}.
60 *
61 * @param formattable the instance to convert to a string, not null
62 * @return the resulting string, not null
63 */
64 public static String toString(Formattable formattable) {
65 return String.format(SIMPLEST_FORMAT, formattable);
66 }
67
68 /**
69 * Handles the common {@code Formattable} operations of truncate-pad-append,
70 * with no ellipsis on precision overflow, and padding width underflow with
71 * spaces.
72 *
73 * @param seq the string to handle, not null
74 * @param formatter the destination formatter, not null
75 * @param flags the flags for formatting, see {@code Formattable}
76 * @param width the width of the output, see {@code Formattable}
77 * @param precision the precision of the output, see {@code Formattable}
78 * @return the {@code formatter} instance, not null
79 */
80 public static Formatter append(CharSequence seq, Formatter formatter, int flags, int width,
81 int precision) {
82 return append(seq, formatter, flags, width, precision, ' ', null);
83 }
84
85 /**
86 * Handles the common {@link Formattable} operations of truncate-pad-append,
87 * with no ellipsis on precision overflow.
88 *
89 * @param seq the string to handle, not null
90 * @param formatter the destination formatter, not null
91 * @param flags the flags for formatting, see {@code Formattable}
92 * @param width the width of the output, see {@code Formattable}
93 * @param precision the precision of the output, see {@code Formattable}
94 * @param padChar the pad character to use
95 * @return the {@code formatter} instance, not null
96 */
97 public static Formatter append(CharSequence seq, Formatter formatter, int flags, int width,
98 int precision, char padChar) {
99 return append(seq, formatter, flags, width, precision, padChar, null);
100 }
101
102 /**
103 * Handles the common {@link Formattable} operations of truncate-pad-append,
104 * padding width underflow with spaces.
105 *
106 * @param seq the string to handle, not null
107 * @param formatter the destination formatter, not null
108 * @param flags the flags for formatting, see {@code Formattable}
109 * @param width the width of the output, see {@code Formattable}
110 * @param precision the precision of the output, see {@code Formattable}
111 * @param ellipsis the ellipsis to use when precision dictates truncation, null or
112 * empty causes a hard truncation
113 * @return the {@code formatter} instance, not null
114 */
115 public static Formatter append(CharSequence seq, Formatter formatter, int flags, int width,
116 int precision, CharSequence ellipsis) {
117 return append(seq, formatter, flags, width, precision, ' ', ellipsis);
118 }
119
120 /**
121 * Handles the common {@link Formattable} operations of truncate-pad-append.
122 *
123 * @param seq the string to handle, not null
124 * @param formatter the destination formatter, not null
125 * @param flags the flags for formatting, see {@code Formattable}
126 * @param width the width of the output, see {@code Formattable}
127 * @param precision the precision of the output, see {@code Formattable}
128 * @param padChar the pad character to use
129 * @param ellipsis the ellipsis to use when precision dictates truncation, null or
130 * empty causes a hard truncation
131 * @return the {@code formatter} instance, not null
132 */
133 public static Formatter append(CharSequence seq, Formatter formatter, int flags, int width,
134 int precision, char padChar, CharSequence ellipsis) {
135 Validate.isTrue(ellipsis == null || precision < 0 || ellipsis.length() <= precision,
136 "Specified ellipsis '%1$s' exceeds precision of %2$s", ellipsis, Integer.valueOf(precision));
137 StringBuilder buf = new StringBuilder(seq);
138 if (precision >= 0 && precision < seq.length()) {
139 CharSequence _ellipsis = ObjectUtils.defaultIfNull(ellipsis, StringUtils.EMPTY);
140 buf.replace(precision - _ellipsis.length(), seq.length(), _ellipsis.toString());
141 }
142 boolean leftJustify = (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY;
143 for (int i = buf.length(); i < width; i++) {
144 buf.insert(leftJustify ? i : 0, padChar);
145 }
146 formatter.format(buf.toString());
147 return formatter;
148 }
149
150 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import java.io.Reader;
19 import java.io.Writer;
20 import java.util.Iterator;
21 import java.util.List;
22
23 import org.apache.commons.lang3.ArrayUtils;
24 import org.apache.commons.lang3.SystemUtils;
25
26 /**
27 * Builds a string from constituent parts providing a more flexible and powerful API
28 * than StringBuffer.
29 * <p>
30 * The main differences from StringBuffer/StringBuilder are:
31 * <ul>
32 * <li>Not synchronized</li>
33 * <li>Not final</li>
34 * <li>Subclasses have direct access to character array</li>
35 * <li>Additional methods
36 * <ul>
37 * <li>appendWithSeparators - adds an array of values, with a separator</li>
38 * <li>appendPadding - adds a length padding characters</li>
39 * <li>appendFixedLength - adds a fixed width field to the builder</li>
40 * <li>toCharArray/getChars - simpler ways to get a range of the character array</li>
41 * <li>delete - delete char or string</li>
42 * <li>replace - search and replace for a char or string</li>
43 * <li>leftString/rightString/midString - substring without exceptions</li>
44 * <li>contains - whether the builder contains a char or string</li>
45 * <li>size/clear/isEmpty - collections style API methods</li>
46 * </ul>
47 * </li>
48 * </ul>
49 * <li>Views
50 * <ul>
51 * <li>asTokenizer - uses the internal buffer as the source of a StrTokenizer</li>
52 * <li>asReader - uses the internal buffer as the source of a Reader</li>
53 * <li>asWriter - allows a Writer to write directly to the internal buffer</li>
54 * </ul>
55 * </li>
56 * </ul>
57 * <p>
58 * The aim has been to provide an API that mimics very closely what StringBuffer
59 * provides, but with additional methods. It should be noted that some edge cases,
60 * with invalid indices or null input, have been altered - see individual methods.
61 * The biggest of these changes is that by default, null will not output the text
62 * 'null'. This can be controlled by a property, {@link #setNullText(String)}.
63 * <p>
64 * Prior to 3.0, this class implemented Cloneable but did not implement the
65 * clone method so could not be used. From 3.0 onwards it no longer implements
66 * the interface.
67 *
68 * @since 2.2
69 * @version $Id: StrBuilder.java 1153484 2011-08-03 13:39:42Z ggregory $
70 */
71 public class StrBuilder implements CharSequence, Appendable {
72
73 /**
74 * The extra capacity for new builders.
75 */
76 static final int CAPACITY = 32;
77
78 /**
79 * Required for serialization support.
80 *
81 * @see java.io.Serializable
82 */
83 private static final long serialVersionUID = 7628716375283629643L;
84
85 /** Internal data storage. */
86 protected char[] buffer; // TODO make private?
87 /** Current size of the buffer. */
88 protected int size; // TODO make private?
89 /** The new line. */
90 private String newLine;
91 /** The null text. */
92 private String nullText;
93
94 //-----------------------------------------------------------------------
95 /**
96 * Constructor that creates an empty builder initial capacity 32 characters.
97 */
98 public StrBuilder() {
99 this(CAPACITY);
100 }
101
102 /**
103 * Constructor that creates an empty builder the specified initial capacity.
104 *
105 * @param initialCapacity the initial capacity, zero or less will be converted to 32
106 */
107 public StrBuilder(int initialCapacity) {
108 super();
109 if (initialCapacity <= 0) {
110 initialCapacity = CAPACITY;
111 }
112 buffer = new char[initialCapacity];
113 }
114
115 /**
116 * Constructor that creates a builder from the string, allocating
117 * 32 extra characters for growth.
118 *
119 * @param str the string to copy, null treated as blank string
120 */
121 public StrBuilder(String str) {
122 super();
123 if (str == null) {
124 buffer = new char[CAPACITY];
125 } else {
126 buffer = new char[str.length() + CAPACITY];
127 append(str);
128 }
129 }
130
131 //-----------------------------------------------------------------------
132 /**
133 * Gets the text to be appended when a new line is added.
134 *
135 * @return the new line text, null means use system default
136 */
137 public String getNewLineText() {
138 return newLine;
139 }
140
141 /**
142 * Sets the text to be appended when a new line is added.
143 *
144 * @param newLine the new line text, null means use system default
145 * @return this, to enable chaining
146 */
147 public StrBuilder setNewLineText(String newLine) {
148 this.newLine = newLine;
149 return this;
150 }
151
152 //-----------------------------------------------------------------------
153 /**
154 * Gets the text to be appended when null is added.
155 *
156 * @return the null text, null means no append
157 */
158 public String getNullText() {
159 return nullText;
160 }
161
162 /**
163 * Sets the text to be appended when null is added.
164 *
165 * @param nullText the null text, null means no append
166 * @return this, to enable chaining
167 */
168 public StrBuilder setNullText(String nullText) {
169 if (nullText != null && nullText.length() == 0) {
170 nullText = null;
171 }
172 this.nullText = nullText;
173 return this;
174 }
175
176 //-----------------------------------------------------------------------
177 /**
178 * Gets the length of the string builder.
179 *
180 * @return the length
181 */
182 public int length() {
183 return size;
184 }
185
186 /**
187 * Updates the length of the builder by either dropping the last characters
188 * or adding filler of Unicode zero.
189 *
190 * @param length the length to set to, must be zero or positive
191 * @return this, to enable chaining
192 * @throws IndexOutOfBoundsException if the length is negative
193 */
194 public StrBuilder setLength(int length) {
195 if (length < 0) {
196 throw new StringIndexOutOfBoundsException(length);
197 }
198 if (length < size) {
199 size = length;
200 } else if (length > size) {
201 ensureCapacity(length);
202 int oldEnd = size;
203 int newEnd = length;
204 size = length;
205 for (int i = oldEnd; i < newEnd; i++) {
206 buffer[i] = '\0';
207 }
208 }
209 return this;
210 }
211
212 //-----------------------------------------------------------------------
213 /**
214 * Gets the current size of the internal character array buffer.
215 *
216 * @return the capacity
217 */
218 public int capacity() {
219 return buffer.length;
220 }
221
222 /**
223 * Checks the capacity and ensures that it is at least the size specified.
224 *
225 * @param capacity the capacity to ensure
226 * @return this, to enable chaining
227 */
228 public StrBuilder ensureCapacity(int capacity) {
229 if (capacity > buffer.length) {
230 char[] old = buffer;
231 buffer = new char[capacity * 2];
232 System.arraycopy(old, 0, buffer, 0, size);
233 }
234 return this;
235 }
236
237 /**
238 * Minimizes the capacity to the actual length of the string.
239 *
240 * @return this, to enable chaining
241 */
242 public StrBuilder minimizeCapacity() {
243 if (buffer.length > length()) {
244 char[] old = buffer;
245 buffer = new char[length()];
246 System.arraycopy(old, 0, buffer, 0, size);
247 }
248 return this;
249 }
250
251 //-----------------------------------------------------------------------
252 /**
253 * Gets the length of the string builder.
254 * <p>
255 * This method is the same as {@link #length()} and is provided to match the
256 * API of Collections.
257 *
258 * @return the length
259 */
260 public int size() {
261 return size;
262 }
263
264 /**
265 * Checks is the string builder is empty (convenience Collections API style method).
266 * <p>
267 * This method is the same as checking {@link #length()} and is provided to match the
268 * API of Collections.
269 *
270 * @return <code>true</code> if the size is <code>0</code>.
271 */
272 public boolean isEmpty() {
273 return size == 0;
274 }
275
276 /**
277 * Clears the string builder (convenience Collections API style method).
278 * <p>
279 * This method does not reduce the size of the internal character buffer.
280 * To do that, call <code>clear()</code> followed by {@link #minimizeCapacity()}.
281 * <p>
282 * This method is the same as {@link #setLength(int)} called with zero
283 * and is provided to match the API of Collections.
284 *
285 * @return this, to enable chaining
286 */
287 public StrBuilder clear() {
288 size = 0;
289 return this;
290 }
291
292 //-----------------------------------------------------------------------
293 /**
294 * Gets the character at the specified index.
295 *
296 * @see #setCharAt(int, char)
297 * @see #deleteCharAt(int)
298 * @param index the index to retrieve, must be valid
299 * @return the character at the index
300 * @throws IndexOutOfBoundsException if the index is invalid
301 */
302 public char charAt(int index) {
303 if (index < 0 || index >= length()) {
304 throw new StringIndexOutOfBoundsException(index);
305 }
306 return buffer[index];
307 }
308
309 /**
310 * Sets the character at the specified index.
311 *
312 * @see #charAt(int)
313 * @see #deleteCharAt(int)
314 * @param index the index to set
315 * @param ch the new character
316 * @return this, to enable chaining
317 * @throws IndexOutOfBoundsException if the index is invalid
318 */
319 public StrBuilder setCharAt(int index, char ch) {
320 if (index < 0 || index >= length()) {
321 throw new StringIndexOutOfBoundsException(index);
322 }
323 buffer[index] = ch;
324 return this;
325 }
326
327 /**
328 * Deletes the character at the specified index.
329 *
330 * @see #charAt(int)
331 * @see #setCharAt(int, char)
332 * @param index the index to delete
333 * @return this, to enable chaining
334 * @throws IndexOutOfBoundsException if the index is invalid
335 */
336 public StrBuilder deleteCharAt(int index) {
337 if (index < 0 || index >= size) {
338 throw new StringIndexOutOfBoundsException(index);
339 }
340 deleteImpl(index, index + 1, 1);
341 return this;
342 }
343
344 //-----------------------------------------------------------------------
345 /**
346 * Copies the builder's character array into a new character array.
347 *
348 * @return a new array that represents the contents of the builder
349 */
350 public char[] toCharArray() {
351 if (size == 0) {
352 return ArrayUtils.EMPTY_CHAR_ARRAY;
353 }
354 char chars[] = new char[size];
355 System.arraycopy(buffer, 0, chars, 0, size);
356 return chars;
357 }
358
359 /**
360 * Copies part of the builder's character array into a new character array.
361 *
362 * @param startIndex the start index, inclusive, must be valid
363 * @param endIndex the end index, exclusive, must be valid except that
364 * if too large it is treated as end of string
365 * @return a new array that holds part of the contents of the builder
366 * @throws IndexOutOfBoundsException if startIndex is invalid,
367 * or if endIndex is invalid (but endIndex greater than size is valid)
368 */
369 public char[] toCharArray(int startIndex, int endIndex) {
370 endIndex = validateRange(startIndex, endIndex);
371 int len = endIndex - startIndex;
372 if (len == 0) {
373 return ArrayUtils.EMPTY_CHAR_ARRAY;
374 }
375 char chars[] = new char[len];
376 System.arraycopy(buffer, startIndex, chars, 0, len);
377 return chars;
378 }
379
380 /**
381 * Copies the character array into the specified array.
382 *
383 * @param destination the destination array, null will cause an array to be created
384 * @return the input array, unless that was null or too small
385 */
386 public char[] getChars(char[] destination) {
387 int len = length();
388 if (destination == null || destination.length < len) {
389 destination = new char[len];
390 }
391 System.arraycopy(buffer, 0, destination, 0, len);
392 return destination;
393 }
394
395 /**
396 * Copies the character array into the specified array.
397 *
398 * @param startIndex first index to copy, inclusive, must be valid
399 * @param endIndex last index, exclusive, must be valid
400 * @param destination the destination array, must not be null or too small
401 * @param destinationIndex the index to start copying in destination
402 * @throws NullPointerException if the array is null
403 * @throws IndexOutOfBoundsException if any index is invalid
404 */
405 public void getChars(int startIndex, int endIndex, char destination[], int destinationIndex) {
406 if (startIndex < 0) {
407 throw new StringIndexOutOfBoundsException(startIndex);
408 }
409 if (endIndex < 0 || endIndex > length()) {
410 throw new StringIndexOutOfBoundsException(endIndex);
411 }
412 if (startIndex > endIndex) {
413 throw new StringIndexOutOfBoundsException("end < start");
414 }
415 System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex);
416 }
417
418 //-----------------------------------------------------------------------
419 /**
420 * Appends the new line string to this string builder.
421 * <p>
422 * The new line string can be altered using {@link #setNewLineText(String)}.
423 * This might be used to force the output to always use Unix line endings
424 * even when on Windows.
425 *
426 * @return this, to enable chaining
427 */
428 public StrBuilder appendNewLine() {
429 if (newLine == null) {
430 append(SystemUtils.LINE_SEPARATOR);
431 return this;
432 }
433 return append(newLine);
434 }
435
436 /**
437 * Appends the text representing <code>null</code> to this string builder.
438 *
439 * @return this, to enable chaining
440 */
441 public StrBuilder appendNull() {
442 if (nullText == null) {
443 return this;
444 }
445 return append(nullText);
446 }
447
448 /**
449 * Appends an object to this string builder.
450 * Appending null will call {@link #appendNull()}.
451 *
452 * @param obj the object to append
453 * @return this, to enable chaining
454 */
455 public StrBuilder append(Object obj) {
456 if (obj == null) {
457 return appendNull();
458 }
459 return append(obj.toString());
460 }
461
462 /**
463 * Appends a CharSequence to this string builder.
464 * Appending null will call {@link #appendNull()}.
465 *
466 * @param seq the CharSequence to append
467 * @return this, to enable chaining
468 * @since 3.0
469 */
470 public StrBuilder append(CharSequence seq) {
471 if (seq == null) {
472 return appendNull();
473 }
474 return append(seq.toString());
475 }
476
477 /**
478 * Appends part of a CharSequence to this string builder.
479 * Appending null will call {@link #appendNull()}.
480 *
481 * @param seq the CharSequence to append
482 * @param startIndex the start index, inclusive, must be valid
483 * @param length the length to append, must be valid
484 * @return this, to enable chaining
485 * @since 3.0
486 */
487 public StrBuilder append(CharSequence seq, int startIndex, int length) {
488 if (seq == null) {
489 return appendNull();
490 }
491 return append(seq.toString(), startIndex, length);
492 }
493
494 /**
495 * Appends a string to this string builder.
496 * Appending null will call {@link #appendNull()}.
497 *
498 * @param str the string to append
499 * @return this, to enable chaining
500 */
501 public StrBuilder append(String str) {
502 if (str == null) {
503 return appendNull();
504 }
505 int strLen = str.length();
506 if (strLen > 0) {
507 int len = length();
508 ensureCapacity(len + strLen);
509 str.getChars(0, strLen, buffer, len);
510 size += strLen;
511 }
512 return this;
513 }
514
515 /**
516 * Appends part of a string to this string builder.
517 * Appending null will call {@link #appendNull()}.
518 *
519 * @param str the string to append
520 * @param startIndex the start index, inclusive, must be valid
521 * @param length the length to append, must be valid
522 * @return this, to enable chaining
523 */
524 public StrBuilder append(String str, int startIndex, int length) {
525 if (str == null) {
526 return appendNull();
527 }
528 if (startIndex < 0 || startIndex > str.length()) {
529 throw new StringIndexOutOfBoundsException("startIndex must be valid");
530 }
531 if (length < 0 || (startIndex + length) > str.length()) {
532 throw new StringIndexOutOfBoundsException("length must be valid");
533 }
534 if (length > 0) {
535 int len = length();
536 ensureCapacity(len + length);
537 str.getChars(startIndex, startIndex + length, buffer, len);
538 size += length;
539 }
540 return this;
541 }
542
543 /**
544 * Appends a string buffer to this string builder.
545 * Appending null will call {@link #appendNull()}.
546 *
547 * @param str the string buffer to append
548 * @return this, to enable chaining
549 */
550 public StrBuilder append(StringBuffer str) {
551 if (str == null) {
552 return appendNull();
553 }
554 int strLen = str.length();
555 if (strLen > 0) {
556 int len = length();
557 ensureCapacity(len + strLen);
558 str.getChars(0, strLen, buffer, len);
559 size += strLen;
560 }
561 return this;
562 }
563
564 /**
565 * Appends part of a string buffer to this string builder.
566 * Appending null will call {@link #appendNull()}.
567 *
568 * @param str the string to append
569 * @param startIndex the start index, inclusive, must be valid
570 * @param length the length to append, must be valid
571 * @return this, to enable chaining
572 */
573 public StrBuilder append(StringBuffer str, int startIndex, int length) {
574 if (str == null) {
575 return appendNull();
576 }
577 if (startIndex < 0 || startIndex > str.length()) {
578 throw new StringIndexOutOfBoundsException("startIndex must be valid");
579 }
580 if (length < 0 || (startIndex + length) > str.length()) {
581 throw new StringIndexOutOfBoundsException("length must be valid");
582 }
583 if (length > 0) {
584 int len = length();
585 ensureCapacity(len + length);
586 str.getChars(startIndex, startIndex + length, buffer, len);
587 size += length;
588 }
589 return this;
590 }
591
592 /**
593 * Appends another string builder to this string builder.
594 * Appending null will call {@link #appendNull()}.
595 *
596 * @param str the string builder to append
597 * @return this, to enable chaining
598 */
599 public StrBuilder append(StrBuilder str) {
600 if (str == null) {
601 return appendNull();
602 }
603 int strLen = str.length();
604 if (strLen > 0) {
605 int len = length();
606 ensureCapacity(len + strLen);
607 System.arraycopy(str.buffer, 0, buffer, len, strLen);
608 size += strLen;
609 }
610 return this;
611 }
612
613 /**
614 * Appends part of a string builder to this string builder.
615 * Appending null will call {@link #appendNull()}.
616 *
617 * @param str the string to append
618 * @param startIndex the start index, inclusive, must be valid
619 * @param length the length to append, must be valid
620 * @return this, to enable chaining
621 */
622 public StrBuilder append(StrBuilder str, int startIndex, int length) {
623 if (str == null) {
624 return appendNull();
625 }
626 if (startIndex < 0 || startIndex > str.length()) {
627 throw new StringIndexOutOfBoundsException("startIndex must be valid");
628 }
629 if (length < 0 || (startIndex + length) > str.length()) {
630 throw new StringIndexOutOfBoundsException("length must be valid");
631 }
632 if (length > 0) {
633 int len = length();
634 ensureCapacity(len + length);
635 str.getChars(startIndex, startIndex + length, buffer, len);
636 size += length;
637 }
638 return this;
639 }
640
641 /**
642 * Appends a char array to the string builder.
643 * Appending null will call {@link #appendNull()}.
644 *
645 * @param chars the char array to append
646 * @return this, to enable chaining
647 */
648 public StrBuilder append(char[] chars) {
649 if (chars == null) {
650 return appendNull();
651 }
652 int strLen = chars.length;
653 if (strLen > 0) {
654 int len = length();
655 ensureCapacity(len + strLen);
656 System.arraycopy(chars, 0, buffer, len, strLen);
657 size += strLen;
658 }
659 return this;
660 }
661
662 /**
663 * Appends a char array to the string builder.
664 * Appending null will call {@link #appendNull()}.
665 *
666 * @param chars the char array to append
667 * @param startIndex the start index, inclusive, must be valid
668 * @param length the length to append, must be valid
669 * @return this, to enable chaining
670 */
671 public StrBuilder append(char[] chars, int startIndex, int length) {
672 if (chars == null) {
673 return appendNull();
674 }
675 if (startIndex < 0 || startIndex > chars.length) {
676 throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length);
677 }
678 if (length < 0 || (startIndex + length) > chars.length) {
679 throw new StringIndexOutOfBoundsException("Invalid length: " + length);
680 }
681 if (length > 0) {
682 int len = length();
683 ensureCapacity(len + length);
684 System.arraycopy(chars, startIndex, buffer, len, length);
685 size += length;
686 }
687 return this;
688 }
689
690 /**
691 * Appends a boolean value to the string builder.
692 *
693 * @param value the value to append
694 * @return this, to enable chaining
695 */
696 public StrBuilder append(boolean value) {
697 if (value) {
698 ensureCapacity(size + 4);
699 buffer[size++] = 't';
700 buffer[size++] = 'r';
701 buffer[size++] = 'u';
702 buffer[size++] = 'e';
703 } else {
704 ensureCapacity(size + 5);
705 buffer[size++] = 'f';
706 buffer[size++] = 'a';
707 buffer[size++] = 'l';
708 buffer[size++] = 's';
709 buffer[size++] = 'e';
710 }
711 return this;
712 }
713
714 /**
715 * Appends a char value to the string builder.
716 *
717 * @param ch the value to append
718 * @return this, to enable chaining
719 * @since 3.0
720 */
721 public StrBuilder append(char ch) {
722 int len = length();
723 ensureCapacity(len + 1);
724 buffer[size++] = ch;
725 return this;
726 }
727
728 /**
729 * Appends an int value to the string builder using <code>String.valueOf</code>.
730 *
731 * @param value the value to append
732 * @return this, to enable chaining
733 */
734 public StrBuilder append(int value) {
735 return append(String.valueOf(value));
736 }
737
738 /**
739 * Appends a long value to the string builder using <code>String.valueOf</code>.
740 *
741 * @param value the value to append
742 * @return this, to enable chaining
743 */
744 public StrBuilder append(long value) {
745 return append(String.valueOf(value));
746 }
747
748 /**
749 * Appends a float value to the string builder using <code>String.valueOf</code>.
750 *
751 * @param value the value to append
752 * @return this, to enable chaining
753 */
754 public StrBuilder append(float value) {
755 return append(String.valueOf(value));
756 }
757
758 /**
759 * Appends a double value to the string builder using <code>String.valueOf</code>.
760 *
761 * @param value the value to append
762 * @return this, to enable chaining
763 */
764 public StrBuilder append(double value) {
765 return append(String.valueOf(value));
766 }
767
768 //-----------------------------------------------------------------------
769 /**
770 * Appends an object followed by a new line to this string builder.
771 * Appending null will call {@link #appendNull()}.
772 *
773 * @param obj the object to append
774 * @return this, to enable chaining
775 * @since 2.3
776 */
777 public StrBuilder appendln(Object obj) {
778 return append(obj).appendNewLine();
779 }
780
781 /**
782 * Appends a string followed by a new line to this string builder.
783 * Appending null will call {@link #appendNull()}.
784 *
785 * @param str the string to append
786 * @return this, to enable chaining
787 * @since 2.3
788 */
789 public StrBuilder appendln(String str) {
790 return append(str).appendNewLine();
791 }
792
793 /**
794 * Appends part of a string followed by a new line to this string builder.
795 * Appending null will call {@link #appendNull()}.
796 *
797 * @param str the string to append
798 * @param startIndex the start index, inclusive, must be valid
799 * @param length the length to append, must be valid
800 * @return this, to enable chaining
801 * @since 2.3
802 */
803 public StrBuilder appendln(String str, int startIndex, int length) {
804 return append(str, startIndex, length).appendNewLine();
805 }
806
807 /**
808 * Appends a string buffer followed by a new line to this string builder.
809 * Appending null will call {@link #appendNull()}.
810 *
811 * @param str the string buffer to append
812 * @return this, to enable chaining
813 * @since 2.3
814 */
815 public StrBuilder appendln(StringBuffer str) {
816 return append(str).appendNewLine();
817 }
818
819 /**
820 * Appends part of a string buffer followed by a new line to this string builder.
821 * Appending null will call {@link #appendNull()}.
822 *
823 * @param str the string to append
824 * @param startIndex the start index, inclusive, must be valid
825 * @param length the length to append, must be valid
826 * @return this, to enable chaining
827 * @since 2.3
828 */
829 public StrBuilder appendln(StringBuffer str, int startIndex, int length) {
830 return append(str, startIndex, length).appendNewLine();
831 }
832
833 /**
834 * Appends another string builder followed by a new line to this string builder.
835 * Appending null will call {@link #appendNull()}.
836 *
837 * @param str the string builder to append
838 * @return this, to enable chaining
839 * @since 2.3
840 */
841 public StrBuilder appendln(StrBuilder str) {
842 return append(str).appendNewLine();
843 }
844
845 /**
846 * Appends part of a string builder followed by a new line to this string builder.
847 * Appending null will call {@link #appendNull()}.
848 *
849 * @param str the string to append
850 * @param startIndex the start index, inclusive, must be valid
851 * @param length the length to append, must be valid
852 * @return this, to enable chaining
853 * @since 2.3
854 */
855 public StrBuilder appendln(StrBuilder str, int startIndex, int length) {
856 return append(str, startIndex, length).appendNewLine();
857 }
858
859 /**
860 * Appends a char array followed by a new line to the string builder.
861 * Appending null will call {@link #appendNull()}.
862 *
863 * @param chars the char array to append
864 * @return this, to enable chaining
865 * @since 2.3
866 */
867 public StrBuilder appendln(char[] chars) {
868 return append(chars).appendNewLine();
869 }
870
871 /**
872 * Appends a char array followed by a new line to the string builder.
873 * Appending null will call {@link #appendNull()}.
874 *
875 * @param chars the char array to append
876 * @param startIndex the start index, inclusive, must be valid
877 * @param length the length to append, must be valid
878 * @return this, to enable chaining
879 * @since 2.3
880 */
881 public StrBuilder appendln(char[] chars, int startIndex, int length) {
882 return append(chars, startIndex, length).appendNewLine();
883 }
884
885 /**
886 * Appends a boolean value followed by a new line to the string builder.
887 *
888 * @param value the value to append
889 * @return this, to enable chaining
890 * @since 2.3
891 */
892 public StrBuilder appendln(boolean value) {
893 return append(value).appendNewLine();
894 }
895
896 /**
897 * Appends a char value followed by a new line to the string builder.
898 *
899 * @param ch the value to append
900 * @return this, to enable chaining
901 * @since 2.3
902 */
903 public StrBuilder appendln(char ch) {
904 return append(ch).appendNewLine();
905 }
906
907 /**
908 * Appends an int value followed by a new line to the string builder using <code>String.valueOf</code>.
909 *
910 * @param value the value to append
911 * @return this, to enable chaining
912 * @since 2.3
913 */
914 public StrBuilder appendln(int value) {
915 return append(value).appendNewLine();
916 }
917
918 /**
919 * Appends a long value followed by a new line to the string builder using <code>String.valueOf</code>.
920 *
921 * @param value the value to append
922 * @return this, to enable chaining
923 * @since 2.3
924 */
925 public StrBuilder appendln(long value) {
926 return append(value).appendNewLine();
927 }
928
929 /**
930 * Appends a float value followed by a new line to the string builder using <code>String.valueOf</code>.
931 *
932 * @param value the value to append
933 * @return this, to enable chaining
934 * @since 2.3
935 */
936 public StrBuilder appendln(float value) {
937 return append(value).appendNewLine();
938 }
939
940 /**
941 * Appends a double value followed by a new line to the string builder using <code>String.valueOf</code>.
942 *
943 * @param value the value to append
944 * @return this, to enable chaining
945 * @since 2.3
946 */
947 public StrBuilder appendln(double value) {
948 return append(value).appendNewLine();
949 }
950
951 //-----------------------------------------------------------------------
952 /**
953 * Appends each item in an array to the builder without any separators.
954 * Appending a null array will have no effect.
955 * Each object is appended using {@link #append(Object)}.
956 *
957 * @param array the array to append
958 * @return this, to enable chaining
959 * @since 2.3
960 */
961 public StrBuilder appendAll(Object[] array) {
962 if (array != null && array.length > 0) {
963 for (Object element : array) {
964 append(element);
965 }
966 }
967 return this;
968 }
969
970 /**
971 * Appends each item in a iterable to the builder without any separators.
972 * Appending a null iterable will have no effect.
973 * Each object is appended using {@link #append(Object)}.
974 *
975 * @param iterable the iterable to append
976 * @return this, to enable chaining
977 * @since 2.3
978 */
979 public StrBuilder appendAll(Iterable<?> iterable) {
980 if (iterable != null) {
981 Iterator<?> it = iterable.iterator();
982 while (it.hasNext()) {
983 append(it.next());
984 }
985 }
986 return this;
987 }
988
989 /**
990 * Appends each item in an iterator to the builder without any separators.
991 * Appending a null iterator will have no effect.
992 * Each object is appended using {@link #append(Object)}.
993 *
994 * @param it the iterator to append
995 * @return this, to enable chaining
996 * @since 2.3
997 */
998 public StrBuilder appendAll(Iterator<?> it) {
999 if (it != null) {
1000 while (it.hasNext()) {
1001 append(it.next());
1002 }
1003 }
1004 return this;
1005 }
1006
1007 //-----------------------------------------------------------------------
1008 /**
1009 * Appends an array placing separators between each value, but
1010 * not before the first or after the last.
1011 * Appending a null array will have no effect.
1012 * Each object is appended using {@link #append(Object)}.
1013 *
1014 * @param array the array to append
1015 * @param separator the separator to use, null means no separator
1016 * @return this, to enable chaining
1017 */
1018 public StrBuilder appendWithSeparators(Object[] array, String separator) {
1019 if (array != null && array.length > 0) {
1020 separator = (separator == null ? "" : separator);
1021 append(array[0]);
1022 for (int i = 1; i < array.length; i++) {
1023 append(separator);
1024 append(array[i]);
1025 }
1026 }
1027 return this;
1028 }
1029
1030 /**
1031 * Appends a iterable placing separators between each value, but
1032 * not before the first or after the last.
1033 * Appending a null iterable will have no effect.
1034 * Each object is appended using {@link #append(Object)}.
1035 *
1036 * @param iterable the iterable to append
1037 * @param separator the separator to use, null means no separator
1038 * @return this, to enable chaining
1039 */
1040 public StrBuilder appendWithSeparators(Iterable<?> iterable, String separator) {
1041 if (iterable != null) {
1042 separator = (separator == null ? "" : separator);
1043 Iterator<?> it = iterable.iterator();
1044 while (it.hasNext()) {
1045 append(it.next());
1046 if (it.hasNext()) {
1047 append(separator);
1048 }
1049 }
1050 }
1051 return this;
1052 }
1053
1054 /**
1055 * Appends an iterator placing separators between each value, but
1056 * not before the first or after the last.
1057 * Appending a null iterator will have no effect.
1058 * Each object is appended using {@link #append(Object)}.
1059 *
1060 * @param it the iterator to append
1061 * @param separator the separator to use, null means no separator
1062 * @return this, to enable chaining
1063 */
1064 public StrBuilder appendWithSeparators(Iterator<?> it, String separator) {
1065 if (it != null) {
1066 separator = (separator == null ? "" : separator);
1067 while (it.hasNext()) {
1068 append(it.next());
1069 if (it.hasNext()) {
1070 append(separator);
1071 }
1072 }
1073 }
1074 return this;
1075 }
1076
1077 //-----------------------------------------------------------------------
1078 /**
1079 * Appends a separator if the builder is currently non-empty.
1080 * Appending a null separator will have no effect.
1081 * The separator is appended using {@link #append(String)}.
1082 * <p>
1083 * This method is useful for adding a separator each time around the
1084 * loop except the first.
1085 * <pre>
1086 * for (Iterator it = list.iterator(); it.hasNext(); ) {
1087 * appendSeparator(",");
1088 * append(it.next());
1089 * }
1090 * </pre>
1091 * Note that for this simple example, you should use
1092 * {@link #appendWithSeparators(Iterable, String)}.
1093 *
1094 * @param separator the separator to use, null means no separator
1095 * @return this, to enable chaining
1096 * @since 2.3
1097 */
1098 public StrBuilder appendSeparator(String separator) {
1099 return appendSeparator(separator, null);
1100 }
1101
1102 /**
1103 * Appends one of both separators to the StrBuilder.
1104 * If the builder is currently empty it will append the defaultIfEmpty-separator
1105 * Otherwise it will append the standard-separator
1106 *
1107 * Appending a null separator will have no effect.
1108 * The separator is appended using {@link #append(String)}.
1109 * <p>
1110 * This method is for example useful for constructing queries
1111 * <pre>
1112 * StrBuilder whereClause = new StrBuilder();
1113 * if(searchCommand.getPriority() != null) {
1114 * whereClause.appendSeparator(" and", " where");
1115 * whereClause.append(" priority = ?")
1116 * }
1117 * if(searchCommand.getComponent() != null) {
1118 * whereClause.appendSeparator(" and", " where");
1119 * whereClause.append(" component = ?")
1120 * }
1121 * selectClause.append(whereClause)
1122 * </pre>
1123 *
1124 * @param standard the separator if builder is not empty, null means no separator
1125 * @param defaultIfEmpty the separator if builder is empty, null means no separator
1126 * @return this, to enable chaining
1127 * @since 2.5
1128 */
1129 public StrBuilder appendSeparator(String standard, String defaultIfEmpty) {
1130 String str = isEmpty() ? defaultIfEmpty : standard;
1131 if (str != null) {
1132 append(str);
1133 }
1134 return this;
1135 }
1136
1137 /**
1138 * Appends a separator if the builder is currently non-empty.
1139 * The separator is appended using {@link #append(char)}.
1140 * <p>
1141 * This method is useful for adding a separator each time around the
1142 * loop except the first.
1143 * <pre>
1144 * for (Iterator it = list.iterator(); it.hasNext(); ) {
1145 * appendSeparator(',');
1146 * append(it.next());
1147 * }
1148 * </pre>
1149 * Note that for this simple example, you should use
1150 * {@link #appendWithSeparators(Iterable, String)}.
1151 *
1152 * @param separator the separator to use
1153 * @return this, to enable chaining
1154 * @since 2.3
1155 */
1156 public StrBuilder appendSeparator(char separator) {
1157 if (size() > 0) {
1158 append(separator);
1159 }
1160 return this;
1161 }
1162
1163 /**
1164 * Append one of both separators to the builder
1165 * If the builder is currently empty it will append the defaultIfEmpty-separator
1166 * Otherwise it will append the standard-separator
1167 *
1168 * The separator is appended using {@link #append(char)}.
1169 * @param standard the separator if builder is not empty
1170 * @param defaultIfEmpty the separator if builder is empty
1171 * @return this, to enable chaining
1172 * @since 2.5
1173 */
1174 public StrBuilder appendSeparator(char standard, char defaultIfEmpty) {
1175 if (size() > 0) {
1176 append(standard);
1177 } else {
1178 append(defaultIfEmpty);
1179 }
1180 return this;
1181 }
1182 /**
1183 * Appends a separator to the builder if the loop index is greater than zero.
1184 * Appending a null separator will have no effect.
1185 * The separator is appended using {@link #append(String)}.
1186 * <p>
1187 * This method is useful for adding a separator each time around the
1188 * loop except the first.
1189 * <pre>
1190 * for (int i = 0; i < list.size(); i++) {
1191 * appendSeparator(",", i);
1192 * append(list.get(i));
1193 * }
1194 * </pre>
1195 * Note that for this simple example, you should use
1196 * {@link #appendWithSeparators(Iterable, String)}.
1197 *
1198 * @param separator the separator to use, null means no separator
1199 * @param loopIndex the loop index
1200 * @return this, to enable chaining
1201 * @since 2.3
1202 */
1203 public StrBuilder appendSeparator(String separator, int loopIndex) {
1204 if (separator != null && loopIndex > 0) {
1205 append(separator);
1206 }
1207 return this;
1208 }
1209
1210 /**
1211 * Appends a separator to the builder if the loop index is greater than zero.
1212 * The separator is appended using {@link #append(char)}.
1213 * <p>
1214 * This method is useful for adding a separator each time around the
1215 * loop except the first.
1216 * <pre>
1217 * for (int i = 0; i < list.size(); i++) {
1218 * appendSeparator(",", i);
1219 * append(list.get(i));
1220 * }
1221 * </pre>
1222 * Note that for this simple example, you should use
1223 * {@link #appendWithSeparators(Iterable, String)}.
1224 *
1225 * @param separator the separator to use
1226 * @param loopIndex the loop index
1227 * @return this, to enable chaining
1228 * @since 2.3
1229 */
1230 public StrBuilder appendSeparator(char separator, int loopIndex) {
1231 if (loopIndex > 0) {
1232 append(separator);
1233 }
1234 return this;
1235 }
1236
1237 //-----------------------------------------------------------------------
1238 /**
1239 * Appends the pad character to the builder the specified number of times.
1240 *
1241 * @param length the length to append, negative means no append
1242 * @param padChar the character to append
1243 * @return this, to enable chaining
1244 */
1245 public StrBuilder appendPadding(int length, char padChar) {
1246 if (length >= 0) {
1247 ensureCapacity(size + length);
1248 for (int i = 0; i < length; i++) {
1249 buffer[size++] = padChar;
1250 }
1251 }
1252 return this;
1253 }
1254
1255 //-----------------------------------------------------------------------
1256 /**
1257 * Appends an object to the builder padding on the left to a fixed width.
1258 * The <code>toString</code> of the object is used.
1259 * If the object is larger than the length, the left hand side is lost.
1260 * If the object is null, the null text value is used.
1261 *
1262 * @param obj the object to append, null uses null text
1263 * @param width the fixed field width, zero or negative has no effect
1264 * @param padChar the pad character to use
1265 * @return this, to enable chaining
1266 */
1267 public StrBuilder appendFixedWidthPadLeft(Object obj, int width, char padChar) {
1268 if (width > 0) {
1269 ensureCapacity(size + width);
1270 String str = (obj == null ? getNullText() : obj.toString());
1271 if (str == null) {
1272 str = "";
1273 }
1274 int strLen = str.length();
1275 if (strLen >= width) {
1276 str.getChars(strLen - width, strLen, buffer, size);
1277 } else {
1278 int padLen = width - strLen;
1279 for (int i = 0; i < padLen; i++) {
1280 buffer[size + i] = padChar;
1281 }
1282 str.getChars(0, strLen, buffer, size + padLen);
1283 }
1284 size += width;
1285 }
1286 return this;
1287 }
1288
1289 /**
1290 * Appends an object to the builder padding on the left to a fixed width.
1291 * The <code>String.valueOf</code> of the <code>int</code> value is used.
1292 * If the formatted value is larger than the length, the left hand side is lost.
1293 *
1294 * @param value the value to append
1295 * @param width the fixed field width, zero or negative has no effect
1296 * @param padChar the pad character to use
1297 * @return this, to enable chaining
1298 */
1299 public StrBuilder appendFixedWidthPadLeft(int value, int width, char padChar) {
1300 return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
1301 }
1302
1303 /**
1304 * Appends an object to the builder padding on the right to a fixed length.
1305 * The <code>toString</code> of the object is used.
1306 * If the object is larger than the length, the right hand side is lost.
1307 * If the object is null, null text value is used.
1308 *
1309 * @param obj the object to append, null uses null text
1310 * @param width the fixed field width, zero or negative has no effect
1311 * @param padChar the pad character to use
1312 * @return this, to enable chaining
1313 */
1314 public StrBuilder appendFixedWidthPadRight(Object obj, int width, char padChar) {
1315 if (width > 0) {
1316 ensureCapacity(size + width);
1317 String str = (obj == null ? getNullText() : obj.toString());
1318 if (str == null) {
1319 str = "";
1320 }
1321 int strLen = str.length();
1322 if (strLen >= width) {
1323 str.getChars(0, width, buffer, size);
1324 } else {
1325 int padLen = width - strLen;
1326 str.getChars(0, strLen, buffer, size);
1327 for (int i = 0; i < padLen; i++) {
1328 buffer[size + strLen + i] = padChar;
1329 }
1330 }
1331 size += width;
1332 }
1333 return this;
1334 }
1335
1336 /**
1337 * Appends an object to the builder padding on the right to a fixed length.
1338 * The <code>String.valueOf</code> of the <code>int</code> value is used.
1339 * If the object is larger than the length, the right hand side is lost.
1340 *
1341 * @param value the value to append
1342 * @param width the fixed field width, zero or negative has no effect
1343 * @param padChar the pad character to use
1344 * @return this, to enable chaining
1345 */
1346 public StrBuilder appendFixedWidthPadRight(int value, int width, char padChar) {
1347 return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
1348 }
1349
1350 //-----------------------------------------------------------------------
1351 /**
1352 * Inserts the string representation of an object into this builder.
1353 * Inserting null will use the stored null text value.
1354 *
1355 * @param index the index to add at, must be valid
1356 * @param obj the object to insert
1357 * @return this, to enable chaining
1358 * @throws IndexOutOfBoundsException if the index is invalid
1359 */
1360 public StrBuilder insert(int index, Object obj) {
1361 if (obj == null) {
1362 return insert(index, nullText);
1363 }
1364 return insert(index, obj.toString());
1365 }
1366
1367 /**
1368 * Inserts the string into this builder.
1369 * Inserting null will use the stored null text value.
1370 *
1371 * @param index the index to add at, must be valid
1372 * @param str the string to insert
1373 * @return this, to enable chaining
1374 * @throws IndexOutOfBoundsException if the index is invalid
1375 */
1376 @SuppressWarnings("null") // str cannot be null
1377 public StrBuilder insert(int index, String str) {
1378 validateIndex(index);
1379 if (str == null) {
1380 str = nullText;
1381 }
1382 int strLen = (str == null ? 0 : str.length());
1383 if (strLen > 0) {
1384 int newSize = size + strLen;
1385 ensureCapacity(newSize);
1386 System.arraycopy(buffer, index, buffer, index + strLen, size - index);
1387 size = newSize;
1388 str.getChars(0, strLen, buffer, index); // str cannot be null here
1389 }
1390 return this;
1391 }
1392
1393 /**
1394 * Inserts the character array into this builder.
1395 * Inserting null will use the stored null text value.
1396 *
1397 * @param index the index to add at, must be valid
1398 * @param chars the char array to insert
1399 * @return this, to enable chaining
1400 * @throws IndexOutOfBoundsException if the index is invalid
1401 */
1402 public StrBuilder insert(int index, char chars[]) {
1403 validateIndex(index);
1404 if (chars == null) {
1405 return insert(index, nullText);
1406 }
1407 int len = chars.length;
1408 if (len > 0) {
1409 ensureCapacity(size + len);
1410 System.arraycopy(buffer, index, buffer, index + len, size - index);
1411 System.arraycopy(chars, 0, buffer, index, len);
1412 size += len;
1413 }
1414 return this;
1415 }
1416
1417 /**
1418 * Inserts part of the character array into this builder.
1419 * Inserting null will use the stored null text value.
1420 *
1421 * @param index the index to add at, must be valid
1422 * @param chars the char array to insert
1423 * @param offset the offset into the character array to start at, must be valid
1424 * @param length the length of the character array part to copy, must be positive
1425 * @return this, to enable chaining
1426 * @throws IndexOutOfBoundsException if any index is invalid
1427 */
1428 public StrBuilder insert(int index, char chars[], int offset, int length) {
1429 validateIndex(index);
1430 if (chars == null) {
1431 return insert(index, nullText);
1432 }
1433 if (offset < 0 || offset > chars.length) {
1434 throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
1435 }
1436 if (length < 0 || offset + length > chars.length) {
1437 throw new StringIndexOutOfBoundsException("Invalid length: " + length);
1438 }
1439 if (length > 0) {
1440 ensureCapacity(size + length);
1441 System.arraycopy(buffer, index, buffer, index + length, size - index);
1442 System.arraycopy(chars, offset, buffer, index, length);
1443 size += length;
1444 }
1445 return this;
1446 }
1447
1448 /**
1449 * Inserts the value into this builder.
1450 *
1451 * @param index the index to add at, must be valid
1452 * @param value the value to insert
1453 * @return this, to enable chaining
1454 * @throws IndexOutOfBoundsException if the index is invalid
1455 */
1456 public StrBuilder insert(int index, boolean value) {
1457 validateIndex(index);
1458 if (value) {
1459 ensureCapacity(size + 4);
1460 System.arraycopy(buffer, index, buffer, index + 4, size - index);
1461 buffer[index++] = 't';
1462 buffer[index++] = 'r';
1463 buffer[index++] = 'u';
1464 buffer[index] = 'e';
1465 size += 4;
1466 } else {
1467 ensureCapacity(size + 5);
1468 System.arraycopy(buffer, index, buffer, index + 5, size - index);
1469 buffer[index++] = 'f';
1470 buffer[index++] = 'a';
1471 buffer[index++] = 'l';
1472 buffer[index++] = 's';
1473 buffer[index] = 'e';
1474 size += 5;
1475 }
1476 return this;
1477 }
1478
1479 /**
1480 * Inserts the value into this builder.
1481 *
1482 * @param index the index to add at, must be valid
1483 * @param value the value to insert
1484 * @return this, to enable chaining
1485 * @throws IndexOutOfBoundsException if the index is invalid
1486 */
1487 public StrBuilder insert(int index, char value) {
1488 validateIndex(index);
1489 ensureCapacity(size + 1);
1490 System.arraycopy(buffer, index, buffer, index + 1, size - index);
1491 buffer[index] = value;
1492 size++;
1493 return this;
1494 }
1495
1496 /**
1497 * Inserts the value into this builder.
1498 *
1499 * @param index the index to add at, must be valid
1500 * @param value the value to insert
1501 * @return this, to enable chaining
1502 * @throws IndexOutOfBoundsException if the index is invalid
1503 */
1504 public StrBuilder insert(int index, int value) {
1505 return insert(index, String.valueOf(value));
1506 }
1507
1508 /**
1509 * Inserts the value into this builder.
1510 *
1511 * @param index the index to add at, must be valid
1512 * @param value the value to insert
1513 * @return this, to enable chaining
1514 * @throws IndexOutOfBoundsException if the index is invalid
1515 */
1516 public StrBuilder insert(int index, long value) {
1517 return insert(index, String.valueOf(value));
1518 }
1519
1520 /**
1521 * Inserts the value into this builder.
1522 *
1523 * @param index the index to add at, must be valid
1524 * @param value the value to insert
1525 * @return this, to enable chaining
1526 * @throws IndexOutOfBoundsException if the index is invalid
1527 */
1528 public StrBuilder insert(int index, float value) {
1529 return insert(index, String.valueOf(value));
1530 }
1531
1532 /**
1533 * Inserts the value into this builder.
1534 *
1535 * @param index the index to add at, must be valid
1536 * @param value the value to insert
1537 * @return this, to enable chaining
1538 * @throws IndexOutOfBoundsException if the index is invalid
1539 */
1540 public StrBuilder insert(int index, double value) {
1541 return insert(index, String.valueOf(value));
1542 }
1543
1544 //-----------------------------------------------------------------------
1545 /**
1546 * Internal method to delete a range without validation.
1547 *
1548 * @param startIndex the start index, must be valid
1549 * @param endIndex the end index (exclusive), must be valid
1550 * @param len the length, must be valid
1551 * @throws IndexOutOfBoundsException if any index is invalid
1552 */
1553 private void deleteImpl(int startIndex, int endIndex, int len) {
1554 System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
1555 size -= len;
1556 }
1557
1558 /**
1559 * Deletes the characters between the two specified indices.
1560 *
1561 * @param startIndex the start index, inclusive, must be valid
1562 * @param endIndex the end index, exclusive, must be valid except
1563 * that if too large it is treated as end of string
1564 * @return this, to enable chaining
1565 * @throws IndexOutOfBoundsException if the index is invalid
1566 */
1567 public StrBuilder delete(int startIndex, int endIndex) {
1568 endIndex = validateRange(startIndex, endIndex);
1569 int len = endIndex - startIndex;
1570 if (len > 0) {
1571 deleteImpl(startIndex, endIndex, len);
1572 }
1573 return this;
1574 }
1575
1576 //-----------------------------------------------------------------------
1577 /**
1578 * Deletes the character wherever it occurs in the builder.
1579 *
1580 * @param ch the character to delete
1581 * @return this, to enable chaining
1582 */
1583 public StrBuilder deleteAll(char ch) {
1584 for (int i = 0; i < size; i++) {
1585 if (buffer[i] == ch) {
1586 int start = i;
1587 while (++i < size) {
1588 if (buffer[i] != ch) {
1589 break;
1590 }
1591 }
1592 int len = i - start;
1593 deleteImpl(start, i, len);
1594 i -= len;
1595 }
1596 }
1597 return this;
1598 }
1599
1600 /**
1601 * Deletes the character wherever it occurs in the builder.
1602 *
1603 * @param ch the character to delete
1604 * @return this, to enable chaining
1605 */
1606 public StrBuilder deleteFirst(char ch) {
1607 for (int i = 0; i < size; i++) {
1608 if (buffer[i] == ch) {
1609 deleteImpl(i, i + 1, 1);
1610 break;
1611 }
1612 }
1613 return this;
1614 }
1615
1616 //-----------------------------------------------------------------------
1617 /**
1618 * Deletes the string wherever it occurs in the builder.
1619 *
1620 * @param str the string to delete, null causes no action
1621 * @return this, to enable chaining
1622 */
1623 public StrBuilder deleteAll(String str) {
1624 int len = (str == null ? 0 : str.length());
1625 if (len > 0) {
1626 int index = indexOf(str, 0);
1627 while (index >= 0) {
1628 deleteImpl(index, index + len, len);
1629 index = indexOf(str, index);
1630 }
1631 }
1632 return this;
1633 }
1634
1635 /**
1636 * Deletes the string wherever it occurs in the builder.
1637 *
1638 * @param str the string to delete, null causes no action
1639 * @return this, to enable chaining
1640 */
1641 public StrBuilder deleteFirst(String str) {
1642 int len = (str == null ? 0 : str.length());
1643 if (len > 0) {
1644 int index = indexOf(str, 0);
1645 if (index >= 0) {
1646 deleteImpl(index, index + len, len);
1647 }
1648 }
1649 return this;
1650 }
1651
1652 //-----------------------------------------------------------------------
1653 /**
1654 * Deletes all parts of the builder that the matcher matches.
1655 * <p>
1656 * Matchers can be used to perform advanced deletion behaviour.
1657 * For example you could write a matcher to delete all occurances
1658 * where the character 'a' is followed by a number.
1659 *
1660 * @param matcher the matcher to use to find the deletion, null causes no action
1661 * @return this, to enable chaining
1662 */
1663 public StrBuilder deleteAll(StrMatcher matcher) {
1664 return replace(matcher, null, 0, size, -1);
1665 }
1666
1667 /**
1668 * Deletes the first match within the builder using the specified matcher.
1669 * <p>
1670 * Matchers can be used to perform advanced deletion behaviour.
1671 * For example you could write a matcher to delete
1672 * where the character 'a' is followed by a number.
1673 *
1674 * @param matcher the matcher to use to find the deletion, null causes no action
1675 * @return this, to enable chaining
1676 */
1677 public StrBuilder deleteFirst(StrMatcher matcher) {
1678 return replace(matcher, null, 0, size, 1);
1679 }
1680
1681 //-----------------------------------------------------------------------
1682 /**
1683 * Internal method to delete a range without validation.
1684 *
1685 * @param startIndex the start index, must be valid
1686 * @param endIndex the end index (exclusive), must be valid
1687 * @param removeLen the length to remove (endIndex - startIndex), must be valid
1688 * @param insertStr the string to replace with, null means delete range
1689 * @param insertLen the length of the insert string, must be valid
1690 * @throws IndexOutOfBoundsException if any index is invalid
1691 */
1692 private void replaceImpl(int startIndex, int endIndex, int removeLen, String insertStr, int insertLen) {
1693 int newSize = size - removeLen + insertLen;
1694 if (insertLen != removeLen) {
1695 ensureCapacity(newSize);
1696 System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
1697 size = newSize;
1698 }
1699 if (insertLen > 0) {
1700 insertStr.getChars(0, insertLen, buffer, startIndex);
1701 }
1702 }
1703
1704 /**
1705 * Replaces a portion of the string builder with another string.
1706 * The length of the inserted string does not have to match the removed length.
1707 *
1708 * @param startIndex the start index, inclusive, must be valid
1709 * @param endIndex the end index, exclusive, must be valid except
1710 * that if too large it is treated as end of string
1711 * @param replaceStr the string to replace with, null means delete range
1712 * @return this, to enable chaining
1713 * @throws IndexOutOfBoundsException if the index is invalid
1714 */
1715 public StrBuilder replace(int startIndex, int endIndex, String replaceStr) {
1716 endIndex = validateRange(startIndex, endIndex);
1717 int insertLen = (replaceStr == null ? 0 : replaceStr.length());
1718 replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
1719 return this;
1720 }
1721
1722 //-----------------------------------------------------------------------
1723 /**
1724 * Replaces the search character with the replace character
1725 * throughout the builder.
1726 *
1727 * @param search the search character
1728 * @param replace the replace character
1729 * @return this, to enable chaining
1730 */
1731 public StrBuilder replaceAll(char search, char replace) {
1732 if (search != replace) {
1733 for (int i = 0; i < size; i++) {
1734 if (buffer[i] == search) {
1735 buffer[i] = replace;
1736 }
1737 }
1738 }
1739 return this;
1740 }
1741
1742 /**
1743 * Replaces the first instance of the search character with the
1744 * replace character in the builder.
1745 *
1746 * @param search the search character
1747 * @param replace the replace character
1748 * @return this, to enable chaining
1749 */
1750 public StrBuilder replaceFirst(char search, char replace) {
1751 if (search != replace) {
1752 for (int i = 0; i < size; i++) {
1753 if (buffer[i] == search) {
1754 buffer[i] = replace;
1755 break;
1756 }
1757 }
1758 }
1759 return this;
1760 }
1761
1762 //-----------------------------------------------------------------------
1763 /**
1764 * Replaces the search string with the replace string throughout the builder.
1765 *
1766 * @param searchStr the search string, null causes no action to occur
1767 * @param replaceStr the replace string, null is equivalent to an empty string
1768 * @return this, to enable chaining
1769 */
1770 public StrBuilder replaceAll(String searchStr, String replaceStr) {
1771 int searchLen = (searchStr == null ? 0 : searchStr.length());
1772 if (searchLen > 0) {
1773 int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
1774 int index = indexOf(searchStr, 0);
1775 while (index >= 0) {
1776 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
1777 index = indexOf(searchStr, index + replaceLen);
1778 }
1779 }
1780 return this;
1781 }
1782
1783 /**
1784 * Replaces the first instance of the search string with the replace string.
1785 *
1786 * @param searchStr the search string, null causes no action to occur
1787 * @param replaceStr the replace string, null is equivalent to an empty string
1788 * @return this, to enable chaining
1789 */
1790 public StrBuilder replaceFirst(String searchStr, String replaceStr) {
1791 int searchLen = (searchStr == null ? 0 : searchStr.length());
1792 if (searchLen > 0) {
1793 int index = indexOf(searchStr, 0);
1794 if (index >= 0) {
1795 int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
1796 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
1797 }
1798 }
1799 return this;
1800 }
1801
1802 //-----------------------------------------------------------------------
1803 /**
1804 * Replaces all matches within the builder with the replace string.
1805 * <p>
1806 * Matchers can be used to perform advanced replace behaviour.
1807 * For example you could write a matcher to replace all occurances
1808 * where the character 'a' is followed by a number.
1809 *
1810 * @param matcher the matcher to use to find the deletion, null causes no action
1811 * @param replaceStr the replace string, null is equivalent to an empty string
1812 * @return this, to enable chaining
1813 */
1814 public StrBuilder replaceAll(StrMatcher matcher, String replaceStr) {
1815 return replace(matcher, replaceStr, 0, size, -1);
1816 }
1817
1818 /**
1819 * Replaces the first match within the builder with the replace string.
1820 * <p>
1821 * Matchers can be used to perform advanced replace behaviour.
1822 * For example you could write a matcher to replace
1823 * where the character 'a' is followed by a number.
1824 *
1825 * @param matcher the matcher to use to find the deletion, null causes no action
1826 * @param replaceStr the replace string, null is equivalent to an empty string
1827 * @return this, to enable chaining
1828 */
1829 public StrBuilder replaceFirst(StrMatcher matcher, String replaceStr) {
1830 return replace(matcher, replaceStr, 0, size, 1);
1831 }
1832
1833 // -----------------------------------------------------------------------
1834 /**
1835 * Advanced search and replaces within the builder using a matcher.
1836 * <p>
1837 * Matchers can be used to perform advanced behaviour.
1838 * For example you could write a matcher to delete all occurances
1839 * where the character 'a' is followed by a number.
1840 *
1841 * @param matcher the matcher to use to find the deletion, null causes no action
1842 * @param replaceStr the string to replace the match with, null is a delete
1843 * @param startIndex the start index, inclusive, must be valid
1844 * @param endIndex the end index, exclusive, must be valid except
1845 * that if too large it is treated as end of string
1846 * @param replaceCount the number of times to replace, -1 for replace all
1847 * @return this, to enable chaining
1848 * @throws IndexOutOfBoundsException if start index is invalid
1849 */
1850 public StrBuilder replace(
1851 StrMatcher matcher, String replaceStr,
1852 int startIndex, int endIndex, int replaceCount) {
1853 endIndex = validateRange(startIndex, endIndex);
1854 return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
1855 }
1856
1857 /**
1858 * Replaces within the builder using a matcher.
1859 * <p>
1860 * Matchers can be used to perform advanced behaviour.
1861 * For example you could write a matcher to delete all occurances
1862 * where the character 'a' is followed by a number.
1863 *
1864 * @param matcher the matcher to use to find the deletion, null causes no action
1865 * @param replaceStr the string to replace the match with, null is a delete
1866 * @param from the start index, must be valid
1867 * @param to the end index (exclusive), must be valid
1868 * @param replaceCount the number of times to replace, -1 for replace all
1869 * @return this, to enable chaining
1870 * @throws IndexOutOfBoundsException if any index is invalid
1871 */
1872 private StrBuilder replaceImpl(
1873 StrMatcher matcher, String replaceStr,
1874 int from, int to, int replaceCount) {
1875 if (matcher == null || size == 0) {
1876 return this;
1877 }
1878 int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
1879 char[] buf = buffer;
1880 for (int i = from; i < to && replaceCount != 0; i++) {
1881 int removeLen = matcher.isMatch(buf, i, from, to);
1882 if (removeLen > 0) {
1883 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
1884 to = to - removeLen + replaceLen;
1885 i = i + replaceLen - 1;
1886 if (replaceCount > 0) {
1887 replaceCount--;
1888 }
1889 }
1890 }
1891 return this;
1892 }
1893
1894 //-----------------------------------------------------------------------
1895 /**
1896 * Reverses the string builder placing each character in the opposite index.
1897 *
1898 * @return this, to enable chaining
1899 */
1900 public StrBuilder reverse() {
1901 if (size == 0) {
1902 return this;
1903 }
1904
1905 int half = size / 2;
1906 char[] buf = buffer;
1907 for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++,rightIdx--) {
1908 char swap = buf[leftIdx];
1909 buf[leftIdx] = buf[rightIdx];
1910 buf[rightIdx] = swap;
1911 }
1912 return this;
1913 }
1914
1915 //-----------------------------------------------------------------------
1916 /**
1917 * Trims the builder by removing characters less than or equal to a space
1918 * from the beginning and end.
1919 *
1920 * @return this, to enable chaining
1921 */
1922 public StrBuilder trim() {
1923 if (size == 0) {
1924 return this;
1925 }
1926 int len = size;
1927 char[] buf = buffer;
1928 int pos = 0;
1929 while (pos < len && buf[pos] <= ' ') {
1930 pos++;
1931 }
1932 while (pos < len && buf[len - 1] <= ' ') {
1933 len--;
1934 }
1935 if (len < size) {
1936 delete(len, size);
1937 }
1938 if (pos > 0) {
1939 delete(0, pos);
1940 }
1941 return this;
1942 }
1943
1944 //-----------------------------------------------------------------------
1945 /**
1946 * Checks whether this builder starts with the specified string.
1947 * <p>
1948 * Note that this method handles null input quietly, unlike String.
1949 *
1950 * @param str the string to search for, null returns false
1951 * @return true if the builder starts with the string
1952 */
1953 public boolean startsWith(String str) {
1954 if (str == null) {
1955 return false;
1956 }
1957 int len = str.length();
1958 if (len == 0) {
1959 return true;
1960 }
1961 if (len > size) {
1962 return false;
1963 }
1964 for (int i = 0; i < len; i++) {
1965 if (buffer[i] != str.charAt(i)) {
1966 return false;
1967 }
1968 }
1969 return true;
1970 }
1971
1972 /**
1973 * Checks whether this builder ends with the specified string.
1974 * <p>
1975 * Note that this method handles null input quietly, unlike String.
1976 *
1977 * @param str the string to search for, null returns false
1978 * @return true if the builder ends with the string
1979 */
1980 public boolean endsWith(String str) {
1981 if (str == null) {
1982 return false;
1983 }
1984 int len = str.length();
1985 if (len == 0) {
1986 return true;
1987 }
1988 if (len > size) {
1989 return false;
1990 }
1991 int pos = size - len;
1992 for (int i = 0; i < len; i++,pos++) {
1993 if (buffer[pos] != str.charAt(i)) {
1994 return false;
1995 }
1996 }
1997 return true;
1998 }
1999
2000 //-----------------------------------------------------------------------
2001 /**
2002 * {@inheritDoc}
2003 * @since 3.0
2004 */
2005 public CharSequence subSequence(int startIndex, int endIndex) {
2006 if (startIndex < 0) {
2007 throw new StringIndexOutOfBoundsException(startIndex);
2008 }
2009 if (endIndex > size) {
2010 throw new StringIndexOutOfBoundsException(endIndex);
2011 }
2012 if (startIndex > endIndex) {
2013 throw new StringIndexOutOfBoundsException(endIndex - startIndex);
2014 }
2015 return substring(startIndex, endIndex);
2016 }
2017
2018 /**
2019 * Extracts a portion of this string builder as a string.
2020 *
2021 * @param start the start index, inclusive, must be valid
2022 * @return the new string
2023 * @throws IndexOutOfBoundsException if the index is invalid
2024 */
2025 public String substring(int start) {
2026 return substring(start, size);
2027 }
2028
2029 /**
2030 * Extracts a portion of this string builder as a string.
2031 * <p>
2032 * Note: This method treats an endIndex greater than the length of the
2033 * builder as equal to the length of the builder, and continues
2034 * without error, unlike StringBuffer or String.
2035 *
2036 * @param startIndex the start index, inclusive, must be valid
2037 * @param endIndex the end index, exclusive, must be valid except
2038 * that if too large it is treated as end of string
2039 * @return the new string
2040 * @throws IndexOutOfBoundsException if the index is invalid
2041 */
2042 public String substring(int startIndex, int endIndex) {
2043 endIndex = validateRange(startIndex, endIndex);
2044 return new String(buffer, startIndex, endIndex - startIndex);
2045 }
2046
2047 /**
2048 * Extracts the leftmost characters from the string builder without
2049 * throwing an exception.
2050 * <p>
2051 * This method extracts the left <code>length</code> characters from
2052 * the builder. If this many characters are not available, the whole
2053 * builder is returned. Thus the returned string may be shorter than the
2054 * length requested.
2055 *
2056 * @param length the number of characters to extract, negative returns empty string
2057 * @return the new string
2058 */
2059 public String leftString(int length) {
2060 if (length <= 0) {
2061 return "";
2062 } else if (length >= size) {
2063 return new String(buffer, 0, size);
2064 } else {
2065 return new String(buffer, 0, length);
2066 }
2067 }
2068
2069 /**
2070 * Extracts the rightmost characters from the string builder without
2071 * throwing an exception.
2072 * <p>
2073 * This method extracts the right <code>length</code> characters from
2074 * the builder. If this many characters are not available, the whole
2075 * builder is returned. Thus the returned string may be shorter than the
2076 * length requested.
2077 *
2078 * @param length the number of characters to extract, negative returns empty string
2079 * @return the new string
2080 */
2081 public String rightString(int length) {
2082 if (length <= 0) {
2083 return "";
2084 } else if (length >= size) {
2085 return new String(buffer, 0, size);
2086 } else {
2087 return new String(buffer, size - length, length);
2088 }
2089 }
2090
2091 /**
2092 * Extracts some characters from the middle of the string builder without
2093 * throwing an exception.
2094 * <p>
2095 * This method extracts <code>length</code> characters from the builder
2096 * at the specified index.
2097 * If the index is negative it is treated as zero.
2098 * If the index is greater than the builder size, it is treated as the builder size.
2099 * If the length is negative, the empty string is returned.
2100 * If insufficient characters are available in the builder, as much as possible is returned.
2101 * Thus the returned string may be shorter than the length requested.
2102 *
2103 * @param index the index to start at, negative means zero
2104 * @param length the number of characters to extract, negative returns empty string
2105 * @return the new string
2106 */
2107 public String midString(int index, int length) {
2108 if (index < 0) {
2109 index = 0;
2110 }
2111 if (length <= 0 || index >= size) {
2112 return "";
2113 }
2114 if (size <= index + length) {
2115 return new String(buffer, index, size - index);
2116 } else {
2117 return new String(buffer, index, length);
2118 }
2119 }
2120
2121 //-----------------------------------------------------------------------
2122 /**
2123 * Checks if the string builder contains the specified char.
2124 *
2125 * @param ch the character to find
2126 * @return true if the builder contains the character
2127 */
2128 public boolean contains(char ch) {
2129 char[] thisBuf = buffer;
2130 for (int i = 0; i < this.size; i++) {
2131 if (thisBuf[i] == ch) {
2132 return true;
2133 }
2134 }
2135 return false;
2136 }
2137
2138 /**
2139 * Checks if the string builder contains the specified string.
2140 *
2141 * @param str the string to find
2142 * @return true if the builder contains the string
2143 */
2144 public boolean contains(String str) {
2145 return indexOf(str, 0) >= 0;
2146 }
2147
2148 /**
2149 * Checks if the string builder contains a string matched using the
2150 * specified matcher.
2151 * <p>
2152 * Matchers can be used to perform advanced searching behaviour.
2153 * For example you could write a matcher to search for the character
2154 * 'a' followed by a number.
2155 *
2156 * @param matcher the matcher to use, null returns -1
2157 * @return true if the matcher finds a match in the builder
2158 */
2159 public boolean contains(StrMatcher matcher) {
2160 return indexOf(matcher, 0) >= 0;
2161 }
2162
2163 //-----------------------------------------------------------------------
2164 /**
2165 * Searches the string builder to find the first reference to the specified char.
2166 *
2167 * @param ch the character to find
2168 * @return the first index of the character, or -1 if not found
2169 */
2170 public int indexOf(char ch) {
2171 return indexOf(ch, 0);
2172 }
2173
2174 /**
2175 * Searches the string builder to find the first reference to the specified char.
2176 *
2177 * @param ch the character to find
2178 * @param startIndex the index to start at, invalid index rounded to edge
2179 * @return the first index of the character, or -1 if not found
2180 */
2181 public int indexOf(char ch, int startIndex) {
2182 startIndex = (startIndex < 0 ? 0 : startIndex);
2183 if (startIndex >= size) {
2184 return -1;
2185 }
2186 char[] thisBuf = buffer;
2187 for (int i = startIndex; i < size; i++) {
2188 if (thisBuf[i] == ch) {
2189 return i;
2190 }
2191 }
2192 return -1;
2193 }
2194
2195 /**
2196 * Searches the string builder to find the first reference to the specified string.
2197 * <p>
2198 * Note that a null input string will return -1, whereas the JDK throws an exception.
2199 *
2200 * @param str the string to find, null returns -1
2201 * @return the first index of the string, or -1 if not found
2202 */
2203 public int indexOf(String str) {
2204 return indexOf(str, 0);
2205 }
2206
2207 /**
2208 * Searches the string builder to find the first reference to the specified
2209 * string starting searching from the given index.
2210 * <p>
2211 * Note that a null input string will return -1, whereas the JDK throws an exception.
2212 *
2213 * @param str the string to find, null returns -1
2214 * @param startIndex the index to start at, invalid index rounded to edge
2215 * @return the first index of the string, or -1 if not found
2216 */
2217 public int indexOf(String str, int startIndex) {
2218 startIndex = (startIndex < 0 ? 0 : startIndex);
2219 if (str == null || startIndex >= size) {
2220 return -1;
2221 }
2222 int strLen = str.length();
2223 if (strLen == 1) {
2224 return indexOf(str.charAt(0), startIndex);
2225 }
2226 if (strLen == 0) {
2227 return startIndex;
2228 }
2229 if (strLen > size) {
2230 return -1;
2231 }
2232 char[] thisBuf = buffer;
2233 int len = size - strLen + 1;
2234 outer:
2235 for (int i = startIndex; i < len; i++) {
2236 for (int j = 0; j < strLen; j++) {
2237 if (str.charAt(j) != thisBuf[i + j]) {
2238 continue outer;
2239 }
2240 }
2241 return i;
2242 }
2243 return -1;
2244 }
2245
2246 /**
2247 * Searches the string builder using the matcher to find the first match.
2248 * <p>
2249 * Matchers can be used to perform advanced searching behaviour.
2250 * For example you could write a matcher to find the character 'a'
2251 * followed by a number.
2252 *
2253 * @param matcher the matcher to use, null returns -1
2254 * @return the first index matched, or -1 if not found
2255 */
2256 public int indexOf(StrMatcher matcher) {
2257 return indexOf(matcher, 0);
2258 }
2259
2260 /**
2261 * Searches the string builder using the matcher to find the first
2262 * match searching from the given index.
2263 * <p>
2264 * Matchers can be used to perform advanced searching behaviour.
2265 * For example you could write a matcher to find the character 'a'
2266 * followed by a number.
2267 *
2268 * @param matcher the matcher to use, null returns -1
2269 * @param startIndex the index to start at, invalid index rounded to edge
2270 * @return the first index matched, or -1 if not found
2271 */
2272 public int indexOf(StrMatcher matcher, int startIndex) {
2273 startIndex = (startIndex < 0 ? 0 : startIndex);
2274 if (matcher == null || startIndex >= size) {
2275 return -1;
2276 }
2277 int len = size;
2278 char[] buf = buffer;
2279 for (int i = startIndex; i < len; i++) {
2280 if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2281 return i;
2282 }
2283 }
2284 return -1;
2285 }
2286
2287 //-----------------------------------------------------------------------
2288 /**
2289 * Searches the string builder to find the last reference to the specified char.
2290 *
2291 * @param ch the character to find
2292 * @return the last index of the character, or -1 if not found
2293 */
2294 public int lastIndexOf(char ch) {
2295 return lastIndexOf(ch, size - 1);
2296 }
2297
2298 /**
2299 * Searches the string builder to find the last reference to the specified char.
2300 *
2301 * @param ch the character to find
2302 * @param startIndex the index to start at, invalid index rounded to edge
2303 * @return the last index of the character, or -1 if not found
2304 */
2305 public int lastIndexOf(char ch, int startIndex) {
2306 startIndex = (startIndex >= size ? size - 1 : startIndex);
2307 if (startIndex < 0) {
2308 return -1;
2309 }
2310 for (int i = startIndex; i >= 0; i--) {
2311 if (buffer[i] == ch) {
2312 return i;
2313 }
2314 }
2315 return -1;
2316 }
2317
2318 /**
2319 * Searches the string builder to find the last reference to the specified string.
2320 * <p>
2321 * Note that a null input string will return -1, whereas the JDK throws an exception.
2322 *
2323 * @param str the string to find, null returns -1
2324 * @return the last index of the string, or -1 if not found
2325 */
2326 public int lastIndexOf(String str) {
2327 return lastIndexOf(str, size - 1);
2328 }
2329
2330 /**
2331 * Searches the string builder to find the last reference to the specified
2332 * string starting searching from the given index.
2333 * <p>
2334 * Note that a null input string will return -1, whereas the JDK throws an exception.
2335 *
2336 * @param str the string to find, null returns -1
2337 * @param startIndex the index to start at, invalid index rounded to edge
2338 * @return the last index of the string, or -1 if not found
2339 */
2340 public int lastIndexOf(String str, int startIndex) {
2341 startIndex = (startIndex >= size ? size - 1 : startIndex);
2342 if (str == null || startIndex < 0) {
2343 return -1;
2344 }
2345 int strLen = str.length();
2346 if (strLen > 0 && strLen <= size) {
2347 if (strLen == 1) {
2348 return lastIndexOf(str.charAt(0), startIndex);
2349 }
2350
2351 outer:
2352 for (int i = startIndex - strLen + 1; i >= 0; i--) {
2353 for (int j = 0; j < strLen; j++) {
2354 if (str.charAt(j) != buffer[i + j]) {
2355 continue outer;
2356 }
2357 }
2358 return i;
2359 }
2360
2361 } else if (strLen == 0) {
2362 return startIndex;
2363 }
2364 return -1;
2365 }
2366
2367 /**
2368 * Searches the string builder using the matcher to find the last match.
2369 * <p>
2370 * Matchers can be used to perform advanced searching behaviour.
2371 * For example you could write a matcher to find the character 'a'
2372 * followed by a number.
2373 *
2374 * @param matcher the matcher to use, null returns -1
2375 * @return the last index matched, or -1 if not found
2376 */
2377 public int lastIndexOf(StrMatcher matcher) {
2378 return lastIndexOf(matcher, size);
2379 }
2380
2381 /**
2382 * Searches the string builder using the matcher to find the last
2383 * match searching from the given index.
2384 * <p>
2385 * Matchers can be used to perform advanced searching behaviour.
2386 * For example you could write a matcher to find the character 'a'
2387 * followed by a number.
2388 *
2389 * @param matcher the matcher to use, null returns -1
2390 * @param startIndex the index to start at, invalid index rounded to edge
2391 * @return the last index matched, or -1 if not found
2392 */
2393 public int lastIndexOf(StrMatcher matcher, int startIndex) {
2394 startIndex = (startIndex >= size ? size - 1 : startIndex);
2395 if (matcher == null || startIndex < 0) {
2396 return -1;
2397 }
2398 char[] buf = buffer;
2399 int endIndex = startIndex + 1;
2400 for (int i = startIndex; i >= 0; i--) {
2401 if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2402 return i;
2403 }
2404 }
2405 return -1;
2406 }
2407
2408 //-----------------------------------------------------------------------
2409 /**
2410 * Creates a tokenizer that can tokenize the contents of this builder.
2411 * <p>
2412 * This method allows the contents of this builder to be tokenized.
2413 * The tokenizer will be setup by default to tokenize on space, tab,
2414 * newline and formfeed (as per StringTokenizer). These values can be
2415 * changed on the tokenizer class, before retrieving the tokens.
2416 * <p>
2417 * The returned tokenizer is linked to this builder. You may intermix
2418 * calls to the buider and tokenizer within certain limits, however
2419 * there is no synchronization. Once the tokenizer has been used once,
2420 * it must be {@link StrTokenizer#reset() reset} to pickup the latest
2421 * changes in the builder. For example:
2422 * <pre>
2423 * StrBuilder b = new StrBuilder();
2424 * b.append("a b ");
2425 * StrTokenizer t = b.asTokenizer();
2426 * String[] tokens1 = t.getTokenArray(); // returns a,b
2427 * b.append("c d ");
2428 * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
2429 * t.reset(); // reset causes builder changes to be picked up
2430 * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
2431 * </pre>
2432 * In addition to simply intermixing appends and tokenization, you can also
2433 * call the set methods on the tokenizer to alter how it tokenizes. Just
2434 * remember to call reset when you want to pickup builder changes.
2435 * <p>
2436 * Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])}
2437 * with a non-null value will break the link with the builder.
2438 *
2439 * @return a tokenizer that is linked to this builder
2440 */
2441 public StrTokenizer asTokenizer() {
2442 return new StrBuilderTokenizer();
2443 }
2444
2445 //-----------------------------------------------------------------------
2446 /**
2447 * Gets the contents of this builder as a Reader.
2448 * <p>
2449 * This method allows the contents of the builder to be read
2450 * using any standard method that expects a Reader.
2451 * <p>
2452 * To use, simply create a <code>StrBuilder</code>, populate it with
2453 * data, call <code>asReader</code>, and then read away.
2454 * <p>
2455 * The internal character array is shared between the builder and the reader.
2456 * This allows you to append to the builder after creating the reader,
2457 * and the changes will be picked up.
2458 * Note however, that no synchronization occurs, so you must perform
2459 * all operations with the builder and the reader in one thread.
2460 * <p>
2461 * The returned reader supports marking, and ignores the flush method.
2462 *
2463 * @return a reader that reads from this builder
2464 */
2465 public Reader asReader() {
2466 return new StrBuilderReader();
2467 }
2468
2469 //-----------------------------------------------------------------------
2470 /**
2471 * Gets this builder as a Writer that can be written to.
2472 * <p>
2473 * This method allows you to populate the contents of the builder
2474 * using any standard method that takes a Writer.
2475 * <p>
2476 * To use, simply create a <code>StrBuilder</code>,
2477 * call <code>asWriter</code>, and populate away. The data is available
2478 * at any time using the methods of the <code>StrBuilder</code>.
2479 * <p>
2480 * The internal character array is shared between the builder and the writer.
2481 * This allows you to intermix calls that append to the builder and
2482 * write using the writer and the changes will be occur correctly.
2483 * Note however, that no synchronization occurs, so you must perform
2484 * all operations with the builder and the writer in one thread.
2485 * <p>
2486 * The returned writer ignores the close and flush methods.
2487 *
2488 * @return a writer that populates this builder
2489 */
2490 public Writer asWriter() {
2491 return new StrBuilderWriter();
2492 }
2493
2494 //-----------------------------------------------------------------------
2495 // /**
2496 // * Gets a String version of the string builder by calling the internal
2497 // * constructor of String by reflection.
2498 // * <p>
2499 // * WARNING: You must not use the StrBuilder after calling this method
2500 // * as the buffer is now shared with the String object. To ensure this,
2501 // * the internal character array is set to null, so you will get
2502 // * NullPointerExceptions on all method calls.
2503 // *
2504 // * @return the builder as a String
2505 // */
2506 // public String toSharedString() {
2507 // try {
2508 // Constructor con = String.class.getDeclaredConstructor(
2509 // new Class[] {int.class, int.class, char[].class});
2510 // con.setAccessible(true);
2511 // char[] buffer = buf;
2512 // buf = null;
2513 // size = -1;
2514 // nullText = null;
2515 // return (String) con.newInstance(
2516 // new Object[] {Integer.valueOf(0), Integer.valueOf(size), buffer});
2517 //
2518 // } catch (Exception ex) {
2519 // ex.printStackTrace();
2520 // throw new UnsupportedOperationException("StrBuilder.toSharedString is unsupported: " + ex.getMessage());
2521 // }
2522 // }
2523
2524 //-----------------------------------------------------------------------
2525 /**
2526 * Checks the contents of this builder against another to see if they
2527 * contain the same character content ignoring case.
2528 *
2529 * @param other the object to check, null returns false
2530 * @return true if the builders contain the same characters in the same order
2531 */
2532 public boolean equalsIgnoreCase(StrBuilder other) {
2533 if (this == other) {
2534 return true;
2535 }
2536 if (this.size != other.size) {
2537 return false;
2538 }
2539 char thisBuf[] = this.buffer;
2540 char otherBuf[] = other.buffer;
2541 for (int i = size - 1; i >= 0; i--) {
2542 char c1 = thisBuf[i];
2543 char c2 = otherBuf[i];
2544 if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
2545 return false;
2546 }
2547 }
2548 return true;
2549 }
2550
2551 /**
2552 * Checks the contents of this builder against another to see if they
2553 * contain the same character content.
2554 *
2555 * @param other the object to check, null returns false
2556 * @return true if the builders contain the same characters in the same order
2557 */
2558 public boolean equals(StrBuilder other) {
2559 if (this == other) {
2560 return true;
2561 }
2562 if (this.size != other.size) {
2563 return false;
2564 }
2565 char thisBuf[] = this.buffer;
2566 char otherBuf[] = other.buffer;
2567 for (int i = size - 1; i >= 0; i--) {
2568 if (thisBuf[i] != otherBuf[i]) {
2569 return false;
2570 }
2571 }
2572 return true;
2573 }
2574
2575 /**
2576 * Checks the contents of this builder against another to see if they
2577 * contain the same character content.
2578 *
2579 * @param obj the object to check, null returns false
2580 * @return true if the builders contain the same characters in the same order
2581 */
2582 @Override
2583 public boolean equals(Object obj) {
2584 if (obj instanceof StrBuilder) {
2585 return equals((StrBuilder) obj);
2586 }
2587 return false;
2588 }
2589
2590 /**
2591 * Gets a suitable hash code for this builder.
2592 *
2593 * @return a hash code
2594 */
2595 @Override
2596 public int hashCode() {
2597 char buf[] = buffer;
2598 int hash = 0;
2599 for (int i = size - 1; i >= 0; i--) {
2600 hash = 31 * hash + buf[i];
2601 }
2602 return hash;
2603 }
2604
2605 //-----------------------------------------------------------------------
2606 /**
2607 * Gets a String version of the string builder, creating a new instance
2608 * each time the method is called.
2609 * <p>
2610 * Note that unlike StringBuffer, the string version returned is
2611 * independent of the string builder.
2612 *
2613 * @return the builder as a String
2614 */
2615 @Override
2616 public String toString() {
2617 return new String(buffer, 0, size);
2618 }
2619
2620 /**
2621 * Gets a StringBuffer version of the string builder, creating a
2622 * new instance each time the method is called.
2623 *
2624 * @return the builder as a StringBuffer
2625 */
2626 public StringBuffer toStringBuffer() {
2627 return new StringBuffer(size).append(buffer, 0, size);
2628 }
2629
2630 //-----------------------------------------------------------------------
2631 /**
2632 * Validates parameters defining a range of the builder.
2633 *
2634 * @param startIndex the start index, inclusive, must be valid
2635 * @param endIndex the end index, exclusive, must be valid except
2636 * that if too large it is treated as end of string
2637 * @return the new string
2638 * @throws IndexOutOfBoundsException if the index is invalid
2639 */
2640 protected int validateRange(int startIndex, int endIndex) {
2641 if (startIndex < 0) {
2642 throw new StringIndexOutOfBoundsException(startIndex);
2643 }
2644 if (endIndex > size) {
2645 endIndex = size;
2646 }
2647 if (startIndex > endIndex) {
2648 throw new StringIndexOutOfBoundsException("end < start");
2649 }
2650 return endIndex;
2651 }
2652
2653 /**
2654 * Validates parameters defining a single index in the builder.
2655 *
2656 * @param index the index, must be valid
2657 * @throws IndexOutOfBoundsException if the index is invalid
2658 */
2659 protected void validateIndex(int index) {
2660 if (index < 0 || index > size) {
2661 throw new StringIndexOutOfBoundsException(index);
2662 }
2663 }
2664
2665 //-----------------------------------------------------------------------
2666 /**
2667 * Inner class to allow StrBuilder to operate as a tokenizer.
2668 */
2669 class StrBuilderTokenizer extends StrTokenizer {
2670
2671 /**
2672 * Default constructor.
2673 */
2674 StrBuilderTokenizer() {
2675 super();
2676 }
2677
2678 /** {@inheritDoc} */
2679 @Override
2680 protected List<String> tokenize(char[] chars, int offset, int count) {
2681 if (chars == null) {
2682 return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size());
2683 } else {
2684 return super.tokenize(chars, offset, count);
2685 }
2686 }
2687
2688 /** {@inheritDoc} */
2689 @Override
2690 public String getContent() {
2691 String str = super.getContent();
2692 if (str == null) {
2693 return StrBuilder.this.toString();
2694 } else {
2695 return str;
2696 }
2697 }
2698 }
2699
2700 //-----------------------------------------------------------------------
2701 /**
2702 * Inner class to allow StrBuilder to operate as a writer.
2703 */
2704 class StrBuilderReader extends Reader {
2705 /** The current stream position. */
2706 private int pos;
2707 /** The last mark position. */
2708 private int mark;
2709
2710 /**
2711 * Default constructor.
2712 */
2713 StrBuilderReader() {
2714 super();
2715 }
2716
2717 /** {@inheritDoc} */
2718 @Override
2719 public void close() {
2720 // do nothing
2721 }
2722
2723 /** {@inheritDoc} */
2724 @Override
2725 public int read() {
2726 if (ready() == false) {
2727 return -1;
2728 }
2729 return StrBuilder.this.charAt(pos++);
2730 }
2731
2732 /** {@inheritDoc} */
2733 @Override
2734 public int read(char b[], int off, int len) {
2735 if (off < 0 || len < 0 || off > b.length ||
2736 (off + len) > b.length || (off + len) < 0) {
2737 throw new IndexOutOfBoundsException();
2738 }
2739 if (len == 0) {
2740 return 0;
2741 }
2742 if (pos >= StrBuilder.this.size()) {
2743 return -1;
2744 }
2745 if (pos + len > size()) {
2746 len = StrBuilder.this.size() - pos;
2747 }
2748 StrBuilder.this.getChars(pos, pos + len, b, off);
2749 pos += len;
2750 return len;
2751 }
2752
2753 /** {@inheritDoc} */
2754 @Override
2755 public long skip(long n) {
2756 if (pos + n > StrBuilder.this.size()) {
2757 n = StrBuilder.this.size() - pos;
2758 }
2759 if (n < 0) {
2760 return 0;
2761 }
2762 pos += n;
2763 return n;
2764 }
2765
2766 /** {@inheritDoc} */
2767 @Override
2768 public boolean ready() {
2769 return pos < StrBuilder.this.size();
2770 }
2771
2772 /** {@inheritDoc} */
2773 @Override
2774 public boolean markSupported() {
2775 return true;
2776 }
2777
2778 /** {@inheritDoc} */
2779 @Override
2780 public void mark(int readAheadLimit) {
2781 mark = pos;
2782 }
2783
2784 /** {@inheritDoc} */
2785 @Override
2786 public void reset() {
2787 pos = mark;
2788 }
2789 }
2790
2791 //-----------------------------------------------------------------------
2792 /**
2793 * Inner class to allow StrBuilder to operate as a writer.
2794 */
2795 class StrBuilderWriter extends Writer {
2796
2797 /**
2798 * Default constructor.
2799 */
2800 StrBuilderWriter() {
2801 super();
2802 }
2803
2804 /** {@inheritDoc} */
2805 @Override
2806 public void close() {
2807 // do nothing
2808 }
2809
2810 /** {@inheritDoc} */
2811 @Override
2812 public void flush() {
2813 // do nothing
2814 }
2815
2816 /** {@inheritDoc} */
2817 @Override
2818 public void write(int c) {
2819 StrBuilder.this.append((char) c);
2820 }
2821
2822 /** {@inheritDoc} */
2823 @Override
2824 public void write(char[] cbuf) {
2825 StrBuilder.this.append(cbuf);
2826 }
2827
2828 /** {@inheritDoc} */
2829 @Override
2830 public void write(char[] cbuf, int off, int len) {
2831 StrBuilder.this.append(cbuf, off, len);
2832 }
2833
2834 /** {@inheritDoc} */
2835 @Override
2836 public void write(String str) {
2837 StrBuilder.this.append(str);
2838 }
2839
2840 /** {@inheritDoc} */
2841 @Override
2842 public void write(String str, int off, int len) {
2843 StrBuilder.this.append(str, off, len);
2844 }
2845 }
2846
2847 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import java.util.Map;
19
20 /**
21 * Lookup a String key to a String value.
22 * <p>
23 * This class represents the simplest form of a string to string map.
24 * It has a benefit over a map in that it can create the result on
25 * demand based on the key.
26 * <p>
27 * This class comes complete with various factory methods.
28 * If these do not suffice, you can subclass and implement your own matcher.
29 * <p>
30 * For example, it would be possible to implement a lookup that used the
31 * key as a primary key, and looked up the value on demand from the database
32 *
33 * @since 2.2
34 * @version $Id: StrLookup.java 1153484 2011-08-03 13:39:42Z ggregory $
35 */
36 public abstract class StrLookup<V> {
37
38 /**
39 * Lookup that always returns null.
40 */
41 private static final StrLookup<String> NONE_LOOKUP;
42 /**
43 * Lookup that uses System properties.
44 */
45 private static final StrLookup<String> SYSTEM_PROPERTIES_LOOKUP;
46 static {
47 NONE_LOOKUP = new MapStrLookup<String>(null);
48 StrLookup<String> lookup = null;
49 try {
50 final Map<?, ?> propMap = System.getProperties();
51 @SuppressWarnings("unchecked") // System property keys and values are always Strings
52 final Map<String, String> properties = (Map<String, String>) propMap;
53 lookup = new MapStrLookup<String>(properties);
54 } catch (SecurityException ex) {
55 lookup = NONE_LOOKUP;
56 }
57 SYSTEM_PROPERTIES_LOOKUP = lookup;
58 }
59
60 //-----------------------------------------------------------------------
61 /**
62 * Returns a lookup which always returns null.
63 *
64 * @return a lookup that always returns null, not null
65 */
66 public static StrLookup<?> noneLookup() {
67 return NONE_LOOKUP;
68 }
69
70 /**
71 * Returns a lookup which uses {@link System#getProperties() System properties}
72 * to lookup the key to value.
73 * <p>
74 * If a security manager blocked access to system properties, then null will
75 * be returned from every lookup.
76 * <p>
77 * If a null key is used, this lookup will throw a NullPointerException.
78 *
79 * @return a lookup using system properties, not null
80 */
81 public static StrLookup<String> systemPropertiesLookup() {
82 return SYSTEM_PROPERTIES_LOOKUP;
83 }
84
85 /**
86 * Returns a lookup which looks up values using a map.
87 * <p>
88 * If the map is null, then null will be returned from every lookup.
89 * The map result object is converted to a string using toString().
90 *
91 * @param <V> the type of the values supported by the lookup
92 * @param map the map of keys to values, may be null
93 * @return a lookup using the map, not null
94 */
95 public static <V> StrLookup<V> mapLookup(Map<String, V> map) {
96 return new MapStrLookup<V>(map);
97 }
98
99 //-----------------------------------------------------------------------
100 /**
101 * Constructor.
102 */
103 protected StrLookup() {
104 super();
105 }
106
107 /**
108 * Looks up a String key to a String value.
109 * <p>
110 * The internal implementation may use any mechanism to return the value.
111 * The simplest implementation is to use a Map. However, virtually any
112 * implementation is possible.
113 * <p>
114 * For example, it would be possible to implement a lookup that used the
115 * key as a primary key, and looked up the value on demand from the database
116 * Or, a numeric based implementation could be created that treats the key
117 * as an integer, increments the value and return the result as a string -
118 * converting 1 to 2, 15 to 16 etc.
119 * <p>
120 * The {@link #lookup(String)} method always returns a String, regardless of
121 * the underlying data, by converting it as necessary. For example:
122 * <pre>
123 * Map<String, Object> map = new HashMap<String, Object>();
124 * map.put("number", Integer.valueOf(2));
125 * assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
126 * </pre>
127 * @param key the key to be looked up, may be null
128 * @return the matching value, null if no match
129 */
130 public abstract String lookup(String key);
131
132 //-----------------------------------------------------------------------
133 /**
134 * Lookup implementation that uses a Map.
135 */
136 static class MapStrLookup<V> extends StrLookup<V> {
137
138 /** Map keys are variable names and value. */
139 private final Map<String, V> map;
140
141 /**
142 * Creates a new instance backed by a Map.
143 *
144 * @param map the map of keys to values, may be null
145 */
146 MapStrLookup(Map<String, V> map) {
147 this.map = map;
148 }
149
150 /**
151 * Looks up a String key to a String value using the map.
152 * <p>
153 * If the map is null, then null is returned.
154 * The map result object is converted to a string using toString().
155 *
156 * @param key the key to be looked up, may be null
157 * @return the matching value, null if no match
158 */
159 @Override
160 public String lookup(String key) {
161 if (map == null) {
162 return null;
163 }
164 Object obj = map.get(key);
165 if (obj == null) {
166 return null;
167 }
168 return obj.toString();
169 }
170 }
171 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import java.util.Arrays;
19
20 import org.apache.commons.lang3.StringUtils;
21
22 /**
23 * A matcher class that can be queried to determine if a character array
24 * portion matches.
25 * <p>
26 * This class comes complete with various factory methods.
27 * If these do not suffice, you can subclass and implement your own matcher.
28 *
29 * @since 2.2
30 * @version $Id: StrMatcher.java 1144925 2011-07-10 18:07:05Z ggregory $
31 */
32 public abstract class StrMatcher {
33
34 /**
35 * Matches the comma character.
36 */
37 private static final StrMatcher COMMA_MATCHER = new CharMatcher(',');
38 /**
39 * Matches the tab character.
40 */
41 private static final StrMatcher TAB_MATCHER = new CharMatcher('\t');
42 /**
43 * Matches the space character.
44 */
45 private static final StrMatcher SPACE_MATCHER = new CharMatcher(' ');
46 /**
47 * Matches the same characters as StringTokenizer,
48 * namely space, tab, newline, formfeed.
49 */
50 private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray());
51 /**
52 * Matches the String trim() whitespace characters.
53 */
54 private static final StrMatcher TRIM_MATCHER = new TrimMatcher();
55 /**
56 * Matches the double quote character.
57 */
58 private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\'');
59 /**
60 * Matches the double quote character.
61 */
62 private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"');
63 /**
64 * Matches the single or double quote character.
65 */
66 private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray());
67 /**
68 * Matches no characters.
69 */
70 private static final StrMatcher NONE_MATCHER = new NoMatcher();
71
72 // -----------------------------------------------------------------------
73
74 /**
75 * Returns a matcher which matches the comma character.
76 *
77 * @return a matcher for a comma
78 */
79 public static StrMatcher commaMatcher() {
80 return COMMA_MATCHER;
81 }
82
83 /**
84 * Returns a matcher which matches the tab character.
85 *
86 * @return a matcher for a tab
87 */
88 public static StrMatcher tabMatcher() {
89 return TAB_MATCHER;
90 }
91
92 /**
93 * Returns a matcher which matches the space character.
94 *
95 * @return a matcher for a space
96 */
97 public static StrMatcher spaceMatcher() {
98 return SPACE_MATCHER;
99 }
100
101 /**
102 * Matches the same characters as StringTokenizer,
103 * namely space, tab, newline and formfeed.
104 *
105 * @return the split matcher
106 */
107 public static StrMatcher splitMatcher() {
108 return SPLIT_MATCHER;
109 }
110
111 /**
112 * Matches the String trim() whitespace characters.
113 *
114 * @return the trim matcher
115 */
116 public static StrMatcher trimMatcher() {
117 return TRIM_MATCHER;
118 }
119
120 /**
121 * Returns a matcher which matches the single quote character.
122 *
123 * @return a matcher for a single quote
124 */
125 public static StrMatcher singleQuoteMatcher() {
126 return SINGLE_QUOTE_MATCHER;
127 }
128
129 /**
130 * Returns a matcher which matches the double quote character.
131 *
132 * @return a matcher for a double quote
133 */
134 public static StrMatcher doubleQuoteMatcher() {
135 return DOUBLE_QUOTE_MATCHER;
136 }
137
138 /**
139 * Returns a matcher which matches the single or double quote character.
140 *
141 * @return a matcher for a single or double quote
142 */
143 public static StrMatcher quoteMatcher() {
144 return QUOTE_MATCHER;
145 }
146
147 /**
148 * Matches no characters.
149 *
150 * @return a matcher that matches nothing
151 */
152 public static StrMatcher noneMatcher() {
153 return NONE_MATCHER;
154 }
155
156 /**
157 * Constructor that creates a matcher from a character.
158 *
159 * @param ch the character to match, must not be null
160 * @return a new Matcher for the given char
161 */
162 public static StrMatcher charMatcher(char ch) {
163 return new CharMatcher(ch);
164 }
165
166 /**
167 * Constructor that creates a matcher from a set of characters.
168 *
169 * @param chars the characters to match, null or empty matches nothing
170 * @return a new matcher for the given char[]
171 */
172 public static StrMatcher charSetMatcher(char... chars) {
173 if (chars == null || chars.length == 0) {
174 return NONE_MATCHER;
175 }
176 if (chars.length == 1) {
177 return new CharMatcher(chars[0]);
178 }
179 return new CharSetMatcher(chars);
180 }
181
182 /**
183 * Constructor that creates a matcher from a string representing a set of characters.
184 *
185 * @param chars the characters to match, null or empty matches nothing
186 * @return a new Matcher for the given characters
187 */
188 public static StrMatcher charSetMatcher(String chars) {
189 if (chars == null || chars.length() == 0) {
190 return NONE_MATCHER;
191 }
192 if (chars.length() == 1) {
193 return new CharMatcher(chars.charAt(0));
194 }
195 return new CharSetMatcher(chars.toCharArray());
196 }
197
198 /**
199 * Constructor that creates a matcher from a string.
200 *
201 * @param str the string to match, null or empty matches nothing
202 * @return a new Matcher for the given String
203 */
204 public static StrMatcher stringMatcher(String str) {
205 if (StringUtils.isEmpty(str)) {
206 return NONE_MATCHER;
207 }
208 return new StringMatcher(str);
209 }
210
211 //-----------------------------------------------------------------------
212 /**
213 * Constructor.
214 */
215 protected StrMatcher() {
216 super();
217 }
218
219 /**
220 * Returns the number of matching characters, zero for no match.
221 * <p>
222 * This method is called to check for a match.
223 * The parameter <code>pos</code> represents the current position to be
224 * checked in the string <code>buffer</code> (a character array which must
225 * not be changed).
226 * The API guarantees that <code>pos</code> is a valid index for <code>buffer</code>.
227 * <p>
228 * The character array may be larger than the active area to be matched.
229 * Only values in the buffer between the specifed indices may be accessed.
230 * <p>
231 * The matching code may check one character or many.
232 * It may check characters preceeding <code>pos</code> as well as those
233 * after, so long as no checks exceed the bounds specified.
234 * <p>
235 * It must return zero for no match, or a positive number if a match was found.
236 * The number indicates the number of characters that matched.
237 *
238 * @param buffer the text content to match against, do not change
239 * @param pos the starting position for the match, valid for buffer
240 * @param bufferStart the first active index in the buffer, valid for buffer
241 * @param bufferEnd the end index (exclusive) of the active buffer, valid for buffer
242 * @return the number of matching characters, zero for no match
243 */
244 public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd);
245
246 /**
247 * Returns the number of matching characters, zero for no match.
248 * <p>
249 * This method is called to check for a match.
250 * The parameter <code>pos</code> represents the current position to be
251 * checked in the string <code>buffer</code> (a character array which must
252 * not be changed).
253 * The API guarantees that <code>pos</code> is a valid index for <code>buffer</code>.
254 * <p>
255 * The matching code may check one character or many.
256 * It may check characters preceeding <code>pos</code> as well as those after.
257 * <p>
258 * It must return zero for no match, or a positive number if a match was found.
259 * The number indicates the number of characters that matched.
260 *
261 * @param buffer the text content to match against, do not change
262 * @param pos the starting position for the match, valid for buffer
263 * @return the number of matching characters, zero for no match
264 * @since 2.4
265 */
266 public int isMatch(char[] buffer, int pos) {
267 return isMatch(buffer, pos, 0, buffer.length);
268 }
269
270 //-----------------------------------------------------------------------
271 /**
272 * Class used to define a set of characters for matching purposes.
273 */
274 static final class CharSetMatcher extends StrMatcher {
275 /** The set of characters to match. */
276 private final char[] chars;
277
278 /**
279 * Constructor that creates a matcher from a character array.
280 *
281 * @param chars the characters to match, must not be null
282 */
283 CharSetMatcher(char chars[]) {
284 super();
285 this.chars = chars.clone();
286 Arrays.sort(this.chars);
287 }
288
289 /**
290 * Returns whether or not the given character matches.
291 *
292 * @param buffer the text content to match against, do not change
293 * @param pos the starting position for the match, valid for buffer
294 * @param bufferStart the first active index in the buffer, valid for buffer
295 * @param bufferEnd the end index of the active buffer, valid for buffer
296 * @return the number of matching characters, zero for no match
297 */
298 @Override
299 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
300 return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0;
301 }
302 }
303
304 //-----------------------------------------------------------------------
305 /**
306 * Class used to define a character for matching purposes.
307 */
308 static final class CharMatcher extends StrMatcher {
309 /** The character to match. */
310 private final char ch;
311
312 /**
313 * Constructor that creates a matcher that matches a single character.
314 *
315 * @param ch the character to match
316 */
317 CharMatcher(char ch) {
318 super();
319 this.ch = ch;
320 }
321
322 /**
323 * Returns whether or not the given character matches.
324 *
325 * @param buffer the text content to match against, do not change
326 * @param pos the starting position for the match, valid for buffer
327 * @param bufferStart the first active index in the buffer, valid for buffer
328 * @param bufferEnd the end index of the active buffer, valid for buffer
329 * @return the number of matching characters, zero for no match
330 */
331 @Override
332 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
333 return ch == buffer[pos] ? 1 : 0;
334 }
335 }
336
337 //-----------------------------------------------------------------------
338 /**
339 * Class used to define a set of characters for matching purposes.
340 */
341 static final class StringMatcher extends StrMatcher {
342 /** The string to match, as a character array. */
343 private final char[] chars;
344
345 /**
346 * Constructor that creates a matcher from a String.
347 *
348 * @param str the string to match, must not be null
349 */
350 StringMatcher(String str) {
351 super();
352 chars = str.toCharArray();
353 }
354
355 /**
356 * Returns whether or not the given text matches the stored string.
357 *
358 * @param buffer the text content to match against, do not change
359 * @param pos the starting position for the match, valid for buffer
360 * @param bufferStart the first active index in the buffer, valid for buffer
361 * @param bufferEnd the end index of the active buffer, valid for buffer
362 * @return the number of matching characters, zero for no match
363 */
364 @Override
365 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
366 int len = chars.length;
367 if (pos + len > bufferEnd) {
368 return 0;
369 }
370 for (int i = 0; i < chars.length; i++, pos++) {
371 if (chars[i] != buffer[pos]) {
372 return 0;
373 }
374 }
375 return len;
376 }
377 }
378
379 //-----------------------------------------------------------------------
380 /**
381 * Class used to match no characters.
382 */
383 static final class NoMatcher extends StrMatcher {
384
385 /**
386 * Constructs a new instance of <code>NoMatcher</code>.
387 */
388 NoMatcher() {
389 super();
390 }
391
392 /**
393 * Always returns <code>false</code>.
394 *
395 * @param buffer the text content to match against, do not change
396 * @param pos the starting position for the match, valid for buffer
397 * @param bufferStart the first active index in the buffer, valid for buffer
398 * @param bufferEnd the end index of the active buffer, valid for buffer
399 * @return the number of matching characters, zero for no match
400 */
401 @Override
402 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
403 return 0;
404 }
405 }
406
407 //-----------------------------------------------------------------------
408 /**
409 * Class used to match whitespace as per trim().
410 */
411 static final class TrimMatcher extends StrMatcher {
412
413 /**
414 * Constructs a new instance of <code>TrimMatcher</code>.
415 */
416 TrimMatcher() {
417 super();
418 }
419
420 /**
421 * Returns whether or not the given character matches.
422 *
423 * @param buffer the text content to match against, do not change
424 * @param pos the starting position for the match, valid for buffer
425 * @param bufferStart the first active index in the buffer, valid for buffer
426 * @param bufferEnd the end index of the active buffer, valid for buffer
427 * @return the number of matching characters, zero for no match
428 */
429 @Override
430 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
431 return buffer[pos] <= 32 ? 1 : 0;
432 }
433 }
434
435 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import java.util.ArrayList;
19 import java.util.Enumeration;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Properties;
24
25 /**
26 * Substitutes variables within a string by values.
27 * <p>
28 * This class takes a piece of text and substitutes all the variables within it.
29 * The default definition of a variable is <code>${variableName}</code>.
30 * The prefix and suffix can be changed via constructors and set methods.
31 * <p>
32 * Variable values are typically resolved from a map, but could also be resolved
33 * from system properties, or by supplying a custom variable resolver.
34 * <p>
35 * The simplest example is to use this class to replace Java System properties. For example:
36 * <pre>
37 * StrSubstitutor.replaceSystemProperties(
38 * "You are running with java.version = ${java.version} and os.name = ${os.name}.");
39 * </pre>
40 * <p>
41 * Typical usage of this class follows the following pattern: First an instance is created
42 * and initialized with the map that contains the values for the available variables.
43 * If a prefix and/or suffix for variables should be used other than the default ones,
44 * the appropriate settings can be performed. After that the <code>replace()</code>
45 * method can be called passing in the source text for interpolation. In the returned
46 * text all variable references (as long as their values are known) will be resolved.
47 * The following example demonstrates this:
48 * <pre>
49 * Map valuesMap = HashMap();
50 * valuesMap.put(&quot;animal&quot;, &quot;quick brown fox&quot;);
51 * valuesMap.put(&quot;target&quot;, &quot;lazy dog&quot;);
52 * String templateString = &quot;The ${animal} jumped over the ${target}.&quot;;
53 * StrSubstitutor sub = new StrSubstitutor(valuesMap);
54 * String resolvedString = sub.replace(templateString);
55 * </pre>
56 * yielding:
57 * <pre>
58 * The quick brown fox jumped over the lazy dog.
59 * </pre>
60 * <p>
61 * In addition to this usage pattern there are some static convenience methods that
62 * cover the most common use cases. These methods can be used without the need of
63 * manually creating an instance. However if multiple replace operations are to be
64 * performed, creating and reusing an instance of this class will be more efficient.
65 * <p>
66 * Variable replacement works in a recursive way. Thus, if a variable value contains
67 * a variable then that variable will also be replaced. Cyclic replacements are
68 * detected and will cause an exception to be thrown.
69 * <p>
70 * Sometimes the interpolation's result must contain a variable prefix. As an example
71 * take the following source text:
72 * <pre>
73 * The variable ${${name}} must be used.
74 * </pre>
75 * Here only the variable's name referred to in the text should be replaced resulting
76 * in the text (assuming that the value of the <code>name</code> variable is <code>x</code>):
77 * <pre>
78 * The variable ${x} must be used.
79 * </pre>
80 * To achieve this effect there are two possibilities: Either set a different prefix
81 * and suffix for variables which do not conflict with the result text you want to
82 * produce. The other possibility is to use the escape character, by default '$'.
83 * If this character is placed before a variable reference, this reference is ignored
84 * and won't be replaced. For example:
85 * <pre>
86 * The variable $${${name}} must be used.
87 * </pre>
88 * <p>
89 * In some complex scenarios you might even want to perform substitution in the
90 * names of variables, for instance
91 * <pre>
92 * ${jre-${java.specification.version}}
93 * </pre>
94 * <code>StrSubstitutor</code> supports this recursive substitution in variable
95 * names, but it has to be enabled explicitly by setting the
96 * {@link #setEnableSubstitutionInVariables(boolean) enableSubstitutionInVariables}
97 * property to <b>true</b>.
98 *
99 * @version $Id: StrSubstitutor.java 1088899 2011-04-05 05:31:27Z bayard $
100 * @since 2.2
101 */
102 public class StrSubstitutor {
103
104 /**
105 * Constant for the default escape character.
106 */
107 public static final char DEFAULT_ESCAPE = '$';
108 /**
109 * Constant for the default variable prefix.
110 */
111 public static final StrMatcher DEFAULT_PREFIX = StrMatcher.stringMatcher("${");
112 /**
113 * Constant for the default variable suffix.
114 */
115 public static final StrMatcher DEFAULT_SUFFIX = StrMatcher.stringMatcher("}");
116
117 /**
118 * Stores the escape character.
119 */
120 private char escapeChar;
121 /**
122 * Stores the variable prefix.
123 */
124 private StrMatcher prefixMatcher;
125 /**
126 * Stores the variable suffix.
127 */
128 private StrMatcher suffixMatcher;
129 /**
130 * Variable resolution is delegated to an implementor of VariableResolver.
131 */
132 private StrLookup<?> variableResolver;
133 /**
134 * The flag whether substitution in variable names is enabled.
135 */
136 private boolean enableSubstitutionInVariables;
137
138 //-----------------------------------------------------------------------
139 /**
140 * Replaces all the occurrences of variables in the given source object with
141 * their matching values from the map.
142 *
143 * @param <V> the type of the values in the map
144 * @param source the source text containing the variables to substitute, null returns null
145 * @param valueMap the map with the values, may be null
146 * @return the result of the replace operation
147 */
148 public static <V> String replace(Object source, Map<String, V> valueMap) {
149 return new StrSubstitutor(valueMap).replace(source);
150 }
151
152 /**
153 * Replaces all the occurrences of variables in the given source object with
154 * their matching values from the map. This method allows to specifiy a
155 * custom variable prefix and suffix
156 *
157 * @param <V> the type of the values in the map
158 * @param source the source text containing the variables to substitute, null returns null
159 * @param valueMap the map with the values, may be null
160 * @param prefix the prefix of variables, not null
161 * @param suffix the suffix of variables, not null
162 * @return the result of the replace operation
163 * @throws IllegalArgumentException if the prefix or suffix is null
164 */
165 public static <V> String replace(Object source, Map<String, V> valueMap, String prefix, String suffix) {
166 return new StrSubstitutor(valueMap, prefix, suffix).replace(source);
167 }
168
169 /**
170 * Replaces all the occurrences of variables in the given source object with their matching
171 * values from the properties.
172 *
173 * @param source the source text containing the variables to substitute, null returns null
174 * @param valueProperties the properties with values, may be null
175 * @return the result of the replace operation
176 */
177 public static String replace(Object source, Properties valueProperties) {
178 if (valueProperties == null) {
179 return source.toString();
180 }
181 Map<String,String> valueMap = new HashMap<String,String>();
182 Enumeration<?> propNames = valueProperties.propertyNames();
183 while (propNames.hasMoreElements()) {
184 String propName = (String)propNames.nextElement();
185 String propValue = valueProperties.getProperty(propName);
186 valueMap.put(propName, propValue);
187 }
188 return StrSubstitutor.replace(source, valueMap);
189 }
190
191 /**
192 * Replaces all the occurrences of variables in the given source object with
193 * their matching values from the system properties.
194 *
195 * @param source the source text containing the variables to substitute, null returns null
196 * @return the result of the replace operation
197 */
198 public static String replaceSystemProperties(Object source) {
199 return new StrSubstitutor(StrLookup.systemPropertiesLookup()).replace(source);
200 }
201
202 //-----------------------------------------------------------------------
203 /**
204 * Creates a new instance with defaults for variable prefix and suffix
205 * and the escaping character.
206 */
207 public StrSubstitutor() {
208 this((StrLookup<?>) null, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
209 }
210
211 /**
212 * Creates a new instance and initializes it. Uses defaults for variable
213 * prefix and suffix and the escaping character.
214 *
215 * @param <V> the type of the values in the map
216 * @param valueMap the map with the variables' values, may be null
217 */
218 public <V> StrSubstitutor(Map<String, V> valueMap) {
219 this(StrLookup.mapLookup(valueMap), DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
220 }
221
222 /**
223 * Creates a new instance and initializes it. Uses a default escaping character.
224 *
225 * @param <V> the type of the values in the map
226 * @param valueMap the map with the variables' values, may be null
227 * @param prefix the prefix for variables, not null
228 * @param suffix the suffix for variables, not null
229 * @throws IllegalArgumentException if the prefix or suffix is null
230 */
231 public <V> StrSubstitutor(Map<String, V> valueMap, String prefix, String suffix) {
232 this(StrLookup.mapLookup(valueMap), prefix, suffix, DEFAULT_ESCAPE);
233 }
234
235 /**
236 * Creates a new instance and initializes it.
237 *
238 * @param <V> the type of the values in the map
239 * @param valueMap the map with the variables' values, may be null
240 * @param prefix the prefix for variables, not null
241 * @param suffix the suffix for variables, not null
242 * @param escape the escape character
243 * @throws IllegalArgumentException if the prefix or suffix is null
244 */
245 public <V> StrSubstitutor(Map<String, V> valueMap, String prefix, String suffix, char escape) {
246 this(StrLookup.mapLookup(valueMap), prefix, suffix, escape);
247 }
248
249 /**
250 * Creates a new instance and initializes it.
251 *
252 * @param variableResolver the variable resolver, may be null
253 */
254 public StrSubstitutor(StrLookup<?> variableResolver) {
255 this(variableResolver, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
256 }
257
258 /**
259 * Creates a new instance and initializes it.
260 *
261 * @param variableResolver the variable resolver, may be null
262 * @param prefix the prefix for variables, not null
263 * @param suffix the suffix for variables, not null
264 * @param escape the escape character
265 * @throws IllegalArgumentException if the prefix or suffix is null
266 */
267 public StrSubstitutor(StrLookup<?> variableResolver, String prefix, String suffix, char escape) {
268 this.setVariableResolver(variableResolver);
269 this.setVariablePrefix(prefix);
270 this.setVariableSuffix(suffix);
271 this.setEscapeChar(escape);
272 }
273
274 /**
275 * Creates a new instance and initializes it.
276 *
277 * @param variableResolver the variable resolver, may be null
278 * @param prefixMatcher the prefix for variables, not null
279 * @param suffixMatcher the suffix for variables, not null
280 * @param escape the escape character
281 * @throws IllegalArgumentException if the prefix or suffix is null
282 */
283 public StrSubstitutor(
284 StrLookup<?> variableResolver, StrMatcher prefixMatcher, StrMatcher suffixMatcher, char escape) {
285 this.setVariableResolver(variableResolver);
286 this.setVariablePrefixMatcher(prefixMatcher);
287 this.setVariableSuffixMatcher(suffixMatcher);
288 this.setEscapeChar(escape);
289 }
290
291 //-----------------------------------------------------------------------
292 /**
293 * Replaces all the occurrences of variables with their matching values
294 * from the resolver using the given source string as a template.
295 *
296 * @param source the string to replace in, null returns null
297 * @return the result of the replace operation
298 */
299 public String replace(String source) {
300 if (source == null) {
301 return null;
302 }
303 StrBuilder buf = new StrBuilder(source);
304 if (substitute(buf, 0, source.length()) == false) {
305 return source;
306 }
307 return buf.toString();
308 }
309
310 /**
311 * Replaces all the occurrences of variables with their matching values
312 * from the resolver using the given source string as a template.
313 * <p>
314 * Only the specified portion of the string will be processed.
315 * The rest of the string is not processed, and is not returned.
316 *
317 * @param source the string to replace in, null returns null
318 * @param offset the start offset within the array, must be valid
319 * @param length the length within the array to be processed, must be valid
320 * @return the result of the replace operation
321 */
322 public String replace(String source, int offset, int length) {
323 if (source == null) {
324 return null;
325 }
326 StrBuilder buf = new StrBuilder(length).append(source, offset, length);
327 if (substitute(buf, 0, length) == false) {
328 return source.substring(offset, offset + length);
329 }
330 return buf.toString();
331 }
332
333 //-----------------------------------------------------------------------
334 /**
335 * Replaces all the occurrences of variables with their matching values
336 * from the resolver using the given source array as a template.
337 * The array is not altered by this method.
338 *
339 * @param source the character array to replace in, not altered, null returns null
340 * @return the result of the replace operation
341 */
342 public String replace(char[] source) {
343 if (source == null) {
344 return null;
345 }
346 StrBuilder buf = new StrBuilder(source.length).append(source);
347 substitute(buf, 0, source.length);
348 return buf.toString();
349 }
350
351 /**
352 * Replaces all the occurrences of variables with their matching values
353 * from the resolver using the given source array as a template.
354 * The array is not altered by this method.
355 * <p>
356 * Only the specified portion of the array will be processed.
357 * The rest of the array is not processed, and is not returned.
358 *
359 * @param source the character array to replace in, not altered, null returns null
360 * @param offset the start offset within the array, must be valid
361 * @param length the length within the array to be processed, must be valid
362 * @return the result of the replace operation
363 */
364 public String replace(char[] source, int offset, int length) {
365 if (source == null) {
366 return null;
367 }
368 StrBuilder buf = new StrBuilder(length).append(source, offset, length);
369 substitute(buf, 0, length);
370 return buf.toString();
371 }
372
373 //-----------------------------------------------------------------------
374 /**
375 * Replaces all the occurrences of variables with their matching values
376 * from the resolver using the given source buffer as a template.
377 * The buffer is not altered by this method.
378 *
379 * @param source the buffer to use as a template, not changed, null returns null
380 * @return the result of the replace operation
381 */
382 public String replace(StringBuffer source) {
383 if (source == null) {
384 return null;
385 }
386 StrBuilder buf = new StrBuilder(source.length()).append(source);
387 substitute(buf, 0, buf.length());
388 return buf.toString();
389 }
390
391 /**
392 * Replaces all the occurrences of variables with their matching values
393 * from the resolver using the given source buffer as a template.
394 * The buffer is not altered by this method.
395 * <p>
396 * Only the specified portion of the buffer will be processed.
397 * The rest of the buffer is not processed, and is not returned.
398 *
399 * @param source the buffer to use as a template, not changed, null returns null
400 * @param offset the start offset within the array, must be valid
401 * @param length the length within the array to be processed, must be valid
402 * @return the result of the replace operation
403 */
404 public String replace(StringBuffer source, int offset, int length) {
405 if (source == null) {
406 return null;
407 }
408 StrBuilder buf = new StrBuilder(length).append(source, offset, length);
409 substitute(buf, 0, length);
410 return buf.toString();
411 }
412
413 //-----------------------------------------------------------------------
414 /**
415 * Replaces all the occurrences of variables with their matching values
416 * from the resolver using the given source builder as a template.
417 * The builder is not altered by this method.
418 *
419 * @param source the builder to use as a template, not changed, null returns null
420 * @return the result of the replace operation
421 */
422 public String replace(StrBuilder source) {
423 if (source == null) {
424 return null;
425 }
426 StrBuilder buf = new StrBuilder(source.length()).append(source);
427 substitute(buf, 0, buf.length());
428 return buf.toString();
429 }
430
431 /**
432 * Replaces all the occurrences of variables with their matching values
433 * from the resolver using the given source builder as a template.
434 * The builder is not altered by this method.
435 * <p>
436 * Only the specified portion of the builder will be processed.
437 * The rest of the builder is not processed, and is not returned.
438 *
439 * @param source the builder to use as a template, not changed, null returns null
440 * @param offset the start offset within the array, must be valid
441 * @param length the length within the array to be processed, must be valid
442 * @return the result of the replace operation
443 */
444 public String replace(StrBuilder source, int offset, int length) {
445 if (source == null) {
446 return null;
447 }
448 StrBuilder buf = new StrBuilder(length).append(source, offset, length);
449 substitute(buf, 0, length);
450 return buf.toString();
451 }
452
453 //-----------------------------------------------------------------------
454 /**
455 * Replaces all the occurrences of variables in the given source object with
456 * their matching values from the resolver. The input source object is
457 * converted to a string using <code>toString</code> and is not altered.
458 *
459 * @param source the source to replace in, null returns null
460 * @return the result of the replace operation
461 */
462 public String replace(Object source) {
463 if (source == null) {
464 return null;
465 }
466 StrBuilder buf = new StrBuilder().append(source);
467 substitute(buf, 0, buf.length());
468 return buf.toString();
469 }
470
471 //-----------------------------------------------------------------------
472 /**
473 * Replaces all the occurrences of variables within the given source buffer
474 * with their matching values from the resolver.
475 * The buffer is updated with the result.
476 *
477 * @param source the buffer to replace in, updated, null returns zero
478 * @return true if altered
479 */
480 public boolean replaceIn(StringBuffer source) {
481 if (source == null) {
482 return false;
483 }
484 return replaceIn(source, 0, source.length());
485 }
486
487 /**
488 * Replaces all the occurrences of variables within the given source buffer
489 * with their matching values from the resolver.
490 * The buffer is updated with the result.
491 * <p>
492 * Only the specified portion of the buffer will be processed.
493 * The rest of the buffer is not processed, but it is not deleted.
494 *
495 * @param source the buffer to replace in, updated, null returns zero
496 * @param offset the start offset within the array, must be valid
497 * @param length the length within the buffer to be processed, must be valid
498 * @return true if altered
499 */
500 public boolean replaceIn(StringBuffer source, int offset, int length) {
501 if (source == null) {
502 return false;
503 }
504 StrBuilder buf = new StrBuilder(length).append(source, offset, length);
505 if (substitute(buf, 0, length) == false) {
506 return false;
507 }
508 source.replace(offset, offset + length, buf.toString());
509 return true;
510 }
511
512 //-----------------------------------------------------------------------
513 /**
514 * Replaces all the occurrences of variables within the given source
515 * builder with their matching values from the resolver.
516 *
517 * @param source the builder to replace in, updated, null returns zero
518 * @return true if altered
519 */
520 public boolean replaceIn(StrBuilder source) {
521 if (source == null) {
522 return false;
523 }
524 return substitute(source, 0, source.length());
525 }
526
527 /**
528 * Replaces all the occurrences of variables within the given source
529 * builder with their matching values from the resolver.
530 * <p>
531 * Only the specified portion of the builder will be processed.
532 * The rest of the builder is not processed, but it is not deleted.
533 *
534 * @param source the builder to replace in, null returns zero
535 * @param offset the start offset within the array, must be valid
536 * @param length the length within the builder to be processed, must be valid
537 * @return true if altered
538 */
539 public boolean replaceIn(StrBuilder source, int offset, int length) {
540 if (source == null) {
541 return false;
542 }
543 return substitute(source, offset, length);
544 }
545
546 //-----------------------------------------------------------------------
547 /**
548 * Internal method that substitutes the variables.
549 * <p>
550 * Most users of this class do not need to call this method. This method will
551 * be called automatically by another (public) method.
552 * <p>
553 * Writers of subclasses can override this method if they need access to
554 * the substitution process at the start or end.
555 *
556 * @param buf the string builder to substitute into, not null
557 * @param offset the start offset within the builder, must be valid
558 * @param length the length within the builder to be processed, must be valid
559 * @return true if altered
560 */
561 protected boolean substitute(StrBuilder buf, int offset, int length) {
562 return substitute(buf, offset, length, null) > 0;
563 }
564
565 /**
566 * Recursive handler for multiple levels of interpolation. This is the main
567 * interpolation method, which resolves the values of all variable references
568 * contained in the passed in text.
569 *
570 * @param buf the string builder to substitute into, not null
571 * @param offset the start offset within the builder, must be valid
572 * @param length the length within the builder to be processed, must be valid
573 * @param priorVariables the stack keeping track of the replaced variables, may be null
574 * @return the length change that occurs, unless priorVariables is null when the int
575 * represents a boolean flag as to whether any change occurred.
576 */
577 private int substitute(StrBuilder buf, int offset, int length, List<String> priorVariables) {
578 StrMatcher prefixMatcher = getVariablePrefixMatcher();
579 StrMatcher suffixMatcher = getVariableSuffixMatcher();
580 char escape = getEscapeChar();
581
582 boolean top = (priorVariables == null);
583 boolean altered = false;
584 int lengthChange = 0;
585 char[] chars = buf.buffer;
586 int bufEnd = offset + length;
587 int pos = offset;
588 while (pos < bufEnd) {
589 int startMatchLen = prefixMatcher.isMatch(chars, pos, offset,
590 bufEnd);
591 if (startMatchLen == 0) {
592 pos++;
593 } else {
594 // found variable start marker
595 if (pos > offset && chars[pos - 1] == escape) {
596 // escaped
597 buf.deleteCharAt(pos - 1);
598 chars = buf.buffer; // in case buffer was altered
599 lengthChange--;
600 altered = true;
601 bufEnd--;
602 } else {
603 // find suffix
604 int startPos = pos;
605 pos += startMatchLen;
606 int endMatchLen = 0;
607 int nestedVarCount = 0;
608 while (pos < bufEnd) {
609 if (isEnableSubstitutionInVariables()
610 && (endMatchLen = prefixMatcher.isMatch(chars,
611 pos, offset, bufEnd)) != 0) {
612 // found a nested variable start
613 nestedVarCount++;
614 pos += endMatchLen;
615 continue;
616 }
617
618 endMatchLen = suffixMatcher.isMatch(chars, pos, offset,
619 bufEnd);
620 if (endMatchLen == 0) {
621 pos++;
622 } else {
623 // found variable end marker
624 if (nestedVarCount == 0) {
625 String varName = new String(chars, startPos
626 + startMatchLen, pos - startPos
627 - startMatchLen);
628 if (isEnableSubstitutionInVariables()) {
629 StrBuilder bufName = new StrBuilder(varName);
630 substitute(bufName, 0, bufName.length());
631 varName = bufName.toString();
632 }
633 pos += endMatchLen;
634 int endPos = pos;
635
636 // on the first call initialize priorVariables
637 if (priorVariables == null) {
638 priorVariables = new ArrayList<String>();
639 priorVariables.add(new String(chars,
640 offset, length));
641 }
642
643 // handle cyclic substitution
644 checkCyclicSubstitution(varName, priorVariables);
645 priorVariables.add(varName);
646
647 // resolve the variable
648 String varValue = resolveVariable(varName, buf,
649 startPos, endPos);
650 if (varValue != null) {
651 // recursive replace
652 int varLen = varValue.length();
653 buf.replace(startPos, endPos, varValue);
654 altered = true;
655 int change = substitute(buf, startPos,
656 varLen, priorVariables);
657 change = change
658 + (varLen - (endPos - startPos));
659 pos += change;
660 bufEnd += change;
661 lengthChange += change;
662 chars = buf.buffer; // in case buffer was
663 // altered
664 }
665
666 // remove variable from the cyclic stack
667 priorVariables
668 .remove(priorVariables.size() - 1);
669 break;
670 } else {
671 nestedVarCount--;
672 pos += endMatchLen;
673 }
674 }
675 }
676 }
677 }
678 }
679 if (top) {
680 return (altered ? 1 : 0);
681 }
682 return lengthChange;
683 }
684
685 /**
686 * Checks if the specified variable is already in the stack (list) of variables.
687 *
688 * @param varName the variable name to check
689 * @param priorVariables the list of prior variables
690 */
691 private void checkCyclicSubstitution(String varName, List<String> priorVariables) {
692 if (priorVariables.contains(varName) == false) {
693 return;
694 }
695 StrBuilder buf = new StrBuilder(256);
696 buf.append("Infinite loop in property interpolation of ");
697 buf.append(priorVariables.remove(0));
698 buf.append(": ");
699 buf.appendWithSeparators(priorVariables, "->");
700 throw new IllegalStateException(buf.toString());
701 }
702
703 /**
704 * Internal method that resolves the value of a variable.
705 * <p>
706 * Most users of this class do not need to call this method. This method is
707 * called automatically by the substitution process.
708 * <p>
709 * Writers of subclasses can override this method if they need to alter
710 * how each substitution occurs. The method is passed the variable's name
711 * and must return the corresponding value. This implementation uses the
712 * {@link #getVariableResolver()} with the variable's name as the key.
713 *
714 * @param variableName the name of the variable, not null
715 * @param buf the buffer where the substitution is occurring, not null
716 * @param startPos the start position of the variable including the prefix, valid
717 * @param endPos the end position of the variable including the suffix, valid
718 * @return the variable's value or <b>null</b> if the variable is unknown
719 */
720 protected String resolveVariable(String variableName, StrBuilder buf, int startPos, int endPos) {
721 StrLookup<?> resolver = getVariableResolver();
722 if (resolver == null) {
723 return null;
724 }
725 return resolver.lookup(variableName);
726 }
727
728 // Escape
729 //-----------------------------------------------------------------------
730 /**
731 * Returns the escape character.
732 *
733 * @return the character used for escaping variable references
734 */
735 public char getEscapeChar() {
736 return this.escapeChar;
737 }
738
739 /**
740 * Sets the escape character.
741 * If this character is placed before a variable reference in the source
742 * text, this variable will be ignored.
743 *
744 * @param escapeCharacter the escape character (0 for disabling escaping)
745 */
746 public void setEscapeChar(char escapeCharacter) {
747 this.escapeChar = escapeCharacter;
748 }
749
750 // Prefix
751 //-----------------------------------------------------------------------
752 /**
753 * Gets the variable prefix matcher currently in use.
754 * <p>
755 * The variable prefix is the characer or characters that identify the
756 * start of a variable. This prefix is expressed in terms of a matcher
757 * allowing advanced prefix matches.
758 *
759 * @return the prefix matcher in use
760 */
761 public StrMatcher getVariablePrefixMatcher() {
762 return prefixMatcher;
763 }
764
765 /**
766 * Sets the variable prefix matcher currently in use.
767 * <p>
768 * The variable prefix is the characer or characters that identify the
769 * start of a variable. This prefix is expressed in terms of a matcher
770 * allowing advanced prefix matches.
771 *
772 * @param prefixMatcher the prefix matcher to use, null ignored
773 * @return this, to enable chaining
774 * @throws IllegalArgumentException if the prefix matcher is null
775 */
776 public StrSubstitutor setVariablePrefixMatcher(StrMatcher prefixMatcher) {
777 if (prefixMatcher == null) {
778 throw new IllegalArgumentException("Variable prefix matcher must not be null!");
779 }
780 this.prefixMatcher = prefixMatcher;
781 return this;
782 }
783
784 /**
785 * Sets the variable prefix to use.
786 * <p>
787 * The variable prefix is the character or characters that identify the
788 * start of a variable. This method allows a single character prefix to
789 * be easily set.
790 *
791 * @param prefix the prefix character to use
792 * @return this, to enable chaining
793 */
794 public StrSubstitutor setVariablePrefix(char prefix) {
795 return setVariablePrefixMatcher(StrMatcher.charMatcher(prefix));
796 }
797
798 /**
799 * Sets the variable prefix to use.
800 * <p>
801 * The variable prefix is the characer or characters that identify the
802 * start of a variable. This method allows a string prefix to be easily set.
803 *
804 * @param prefix the prefix for variables, not null
805 * @return this, to enable chaining
806 * @throws IllegalArgumentException if the prefix is null
807 */
808 public StrSubstitutor setVariablePrefix(String prefix) {
809 if (prefix == null) {
810 throw new IllegalArgumentException("Variable prefix must not be null!");
811 }
812 return setVariablePrefixMatcher(StrMatcher.stringMatcher(prefix));
813 }
814
815 // Suffix
816 //-----------------------------------------------------------------------
817 /**
818 * Gets the variable suffix matcher currently in use.
819 * <p>
820 * The variable suffix is the characer or characters that identify the
821 * end of a variable. This suffix is expressed in terms of a matcher
822 * allowing advanced suffix matches.
823 *
824 * @return the suffix matcher in use
825 */
826 public StrMatcher getVariableSuffixMatcher() {
827 return suffixMatcher;
828 }
829
830 /**
831 * Sets the variable suffix matcher currently in use.
832 * <p>
833 * The variable suffix is the characer or characters that identify the
834 * end of a variable. This suffix is expressed in terms of a matcher
835 * allowing advanced suffix matches.
836 *
837 * @param suffixMatcher the suffix matcher to use, null ignored
838 * @return this, to enable chaining
839 * @throws IllegalArgumentException if the suffix matcher is null
840 */
841 public StrSubstitutor setVariableSuffixMatcher(StrMatcher suffixMatcher) {
842 if (suffixMatcher == null) {
843 throw new IllegalArgumentException("Variable suffix matcher must not be null!");
844 }
845 this.suffixMatcher = suffixMatcher;
846 return this;
847 }
848
849 /**
850 * Sets the variable suffix to use.
851 * <p>
852 * The variable suffix is the characer or characters that identify the
853 * end of a variable. This method allows a single character suffix to
854 * be easily set.
855 *
856 * @param suffix the suffix character to use
857 * @return this, to enable chaining
858 */
859 public StrSubstitutor setVariableSuffix(char suffix) {
860 return setVariableSuffixMatcher(StrMatcher.charMatcher(suffix));
861 }
862
863 /**
864 * Sets the variable suffix to use.
865 * <p>
866 * The variable suffix is the character or characters that identify the
867 * end of a variable. This method allows a string suffix to be easily set.
868 *
869 * @param suffix the suffix for variables, not null
870 * @return this, to enable chaining
871 * @throws IllegalArgumentException if the suffix is null
872 */
873 public StrSubstitutor setVariableSuffix(String suffix) {
874 if (suffix == null) {
875 throw new IllegalArgumentException("Variable suffix must not be null!");
876 }
877 return setVariableSuffixMatcher(StrMatcher.stringMatcher(suffix));
878 }
879
880 // Resolver
881 //-----------------------------------------------------------------------
882 /**
883 * Gets the VariableResolver that is used to lookup variables.
884 *
885 * @return the VariableResolver
886 */
887 public StrLookup<?> getVariableResolver() {
888 return this.variableResolver;
889 }
890
891 /**
892 * Sets the VariableResolver that is used to lookup variables.
893 *
894 * @param variableResolver the VariableResolver
895 */
896 public void setVariableResolver(StrLookup<?> variableResolver) {
897 this.variableResolver = variableResolver;
898 }
899
900 // Substitution support in variable names
901 //-----------------------------------------------------------------------
902 /**
903 * Returns a flag whether substitution is done in variable names.
904 *
905 * @return the substitution in variable names flag
906 * @since 3.0
907 */
908 public boolean isEnableSubstitutionInVariables() {
909 return enableSubstitutionInVariables;
910 }
911
912 /**
913 * Sets a flag whether substitution is done in variable names. If set to
914 * <b>true</b>, the names of variables can contain other variables which are
915 * processed first before the original variable is evaluated, e.g.
916 * <code>${jre-${java.version}}</code>. The default value is <b>false</b>.
917 *
918 * @param enableSubstitutionInVariables the new value of the flag
919 * @since 3.0
920 */
921 public void setEnableSubstitutionInVariables(
922 boolean enableSubstitutionInVariables) {
923 this.enableSubstitutionInVariables = enableSubstitutionInVariables;
924 }
925 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.ListIterator;
22 import java.util.NoSuchElementException;
23
24 import org.apache.commons.lang3.ArrayUtils;
25
26 /**
27 * Tokenizes a string based based on delimiters (separators)
28 * and supporting quoting and ignored character concepts.
29 * <p>
30 * This class can split a String into many smaller strings. It aims
31 * to do a similar job to {@link java.util.StringTokenizer StringTokenizer},
32 * however it offers much more control and flexibility including implementing
33 * the <code>ListIterator</code> interface. By default, it is set up
34 * like <code>StringTokenizer</code>.
35 * <p>
36 * The input String is split into a number of <i>tokens</i>.
37 * Each token is separated from the next String by a <i>delimiter</i>.
38 * One or more delimiter characters must be specified.
39 * <p>
40 * Each token may be surrounded by quotes.
41 * The <i>quote</i> matcher specifies the quote character(s).
42 * A quote may be escaped within a quoted section by duplicating itself.
43 * <p>
44 * Between each token and the delimiter are potentially characters that need trimming.
45 * The <i>trimmer</i> matcher specifies these characters.
46 * One usage might be to trim whitespace characters.
47 * <p>
48 * At any point outside the quotes there might potentially be invalid characters.
49 * The <i>ignored</i> matcher specifies these characters to be removed.
50 * One usage might be to remove new line characters.
51 * <p>
52 * Empty tokens may be removed or returned as null.
53 * <pre>
54 * "a,b,c" - Three tokens "a","b","c" (comma delimiter)
55 * " a, b , c " - Three tokens "a","b","c" (default CSV processing trims whitespace)
56 * "a, ", b ,", c" - Three tokens "a, " , " b ", ", c" (quoted text untouched)
57 * </pre>
58 * <p>
59 *
60 * This tokenizer has the following properties and options:
61 *
62 * <table>
63 * <tr>
64 * <th>Property</th><th>Type</th><th>Default</th>
65 * </tr>
66 * <tr>
67 * <td>delim</td><td>CharSetMatcher</td><td>{ \t\n\r\f}</td>
68 * </tr>
69 * <tr>
70 * <td>quote</td><td>NoneMatcher</td><td>{}</td>
71 * </tr>
72 * <tr>
73 * <td>ignore</td><td>NoneMatcher</td><td>{}</td>
74 * </tr>
75 * <tr>
76 * <td>emptyTokenAsNull</td><td>boolean</td><td>false</td>
77 * </tr>
78 * <tr>
79 * <td>ignoreEmptyTokens</td><td>boolean</td><td>true</td>
80 * </tr>
81 * </table>
82 *
83 * @since 2.2
84 * @version $Id: StrTokenizer.java 1153241 2011-08-02 18:49:52Z ggregory $
85 */
86 public class StrTokenizer implements ListIterator<String>, Cloneable {
87
88 private static final StrTokenizer CSV_TOKENIZER_PROTOTYPE;
89 private static final StrTokenizer TSV_TOKENIZER_PROTOTYPE;
90 static {
91 CSV_TOKENIZER_PROTOTYPE = new StrTokenizer();
92 CSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.commaMatcher());
93 CSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
94 CSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher());
95 CSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher());
96 CSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false);
97 CSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false);
98
99 TSV_TOKENIZER_PROTOTYPE = new StrTokenizer();
100 TSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.tabMatcher());
101 TSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
102 TSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher());
103 TSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher());
104 TSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false);
105 TSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false);
106 }
107
108 /** The text to work on. */
109 private char chars[];
110 /** The parsed tokens */
111 private String tokens[];
112 /** The current iteration position */
113 private int tokenPos;
114
115 /** The delimiter matcher */
116 private StrMatcher delimMatcher = StrMatcher.splitMatcher();
117 /** The quote matcher */
118 private StrMatcher quoteMatcher = StrMatcher.noneMatcher();
119 /** The ignored matcher */
120 private StrMatcher ignoredMatcher = StrMatcher.noneMatcher();
121 /** The trimmer matcher */
122 private StrMatcher trimmerMatcher = StrMatcher.noneMatcher();
123
124 /** Whether to return empty tokens as null */
125 private boolean emptyAsNull = false;
126 /** Whether to ignore empty tokens */
127 private boolean ignoreEmptyTokens = true;
128
129 //-----------------------------------------------------------------------
130
131 /**
132 * Returns a clone of <code>CSV_TOKENIZER_PROTOTYPE</code>.
133 *
134 * @return a clone of <code>CSV_TOKENIZER_PROTOTYPE</code>.
135 */
136 private static StrTokenizer getCSVClone() {
137 return (StrTokenizer) CSV_TOKENIZER_PROTOTYPE.clone();
138 }
139
140 /**
141 * Gets a new tokenizer instance which parses Comma Separated Value strings
142 * initializing it with the given input. The default for CSV processing
143 * will be trim whitespace from both ends (which can be overridden with
144 * the setTrimmer method).
145 * <p>
146 * You must call a "reset" method to set the string which you want to parse.
147 * @return a new tokenizer instance which parses Comma Separated Value strings
148 */
149 public static StrTokenizer getCSVInstance() {
150 return getCSVClone();
151 }
152
153 /**
154 * Gets a new tokenizer instance which parses Comma Separated Value strings
155 * initializing it with the given input. The default for CSV processing
156 * will be trim whitespace from both ends (which can be overridden with
157 * the setTrimmer method).
158 *
159 * @param input the text to parse
160 * @return a new tokenizer instance which parses Comma Separated Value strings
161 */
162 public static StrTokenizer getCSVInstance(String input) {
163 StrTokenizer tok = getCSVClone();
164 tok.reset(input);
165 return tok;
166 }
167
168 /**
169 * Gets a new tokenizer instance which parses Comma Separated Value strings
170 * initializing it with the given input. The default for CSV processing
171 * will be trim whitespace from both ends (which can be overridden with
172 * the setTrimmer method).
173 *
174 * @param input the text to parse
175 * @return a new tokenizer instance which parses Comma Separated Value strings
176 */
177 public static StrTokenizer getCSVInstance(char[] input) {
178 StrTokenizer tok = getCSVClone();
179 tok.reset(input);
180 return tok;
181 }
182
183 /**
184 * Returns a clone of <code>TSV_TOKENIZER_PROTOTYPE</code>.
185 *
186 * @return a clone of <code>TSV_TOKENIZER_PROTOTYPE</code>.
187 */
188 private static StrTokenizer getTSVClone() {
189 return (StrTokenizer) TSV_TOKENIZER_PROTOTYPE.clone();
190 }
191
192
193 /**
194 * Gets a new tokenizer instance which parses Tab Separated Value strings.
195 * The default for CSV processing will be trim whitespace from both ends
196 * (which can be overridden with the setTrimmer method).
197 * <p>
198 * You must call a "reset" method to set the string which you want to parse.
199 * @return a new tokenizer instance which parses Tab Separated Value strings.
200 */
201 public static StrTokenizer getTSVInstance() {
202 return getTSVClone();
203 }
204
205 /**
206 * Gets a new tokenizer instance which parses Tab Separated Value strings.
207 * The default for CSV processing will be trim whitespace from both ends
208 * (which can be overridden with the setTrimmer method).
209 * @param input the string to parse
210 * @return a new tokenizer instance which parses Tab Separated Value strings.
211 */
212 public static StrTokenizer getTSVInstance(String input) {
213 StrTokenizer tok = getTSVClone();
214 tok.reset(input);
215 return tok;
216 }
217
218 /**
219 * Gets a new tokenizer instance which parses Tab Separated Value strings.
220 * The default for CSV processing will be trim whitespace from both ends
221 * (which can be overridden with the setTrimmer method).
222 * @param input the string to parse
223 * @return a new tokenizer instance which parses Tab Separated Value strings.
224 */
225 public static StrTokenizer getTSVInstance(char[] input) {
226 StrTokenizer tok = getTSVClone();
227 tok.reset(input);
228 return tok;
229 }
230
231 //-----------------------------------------------------------------------
232 /**
233 * Constructs a tokenizer splitting on space, tab, newline and formfeed
234 * as per StringTokenizer, but with no text to tokenize.
235 * <p>
236 * This constructor is normally used with {@link #reset(String)}.
237 */
238 public StrTokenizer() {
239 super();
240 this.chars = null;
241 }
242
243 /**
244 * Constructs a tokenizer splitting on space, tab, newline and formfeed
245 * as per StringTokenizer.
246 *
247 * @param input the string which is to be parsed
248 */
249 public StrTokenizer(String input) {
250 super();
251 if (input != null) {
252 chars = input.toCharArray();
253 } else {
254 chars = null;
255 }
256 }
257
258 /**
259 * Constructs a tokenizer splitting on the specified delimiter character.
260 *
261 * @param input the string which is to be parsed
262 * @param delim the field delimiter character
263 */
264 public StrTokenizer(String input, char delim) {
265 this(input);
266 setDelimiterChar(delim);
267 }
268
269 /**
270 * Constructs a tokenizer splitting on the specified delimiter string.
271 *
272 * @param input the string which is to be parsed
273 * @param delim the field delimiter string
274 */
275 public StrTokenizer(String input, String delim) {
276 this(input);
277 setDelimiterString(delim);
278 }
279
280 /**
281 * Constructs a tokenizer splitting using the specified delimiter matcher.
282 *
283 * @param input the string which is to be parsed
284 * @param delim the field delimiter matcher
285 */
286 public StrTokenizer(String input, StrMatcher delim) {
287 this(input);
288 setDelimiterMatcher(delim);
289 }
290
291 /**
292 * Constructs a tokenizer splitting on the specified delimiter character
293 * and handling quotes using the specified quote character.
294 *
295 * @param input the string which is to be parsed
296 * @param delim the field delimiter character
297 * @param quote the field quoted string character
298 */
299 public StrTokenizer(String input, char delim, char quote) {
300 this(input, delim);
301 setQuoteChar(quote);
302 }
303
304 /**
305 * Constructs a tokenizer splitting using the specified delimiter matcher
306 * and handling quotes using the specified quote matcher.
307 *
308 * @param input the string which is to be parsed
309 * @param delim the field delimiter matcher
310 * @param quote the field quoted string matcher
311 */
312 public StrTokenizer(String input, StrMatcher delim, StrMatcher quote) {
313 this(input, delim);
314 setQuoteMatcher(quote);
315 }
316
317 /**
318 * Constructs a tokenizer splitting on space, tab, newline and formfeed
319 * as per StringTokenizer.
320 *
321 * @param input the string which is to be parsed, not cloned
322 */
323 public StrTokenizer(char[] input) {
324 super();
325 this.chars = ArrayUtils.clone(input);
326 }
327
328 /**
329 * Constructs a tokenizer splitting on the specified character.
330 *
331 * @param input the string which is to be parsed, not cloned
332 * @param delim the field delimiter character
333 */
334 public StrTokenizer(char[] input, char delim) {
335 this(input);
336 setDelimiterChar(delim);
337 }
338
339 /**
340 * Constructs a tokenizer splitting on the specified string.
341 *
342 * @param input the string which is to be parsed, not cloned
343 * @param delim the field delimiter string
344 */
345 public StrTokenizer(char[] input, String delim) {
346 this(input);
347 setDelimiterString(delim);
348 }
349
350 /**
351 * Constructs a tokenizer splitting using the specified delimiter matcher.
352 *
353 * @param input the string which is to be parsed, not cloned
354 * @param delim the field delimiter matcher
355 */
356 public StrTokenizer(char[] input, StrMatcher delim) {
357 this(input);
358 setDelimiterMatcher(delim);
359 }
360
361 /**
362 * Constructs a tokenizer splitting on the specified delimiter character
363 * and handling quotes using the specified quote character.
364 *
365 * @param input the string which is to be parsed, not cloned
366 * @param delim the field delimiter character
367 * @param quote the field quoted string character
368 */
369 public StrTokenizer(char[] input, char delim, char quote) {
370 this(input, delim);
371 setQuoteChar(quote);
372 }
373
374 /**
375 * Constructs a tokenizer splitting using the specified delimiter matcher
376 * and handling quotes using the specified quote matcher.
377 *
378 * @param input the string which is to be parsed, not cloned
379 * @param delim the field delimiter character
380 * @param quote the field quoted string character
381 */
382 public StrTokenizer(char[] input, StrMatcher delim, StrMatcher quote) {
383 this(input, delim);
384 setQuoteMatcher(quote);
385 }
386
387 // API
388 //-----------------------------------------------------------------------
389 /**
390 * Gets the number of tokens found in the String.
391 *
392 * @return the number of matched tokens
393 */
394 public int size() {
395 checkTokenized();
396 return tokens.length;
397 }
398
399 /**
400 * Gets the next token from the String.
401 * Equivalent to {@link #next()} except it returns null rather than
402 * throwing {@link NoSuchElementException} when no tokens remain.
403 *
404 * @return the next sequential token, or null when no more tokens are found
405 */
406 public String nextToken() {
407 if (hasNext()) {
408 return tokens[tokenPos++];
409 }
410 return null;
411 }
412
413 /**
414 * Gets the previous token from the String.
415 *
416 * @return the previous sequential token, or null when no more tokens are found
417 */
418 public String previousToken() {
419 if (hasPrevious()) {
420 return tokens[--tokenPos];
421 }
422 return null;
423 }
424
425 /**
426 * Gets a copy of the full token list as an independent modifiable array.
427 *
428 * @return the tokens as a String array
429 */
430 public String[] getTokenArray() {
431 checkTokenized();
432 return tokens.clone();
433 }
434
435 /**
436 * Gets a copy of the full token list as an independent modifiable list.
437 *
438 * @return the tokens as a String array
439 */
440 public List<String> getTokenList() {
441 checkTokenized();
442 List<String> list = new ArrayList<String>(tokens.length);
443 for (String element : tokens) {
444 list.add(element);
445 }
446 return list;
447 }
448
449 /**
450 * Resets this tokenizer, forgetting all parsing and iteration already completed.
451 * <p>
452 * This method allows the same tokenizer to be reused for the same String.
453 *
454 * @return this, to enable chaining
455 */
456 public StrTokenizer reset() {
457 tokenPos = 0;
458 tokens = null;
459 return this;
460 }
461
462 /**
463 * Reset this tokenizer, giving it a new input string to parse.
464 * In this manner you can re-use a tokenizer with the same settings
465 * on multiple input lines.
466 *
467 * @param input the new string to tokenize, null sets no text to parse
468 * @return this, to enable chaining
469 */
470 public StrTokenizer reset(String input) {
471 reset();
472 if (input != null) {
473 this.chars = input.toCharArray();
474 } else {
475 this.chars = null;
476 }
477 return this;
478 }
479
480 /**
481 * Reset this tokenizer, giving it a new input string to parse.
482 * In this manner you can re-use a tokenizer with the same settings
483 * on multiple input lines.
484 *
485 * @param input the new character array to tokenize, not cloned, null sets no text to parse
486 * @return this, to enable chaining
487 */
488 public StrTokenizer reset(char[] input) {
489 reset();
490 this.chars = ArrayUtils.clone(input);
491 return this;
492 }
493
494 // ListIterator
495 //-----------------------------------------------------------------------
496 /**
497 * Checks whether there are any more tokens.
498 *
499 * @return true if there are more tokens
500 */
501 public boolean hasNext() {
502 checkTokenized();
503 return tokenPos < tokens.length;
504 }
505
506 /**
507 * Gets the next token.
508 *
509 * @return the next String token
510 * @throws NoSuchElementException if there are no more elements
511 */
512 public String next() {
513 if (hasNext()) {
514 return tokens[tokenPos++];
515 }
516 throw new NoSuchElementException();
517 }
518
519 /**
520 * Gets the index of the next token to return.
521 *
522 * @return the next token index
523 */
524 public int nextIndex() {
525 return tokenPos;
526 }
527
528 /**
529 * Checks whether there are any previous tokens that can be iterated to.
530 *
531 * @return true if there are previous tokens
532 */
533 public boolean hasPrevious() {
534 checkTokenized();
535 return tokenPos > 0;
536 }
537
538 /**
539 * Gets the token previous to the last returned token.
540 *
541 * @return the previous token
542 */
543 public String previous() {
544 if (hasPrevious()) {
545 return tokens[--tokenPos];
546 }
547 throw new NoSuchElementException();
548 }
549
550 /**
551 * Gets the index of the previous token.
552 *
553 * @return the previous token index
554 */
555 public int previousIndex() {
556 return tokenPos - 1;
557 }
558
559 /**
560 * Unsupported ListIterator operation.
561 *
562 * @throws UnsupportedOperationException always
563 */
564 public void remove() {
565 throw new UnsupportedOperationException("remove() is unsupported");
566 }
567
568 /**
569 * Unsupported ListIterator operation.
570 * @param obj this parameter ignored.
571 * @throws UnsupportedOperationException always
572 */
573 public void set(String obj) {
574 throw new UnsupportedOperationException("set() is unsupported");
575 }
576
577 /**
578 * Unsupported ListIterator operation.
579 * @param obj this parameter ignored.
580 * @throws UnsupportedOperationException always
581 */
582 public void add(String obj) {
583 throw new UnsupportedOperationException("add() is unsupported");
584 }
585
586 // Implementation
587 //-----------------------------------------------------------------------
588 /**
589 * Checks if tokenization has been done, and if not then do it.
590 */
591 private void checkTokenized() {
592 if (tokens == null) {
593 if (chars == null) {
594 // still call tokenize as subclass may do some work
595 List<String> split = tokenize(null, 0, 0);
596 tokens = split.toArray(new String[split.size()]);
597 } else {
598 List<String> split = tokenize(chars, 0, chars.length);
599 tokens = split.toArray(new String[split.size()]);
600 }
601 }
602 }
603
604 /**
605 * Internal method to performs the tokenization.
606 * <p>
607 * Most users of this class do not need to call this method. This method
608 * will be called automatically by other (public) methods when required.
609 * <p>
610 * This method exists to allow subclasses to add code before or after the
611 * tokenization. For example, a subclass could alter the character array,
612 * offset or count to be parsed, or call the tokenizer multiple times on
613 * multiple strings. It is also be possible to filter the results.
614 * <p>
615 * <code>StrTokenizer</code> will always pass a zero offset and a count
616 * equal to the length of the array to this method, however a subclass
617 * may pass other values, or even an entirely different array.
618 *
619 * @param chars the character array being tokenized, may be null
620 * @param offset the start position within the character array, must be valid
621 * @param count the number of characters to tokenize, must be valid
622 * @return the modifiable list of String tokens, unmodifiable if null array or zero count
623 */
624 protected List<String> tokenize(char[] chars, int offset, int count) {
625 if (chars == null || count == 0) {
626 return Collections.emptyList();
627 }
628 StrBuilder buf = new StrBuilder();
629 List<String> tokens = new ArrayList<String>();
630 int pos = offset;
631
632 // loop around the entire buffer
633 while (pos >= 0 && pos < count) {
634 // find next token
635 pos = readNextToken(chars, pos, count, buf, tokens);
636
637 // handle case where end of string is a delimiter
638 if (pos >= count) {
639 addToken(tokens, "");
640 }
641 }
642 return tokens;
643 }
644
645 /**
646 * Adds a token to a list, paying attention to the parameters we've set.
647 *
648 * @param list the list to add to
649 * @param tok the token to add
650 */
651 private void addToken(List<String> list, String tok) {
652 if (tok == null || tok.length() == 0) {
653 if (isIgnoreEmptyTokens()) {
654 return;
655 }
656 if (isEmptyTokenAsNull()) {
657 tok = null;
658 }
659 }
660 list.add(tok);
661 }
662
663 /**
664 * Reads character by character through the String to get the next token.
665 *
666 * @param chars the character array being tokenized
667 * @param start the first character of field
668 * @param len the length of the character array being tokenized
669 * @param workArea a temporary work area
670 * @param tokens the list of parsed tokens
671 * @return the starting position of the next field (the character
672 * immediately after the delimiter), or -1 if end of string found
673 */
674 private int readNextToken(char[] chars, int start, int len, StrBuilder workArea, List<String> tokens) {
675 // skip all leading whitespace, unless it is the
676 // field delimiter or the quote character
677 while (start < len) {
678 int removeLen = Math.max(
679 getIgnoredMatcher().isMatch(chars, start, start, len),
680 getTrimmerMatcher().isMatch(chars, start, start, len));
681 if (removeLen == 0 ||
682 getDelimiterMatcher().isMatch(chars, start, start, len) > 0 ||
683 getQuoteMatcher().isMatch(chars, start, start, len) > 0) {
684 break;
685 }
686 start += removeLen;
687 }
688
689 // handle reaching end
690 if (start >= len) {
691 addToken(tokens, "");
692 return -1;
693 }
694
695 // handle empty token
696 int delimLen = getDelimiterMatcher().isMatch(chars, start, start, len);
697 if (delimLen > 0) {
698 addToken(tokens, "");
699 return start + delimLen;
700 }
701
702 // handle found token
703 int quoteLen = getQuoteMatcher().isMatch(chars, start, start, len);
704 if (quoteLen > 0) {
705 return readWithQuotes(chars, start + quoteLen, len, workArea, tokens, start, quoteLen);
706 }
707 return readWithQuotes(chars, start, len, workArea, tokens, 0, 0);
708 }
709
710 /**
711 * Reads a possibly quoted string token.
712 *
713 * @param chars the character array being tokenized
714 * @param start the first character of field
715 * @param len the length of the character array being tokenized
716 * @param workArea a temporary work area
717 * @param tokens the list of parsed tokens
718 * @param quoteStart the start position of the matched quote, 0 if no quoting
719 * @param quoteLen the length of the matched quote, 0 if no quoting
720 * @return the starting position of the next field (the character
721 * immediately after the delimiter, or if end of string found,
722 * then the length of string
723 */
724 private int readWithQuotes(char[] chars, int start, int len, StrBuilder workArea,
725 List<String> tokens, int quoteStart, int quoteLen) {
726 // Loop until we've found the end of the quoted
727 // string or the end of the input
728 workArea.clear();
729 int pos = start;
730 boolean quoting = (quoteLen > 0);
731 int trimStart = 0;
732
733 while (pos < len) {
734 // quoting mode can occur several times throughout a string
735 // we must switch between quoting and non-quoting until we
736 // encounter a non-quoted delimiter, or end of string
737 if (quoting) {
738 // In quoting mode
739
740 // If we've found a quote character, see if it's
741 // followed by a second quote. If so, then we need
742 // to actually put the quote character into the token
743 // rather than end the token.
744 if (isQuote(chars, pos, len, quoteStart, quoteLen)) {
745 if (isQuote(chars, pos + quoteLen, len, quoteStart, quoteLen)) {
746 // matched pair of quotes, thus an escaped quote
747 workArea.append(chars, pos, quoteLen);
748 pos += (quoteLen * 2);
749 trimStart = workArea.size();
750 continue;
751 }
752
753 // end of quoting
754 quoting = false;
755 pos += quoteLen;
756 continue;
757 }
758
759 // copy regular character from inside quotes
760 workArea.append(chars[pos++]);
761 trimStart = workArea.size();
762
763 } else {
764 // Not in quoting mode
765
766 // check for delimiter, and thus end of token
767 int delimLen = getDelimiterMatcher().isMatch(chars, pos, start, len);
768 if (delimLen > 0) {
769 // return condition when end of token found
770 addToken(tokens, workArea.substring(0, trimStart));
771 return pos + delimLen;
772 }
773
774 // check for quote, and thus back into quoting mode
775 if (quoteLen > 0 && isQuote(chars, pos, len, quoteStart, quoteLen)) {
776 quoting = true;
777 pos += quoteLen;
778 continue;
779 }
780
781 // check for ignored (outside quotes), and ignore
782 int ignoredLen = getIgnoredMatcher().isMatch(chars, pos, start, len);
783 if (ignoredLen > 0) {
784 pos += ignoredLen;
785 continue;
786 }
787
788 // check for trimmed character
789 // don't yet know if its at the end, so copy to workArea
790 // use trimStart to keep track of trim at the end
791 int trimmedLen = getTrimmerMatcher().isMatch(chars, pos, start, len);
792 if (trimmedLen > 0) {
793 workArea.append(chars, pos, trimmedLen);
794 pos += trimmedLen;
795 continue;
796 }
797
798 // copy regular character from outside quotes
799 workArea.append(chars[pos++]);
800 trimStart = workArea.size();
801 }
802 }
803
804 // return condition when end of string found
805 addToken(tokens, workArea.substring(0, trimStart));
806 return -1;
807 }
808
809 /**
810 * Checks if the characters at the index specified match the quote
811 * already matched in readNextToken().
812 *
813 * @param chars the character array being tokenized
814 * @param pos the position to check for a quote
815 * @param len the length of the character array being tokenized
816 * @param quoteStart the start position of the matched quote, 0 if no quoting
817 * @param quoteLen the length of the matched quote, 0 if no quoting
818 * @return true if a quote is matched
819 */
820 private boolean isQuote(char[] chars, int pos, int len, int quoteStart, int quoteLen) {
821 for (int i = 0; i < quoteLen; i++) {
822 if ((pos + i) >= len || chars[pos + i] != chars[quoteStart + i]) {
823 return false;
824 }
825 }
826 return true;
827 }
828
829 // Delimiter
830 //-----------------------------------------------------------------------
831 /**
832 * Gets the field delimiter matcher.
833 *
834 * @return the delimiter matcher in use
835 */
836 public StrMatcher getDelimiterMatcher() {
837 return this.delimMatcher;
838 }
839
840 /**
841 * Sets the field delimiter matcher.
842 * <p>
843 * The delimitier is used to separate one token from another.
844 *
845 * @param delim the delimiter matcher to use
846 * @return this, to enable chaining
847 */
848 public StrTokenizer setDelimiterMatcher(StrMatcher delim) {
849 if (delim == null) {
850 this.delimMatcher = StrMatcher.noneMatcher();
851 } else {
852 this.delimMatcher = delim;
853 }
854 return this;
855 }
856
857 /**
858 * Sets the field delimiter character.
859 *
860 * @param delim the delimiter character to use
861 * @return this, to enable chaining
862 */
863 public StrTokenizer setDelimiterChar(char delim) {
864 return setDelimiterMatcher(StrMatcher.charMatcher(delim));
865 }
866
867 /**
868 * Sets the field delimiter string.
869 *
870 * @param delim the delimiter string to use
871 * @return this, to enable chaining
872 */
873 public StrTokenizer setDelimiterString(String delim) {
874 return setDelimiterMatcher(StrMatcher.stringMatcher(delim));
875 }
876
877 // Quote
878 //-----------------------------------------------------------------------
879 /**
880 * Gets the quote matcher currently in use.
881 * <p>
882 * The quote character is used to wrap data between the tokens.
883 * This enables delimiters to be entered as data.
884 * The default value is '"' (double quote).
885 *
886 * @return the quote matcher in use
887 */
888 public StrMatcher getQuoteMatcher() {
889 return quoteMatcher;
890 }
891
892 /**
893 * Set the quote matcher to use.
894 * <p>
895 * The quote character is used to wrap data between the tokens.
896 * This enables delimiters to be entered as data.
897 *
898 * @param quote the quote matcher to use, null ignored
899 * @return this, to enable chaining
900 */
901 public StrTokenizer setQuoteMatcher(StrMatcher quote) {
902 if (quote != null) {
903 this.quoteMatcher = quote;
904 }
905 return this;
906 }
907
908 /**
909 * Sets the quote character to use.
910 * <p>
911 * The quote character is used to wrap data between the tokens.
912 * This enables delimiters to be entered as data.
913 *
914 * @param quote the quote character to use
915 * @return this, to enable chaining
916 */
917 public StrTokenizer setQuoteChar(char quote) {
918 return setQuoteMatcher(StrMatcher.charMatcher(quote));
919 }
920
921 // Ignored
922 //-----------------------------------------------------------------------
923 /**
924 * Gets the ignored character matcher.
925 * <p>
926 * These characters are ignored when parsing the String, unless they are
927 * within a quoted region.
928 * The default value is not to ignore anything.
929 *
930 * @return the ignored matcher in use
931 */
932 public StrMatcher getIgnoredMatcher() {
933 return ignoredMatcher;
934 }
935
936 /**
937 * Set the matcher for characters to ignore.
938 * <p>
939 * These characters are ignored when parsing the String, unless they are
940 * within a quoted region.
941 *
942 * @param ignored the ignored matcher to use, null ignored
943 * @return this, to enable chaining
944 */
945 public StrTokenizer setIgnoredMatcher(StrMatcher ignored) {
946 if (ignored != null) {
947 this.ignoredMatcher = ignored;
948 }
949 return this;
950 }
951
952 /**
953 * Set the character to ignore.
954 * <p>
955 * This character is ignored when parsing the String, unless it is
956 * within a quoted region.
957 *
958 * @param ignored the ignored character to use
959 * @return this, to enable chaining
960 */
961 public StrTokenizer setIgnoredChar(char ignored) {
962 return setIgnoredMatcher(StrMatcher.charMatcher(ignored));
963 }
964
965 // Trimmer
966 //-----------------------------------------------------------------------
967 /**
968 * Gets the trimmer character matcher.
969 * <p>
970 * These characters are trimmed off on each side of the delimiter
971 * until the token or quote is found.
972 * The default value is not to trim anything.
973 *
974 * @return the trimmer matcher in use
975 */
976 public StrMatcher getTrimmerMatcher() {
977 return trimmerMatcher;
978 }
979
980 /**
981 * Sets the matcher for characters to trim.
982 * <p>
983 * These characters are trimmed off on each side of the delimiter
984 * until the token or quote is found.
985 *
986 * @param trimmer the trimmer matcher to use, null ignored
987 * @return this, to enable chaining
988 */
989 public StrTokenizer setTrimmerMatcher(StrMatcher trimmer) {
990 if (trimmer != null) {
991 this.trimmerMatcher = trimmer;
992 }
993 return this;
994 }
995
996 //-----------------------------------------------------------------------
997 /**
998 * Gets whether the tokenizer currently returns empty tokens as null.
999 * The default for this property is false.
1000 *
1001 * @return true if empty tokens are returned as null
1002 */
1003 public boolean isEmptyTokenAsNull() {
1004 return this.emptyAsNull;
1005 }
1006
1007 /**
1008 * Sets whether the tokenizer should return empty tokens as null.
1009 * The default for this property is false.
1010 *
1011 * @param emptyAsNull whether empty tokens are returned as null
1012 * @return this, to enable chaining
1013 */
1014 public StrTokenizer setEmptyTokenAsNull(boolean emptyAsNull) {
1015 this.emptyAsNull = emptyAsNull;
1016 return this;
1017 }
1018
1019 //-----------------------------------------------------------------------
1020 /**
1021 * Gets whether the tokenizer currently ignores empty tokens.
1022 * The default for this property is true.
1023 *
1024 * @return true if empty tokens are not returned
1025 */
1026 public boolean isIgnoreEmptyTokens() {
1027 return ignoreEmptyTokens;
1028 }
1029
1030 /**
1031 * Sets whether the tokenizer should ignore and not return empty tokens.
1032 * The default for this property is true.
1033 *
1034 * @param ignoreEmptyTokens whether empty tokens are not returned
1035 * @return this, to enable chaining
1036 */
1037 public StrTokenizer setIgnoreEmptyTokens(boolean ignoreEmptyTokens) {
1038 this.ignoreEmptyTokens = ignoreEmptyTokens;
1039 return this;
1040 }
1041
1042 //-----------------------------------------------------------------------
1043 /**
1044 * Gets the String content that the tokenizer is parsing.
1045 *
1046 * @return the string content being parsed
1047 */
1048 public String getContent() {
1049 if (chars == null) {
1050 return null;
1051 }
1052 return new String(chars);
1053 }
1054
1055 //-----------------------------------------------------------------------
1056 /**
1057 * Creates a new instance of this Tokenizer. The new instance is reset so
1058 * that it will be at the start of the token list.
1059 * If a {@link CloneNotSupportedException} is caught, return <code>null</code>.
1060 *
1061 * @return a new instance of this Tokenizer which has been reset.
1062 */
1063 @Override
1064 public Object clone() {
1065 try {
1066 return cloneReset();
1067 } catch (CloneNotSupportedException ex) {
1068 return null;
1069 }
1070 }
1071
1072 /**
1073 * Creates a new instance of this Tokenizer. The new instance is reset so that
1074 * it will be at the start of the token list.
1075 *
1076 * @return a new instance of this Tokenizer which has been reset.
1077 * @throws CloneNotSupportedException if there is a problem cloning
1078 */
1079 Object cloneReset() throws CloneNotSupportedException {
1080 // this method exists to enable 100% test coverage
1081 StrTokenizer cloned = (StrTokenizer) super.clone();
1082 if (cloned.chars != null) {
1083 cloned.chars = cloned.chars.clone();
1084 }
1085 cloned.reset();
1086 return cloned;
1087 }
1088
1089 //-----------------------------------------------------------------------
1090 /**
1091 * Gets the String content that the tokenizer is parsing.
1092 *
1093 * @return the string content being parsed
1094 */
1095 @Override
1096 public String toString() {
1097 if (tokens == null) {
1098 return "StrTokenizer[not tokenized yet]";
1099 }
1100 return "StrTokenizer" + getTokenList();
1101 }
1102
1103 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import org.apache.commons.lang3.StringUtils;
19 import org.apache.commons.lang3.SystemUtils;
20
21 /**
22 * <p>Operations on Strings that contain words.</p>
23 *
24 * <p>This class tries to handle <code>null</code> input gracefully.
25 * An exception will not be thrown for a <code>null</code> input.
26 * Each method documents its behaviour in more detail.</p>
27 *
28 * @since 2.0
29 * @version $Id: WordUtils.java 1148520 2011-07-19 20:53:23Z ggregory $
30 */
31 public class WordUtils {
32
33 /**
34 * <p><code>WordUtils</code> instances should NOT be constructed in
35 * standard programming. Instead, the class should be used as
36 * <code>WordUtils.wrap("foo bar", 20);</code>.</p>
37 *
38 * <p>This constructor is public to permit tools that require a JavaBean
39 * instance to operate.</p>
40 */
41 public WordUtils() {
42 super();
43 }
44
45 // Wrapping
46 //--------------------------------------------------------------------------
47 /**
48 * <p>Wraps a single line of text, identifying words by <code>' '</code>.</p>
49 *
50 * <p>New lines will be separated by the system property line separator.
51 * Very long words, such as URLs will <i>not</i> be wrapped.</p>
52 *
53 * <p>Leading spaces on a new line are stripped.
54 * Trailing spaces are not stripped.</p>
55 *
56 * <pre>
57 * WordUtils.wrap(null, *) = null
58 * WordUtils.wrap("", *) = ""
59 * </pre>
60 *
61 * @param str the String to be word wrapped, may be null
62 * @param wrapLength the column to wrap the words at, less than 1 is treated as 1
63 * @return a line with newlines inserted, <code>null</code> if null input
64 */
65 public static String wrap(String str, int wrapLength) {
66 return wrap(str, wrapLength, null, false);
67 }
68
69 /**
70 * <p>Wraps a single line of text, identifying words by <code>' '</code>.</p>
71 *
72 * <p>Leading spaces on a new line are stripped.
73 * Trailing spaces are not stripped.</p>
74 *
75 * <pre>
76 * WordUtils.wrap(null, *, *, *) = null
77 * WordUtils.wrap("", *, *, *) = ""
78 * </pre>
79 *
80 * @param str the String to be word wrapped, may be null
81 * @param wrapLength the column to wrap the words at, less than 1 is treated as 1
82 * @param newLineStr the string to insert for a new line,
83 * <code>null</code> uses the system property line separator
84 * @param wrapLongWords true if long words (such as URLs) should be wrapped
85 * @return a line with newlines inserted, <code>null</code> if null input
86 */
87 public static String wrap(String str, int wrapLength, String newLineStr, boolean wrapLongWords) {
88 if (str == null) {
89 return null;
90 }
91 if (newLineStr == null) {
92 newLineStr = SystemUtils.LINE_SEPARATOR;
93 }
94 if (wrapLength < 1) {
95 wrapLength = 1;
96 }
97 int inputLineLength = str.length();
98 int offset = 0;
99 StringBuilder wrappedLine = new StringBuilder(inputLineLength + 32);
100
101 while ((inputLineLength - offset) > wrapLength) {
102 if (str.charAt(offset) == ' ') {
103 offset++;
104 continue;
105 }
106 int spaceToWrapAt = str.lastIndexOf(' ', wrapLength + offset);
107
108 if (spaceToWrapAt >= offset) {
109 // normal case
110 wrappedLine.append(str.substring(offset, spaceToWrapAt));
111 wrappedLine.append(newLineStr);
112 offset = spaceToWrapAt + 1;
113
114 } else {
115 // really long word or URL
116 if (wrapLongWords) {
117 // wrap really long word one line at a time
118 wrappedLine.append(str.substring(offset, wrapLength + offset));
119 wrappedLine.append(newLineStr);
120 offset += wrapLength;
121 } else {
122 // do not wrap really long word, just extend beyond limit
123 spaceToWrapAt = str.indexOf(' ', wrapLength + offset);
124 if (spaceToWrapAt >= 0) {
125 wrappedLine.append(str.substring(offset, spaceToWrapAt));
126 wrappedLine.append(newLineStr);
127 offset = spaceToWrapAt + 1;
128 } else {
129 wrappedLine.append(str.substring(offset));
130 offset = inputLineLength;
131 }
132 }
133 }
134 }
135
136 // Whatever is left in line is short enough to just pass through
137 wrappedLine.append(str.substring(offset));
138
139 return wrappedLine.toString();
140 }
141
142 // Capitalizing
143 //-----------------------------------------------------------------------
144 /**
145 * <p>Capitalizes all the whitespace separated words in a String.
146 * Only the first letter of each word is changed. To convert the
147 * rest of each word to lowercase at the same time,
148 * use {@link #capitalizeFully(String)}.</p>
149 *
150 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
151 * A <code>null</code> input String returns <code>null</code>.
152 * Capitalization uses the Unicode title case, normally equivalent to
153 * upper case.</p>
154 *
155 * <pre>
156 * WordUtils.capitalize(null) = null
157 * WordUtils.capitalize("") = ""
158 * WordUtils.capitalize("i am FINE") = "I Am FINE"
159 * </pre>
160 *
161 * @param str the String to capitalize, may be null
162 * @return capitalized String, <code>null</code> if null String input
163 * @see #uncapitalize(String)
164 * @see #capitalizeFully(String)
165 */
166 public static String capitalize(String str) {
167 return capitalize(str, null);
168 }
169
170 /**
171 * <p>Capitalizes all the delimiter separated words in a String.
172 * Only the first letter of each word is changed. To convert the
173 * rest of each word to lowercase at the same time,
174 * use {@link #capitalizeFully(String, char[])}.</p>
175 *
176 * <p>The delimiters represent a set of characters understood to separate words.
177 * The first string character and the first non-delimiter character after a
178 * delimiter will be capitalized. </p>
179 *
180 * <p>A <code>null</code> input String returns <code>null</code>.
181 * Capitalization uses the Unicode title case, normally equivalent to
182 * upper case.</p>
183 *
184 * <pre>
185 * WordUtils.capitalize(null, *) = null
186 * WordUtils.capitalize("", *) = ""
187 * WordUtils.capitalize(*, new char[0]) = *
188 * WordUtils.capitalize("i am fine", null) = "I Am Fine"
189 * WordUtils.capitalize("i aM.fine", {'.'}) = "I aM.Fine"
190 * </pre>
191 *
192 * @param str the String to capitalize, may be null
193 * @param delimiters set of characters to determine capitalization, null means whitespace
194 * @return capitalized String, <code>null</code> if null String input
195 * @see #uncapitalize(String)
196 * @see #capitalizeFully(String)
197 * @since 2.1
198 */
199 public static String capitalize(String str, char... delimiters) {
200 int delimLen = delimiters == null ? -1 : delimiters.length;
201 if (StringUtils.isEmpty(str) || delimLen == 0) {
202 return str;
203 }
204 char[] buffer = str.toCharArray();
205 boolean capitalizeNext = true;
206 for (int i = 0; i < buffer.length; i++) {
207 char ch = buffer[i];
208 if (isDelimiter(ch, delimiters)) {
209 capitalizeNext = true;
210 } else if (capitalizeNext) {
211 buffer[i] = Character.toTitleCase(ch);
212 capitalizeNext = false;
213 }
214 }
215 return new String(buffer);
216 }
217
218 //-----------------------------------------------------------------------
219 /**
220 * <p>Converts all the whitespace separated words in a String into capitalized words,
221 * that is each word is made up of a titlecase character and then a series of
222 * lowercase characters. </p>
223 *
224 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
225 * A <code>null</code> input String returns <code>null</code>.
226 * Capitalization uses the Unicode title case, normally equivalent to
227 * upper case.</p>
228 *
229 * <pre>
230 * WordUtils.capitalizeFully(null) = null
231 * WordUtils.capitalizeFully("") = ""
232 * WordUtils.capitalizeFully("i am FINE") = "I Am Fine"
233 * </pre>
234 *
235 * @param str the String to capitalize, may be null
236 * @return capitalized String, <code>null</code> if null String input
237 */
238 public static String capitalizeFully(String str) {
239 return capitalizeFully(str, null);
240 }
241
242 /**
243 * <p>Converts all the delimiter separated words in a String into capitalized words,
244 * that is each word is made up of a titlecase character and then a series of
245 * lowercase characters. </p>
246 *
247 * <p>The delimiters represent a set of characters understood to separate words.
248 * The first string character and the first non-delimiter character after a
249 * delimiter will be capitalized. </p>
250 *
251 * <p>A <code>null</code> input String returns <code>null</code>.
252 * Capitalization uses the Unicode title case, normally equivalent to
253 * upper case.</p>
254 *
255 * <pre>
256 * WordUtils.capitalizeFully(null, *) = null
257 * WordUtils.capitalizeFully("", *) = ""
258 * WordUtils.capitalizeFully(*, null) = *
259 * WordUtils.capitalizeFully(*, new char[0]) = *
260 * WordUtils.capitalizeFully("i aM.fine", {'.'}) = "I am.Fine"
261 * </pre>
262 *
263 * @param str the String to capitalize, may be null
264 * @param delimiters set of characters to determine capitalization, null means whitespace
265 * @return capitalized String, <code>null</code> if null String input
266 * @since 2.1
267 */
268 public static String capitalizeFully(String str, char... delimiters) {
269 int delimLen = (delimiters == null ? -1 : delimiters.length);
270 if (StringUtils.isEmpty(str) || delimLen == 0) {
271 return str;
272 }
273 str = str.toLowerCase();
274 return capitalize(str, delimiters);
275 }
276
277 //-----------------------------------------------------------------------
278 /**
279 * <p>Uncapitalizes all the whitespace separated words in a String.
280 * Only the first letter of each word is changed.</p>
281 *
282 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
283 * A <code>null</code> input String returns <code>null</code>.</p>
284 *
285 * <pre>
286 * WordUtils.uncapitalize(null) = null
287 * WordUtils.uncapitalize("") = ""
288 * WordUtils.uncapitalize("I Am FINE") = "i am fINE"
289 * </pre>
290 *
291 * @param str the String to uncapitalize, may be null
292 * @return uncapitalized String, <code>null</code> if null String input
293 * @see #capitalize(String)
294 */
295 public static String uncapitalize(String str) {
296 return uncapitalize(str, null);
297 }
298
299 /**
300 * <p>Uncapitalizes all the whitespace separated words in a String.
301 * Only the first letter of each word is changed.</p>
302 *
303 * <p>The delimiters represent a set of characters understood to separate words.
304 * The first string character and the first non-delimiter character after a
305 * delimiter will be uncapitalized. </p>
306 *
307 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
308 * A <code>null</code> input String returns <code>null</code>.</p>
309 *
310 * <pre>
311 * WordUtils.uncapitalize(null, *) = null
312 * WordUtils.uncapitalize("", *) = ""
313 * WordUtils.uncapitalize(*, null) = *
314 * WordUtils.uncapitalize(*, new char[0]) = *
315 * WordUtils.uncapitalize("I AM.FINE", {'.'}) = "i AM.fINE"
316 * </pre>
317 *
318 * @param str the String to uncapitalize, may be null
319 * @param delimiters set of characters to determine uncapitalization, null means whitespace
320 * @return uncapitalized String, <code>null</code> if null String input
321 * @see #capitalize(String)
322 * @since 2.1
323 */
324 public static String uncapitalize(String str, char... delimiters) {
325 int delimLen = (delimiters == null ? -1 : delimiters.length);
326 if (StringUtils.isEmpty(str) || delimLen == 0) {
327 return str;
328 }
329 char[] buffer = str.toCharArray();
330 boolean uncapitalizeNext = true;
331 for (int i = 0; i < buffer.length; i++) {
332 char ch = buffer[i];
333 if (isDelimiter(ch, delimiters)) {
334 uncapitalizeNext = true;
335 } else if (uncapitalizeNext) {
336 buffer[i] = Character.toLowerCase(ch);
337 uncapitalizeNext = false;
338 }
339 }
340 return new String(buffer);
341 }
342
343 //-----------------------------------------------------------------------
344 /**
345 * <p>Swaps the case of a String using a word based algorithm.</p>
346 *
347 * <ul>
348 * <li>Upper case character converts to Lower case</li>
349 * <li>Title case character converts to Lower case</li>
350 * <li>Lower case character after Whitespace or at start converts to Title case</li>
351 * <li>Other Lower case character converts to Upper case</li>
352 * </ul>
353 *
354 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
355 * A <code>null</code> input String returns <code>null</code>.</p>
356 *
357 * <pre>
358 * StringUtils.swapCase(null) = null
359 * StringUtils.swapCase("") = ""
360 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
361 * </pre>
362 *
363 * @param str the String to swap case, may be null
364 * @return the changed String, <code>null</code> if null String input
365 */
366 public static String swapCase(String str) {
367 if (StringUtils.isEmpty(str)) {
368 return str;
369 }
370 char[] buffer = str.toCharArray();
371
372 boolean whitespace = true;
373
374 for (int i = 0; i < buffer.length; i++) {
375 char ch = buffer[i];
376 if (Character.isUpperCase(ch)) {
377 buffer[i] = Character.toLowerCase(ch);
378 whitespace = false;
379 } else if (Character.isTitleCase(ch)) {
380 buffer[i] = Character.toLowerCase(ch);
381 whitespace = false;
382 } else if (Character.isLowerCase(ch)) {
383 if (whitespace) {
384 buffer[i] = Character.toTitleCase(ch);
385 whitespace = false;
386 } else {
387 buffer[i] = Character.toUpperCase(ch);
388 }
389 } else {
390 whitespace = Character.isWhitespace(ch);
391 }
392 }
393 return new String(buffer);
394 }
395
396 //-----------------------------------------------------------------------
397 /**
398 * <p>Extracts the initial letters from each word in the String.</p>
399 *
400 * <p>The first letter of the string and all first letters after
401 * whitespace are returned as a new string.
402 * Their case is not changed.</p>
403 *
404 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.
405 * A <code>null</code> input String returns <code>null</code>.</p>
406 *
407 * <pre>
408 * WordUtils.initials(null) = null
409 * WordUtils.initials("") = ""
410 * WordUtils.initials("Ben John Lee") = "BJL"
411 * WordUtils.initials("Ben J.Lee") = "BJ"
412 * </pre>
413 *
414 * @param str the String to get initials from, may be null
415 * @return String of initial letters, <code>null</code> if null String input
416 * @see #initials(String,char[])
417 * @since 2.2
418 */
419 public static String initials(String str) {
420 return initials(str, null);
421 }
422
423 /**
424 * <p>Extracts the initial letters from each word in the String.</p>
425 *
426 * <p>The first letter of the string and all first letters after the
427 * defined delimiters are returned as a new string.
428 * Their case is not changed.</p>
429 *
430 * <p>If the delimiters array is null, then Whitespace is used.
431 * Whitespace is defined by {@link Character#isWhitespace(char)}.
432 * A <code>null</code> input String returns <code>null</code>.
433 * An empty delimiter array returns an empty String.</p>
434 *
435 * <pre>
436 * WordUtils.initials(null, *) = null
437 * WordUtils.initials("", *) = ""
438 * WordUtils.initials("Ben John Lee", null) = "BJL"
439 * WordUtils.initials("Ben J.Lee", null) = "BJ"
440 * WordUtils.initials("Ben J.Lee", [' ','.']) = "BJL"
441 * WordUtils.initials(*, new char[0]) = ""
442 * </pre>
443 *
444 * @param str the String to get initials from, may be null
445 * @param delimiters set of characters to determine words, null means whitespace
446 * @return String of initial letters, <code>null</code> if null String input
447 * @see #initials(String)
448 * @since 2.2
449 */
450 public static String initials(String str, char... delimiters) {
451 if (StringUtils.isEmpty(str)) {
452 return str;
453 }
454 if (delimiters != null && delimiters.length == 0) {
455 return "";
456 }
457 int strLen = str.length();
458 char[] buf = new char[strLen / 2 + 1];
459 int count = 0;
460 boolean lastWasGap = true;
461 for (int i = 0; i < strLen; i++) {
462 char ch = str.charAt(i);
463
464 if (isDelimiter(ch, delimiters)) {
465 lastWasGap = true;
466 } else if (lastWasGap) {
467 buf[count++] = ch;
468 lastWasGap = false;
469 } else {
470 continue; // ignore ch
471 }
472 }
473 return new String(buf, 0, count);
474 }
475
476 //-----------------------------------------------------------------------
477 /**
478 * Is the character a delimiter.
479 *
480 * @param ch the character to check
481 * @param delimiters the delimiters
482 * @return true if it is a delimiter
483 */
484 private static boolean isDelimiter(char ch, char[] delimiters) {
485 if (delimiters == null) {
486 return Character.isWhitespace(ch);
487 }
488 for (char delimiter : delimiters) {
489 if (ch == delimiter) {
490 return true;
491 }
492 }
493 return false;
494 }
495
496 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 <p>
19 Provides classes for handling and manipulating text, partly as an extension to {@link java.text}.
20 The classes in this package are, for the most part, intended to be instantiated.
21 (ie. they are not utility classes with lots of static methods)
22 </p>
23 @since 2.1
24 </body>
25 </html>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text.translate;
17
18 import java.io.IOException;
19 import java.io.Writer;
20
21 import org.apache.commons.lang3.ArrayUtils;
22
23 /**
24 * Executes a sequence of translators one after the other. Execution ends whenever
25 * the first translator consumes codepoints from the input.
26 *
27 * @since 3.0
28 * @version $Id: AggregateTranslator.java 1088899 2011-04-05 05:31:27Z bayard $
29 */
30 public class AggregateTranslator extends CharSequenceTranslator {
31
32 private final CharSequenceTranslator[] translators;
33
34 /**
35 * Specify the translators to be used at creation time.
36 *
37 * @param translators CharSequenceTranslator array to aggregate
38 */
39 public AggregateTranslator(CharSequenceTranslator... translators) {
40 this.translators = ArrayUtils.clone(translators);
41 }
42
43 /**
44 * The first translator to consume codepoints from the input is the 'winner'.
45 * Execution stops with the number of consumed codepoints being returned.
46 * {@inheritDoc}
47 */
48 @Override
49 public int translate(CharSequence input, int index, Writer out) throws IOException {
50 for (CharSequenceTranslator translator : translators) {
51 int consumed = translator.translate(input, index, out);
52 if(consumed != 0) {
53 return consumed;
54 }
55 }
56 return 0;
57 }
58
59 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text.translate;
17
18 import java.io.IOException;
19 import java.io.StringWriter;
20 import java.io.Writer;
21 import java.util.Locale;
22
23 /**
24 * An API for translating text.
25 * Its core use is to escape and unescape text. Because escaping and unescaping
26 * is completely contextual, the API does not present two separate signatures.
27 *
28 * @since 3.0
29 * @version $Id: CharSequenceTranslator.java 1146844 2011-07-14 18:49:51Z mbenson $
30 */
31 public abstract class CharSequenceTranslator {
32
33 /**
34 * Translate a set of codepoints, represented by an int index into a CharSequence,
35 * into another set of codepoints. The number of codepoints consumed must be returned,
36 * and the only IOExceptions thrown must be from interacting with the Writer so that
37 * the top level API may reliable ignore StringWriter IOExceptions.
38 *
39 * @param input CharSequence that is being translated
40 * @param index int representing the current point of translation
41 * @param out Writer to translate the text to
42 * @return int count of codepoints consumed
43 * @throws IOException if and only if the Writer produces an IOException
44 */
45 public abstract int translate(CharSequence input, int index, Writer out) throws IOException;
46
47 /**
48 * Helper for non-Writer usage.
49 * @param input CharSequence to be translated
50 * @return String output of translation
51 */
52 public final String translate(CharSequence input) {
53 if (input == null) {
54 return null;
55 }
56 try {
57 StringWriter writer = new StringWriter(input.length() * 2);
58 translate(input, writer);
59 return writer.toString();
60 } catch (IOException ioe) {
61 // this should never ever happen while writing to a StringWriter
62 throw new RuntimeException(ioe);
63 }
64 }
65
66 /**
67 * Translate an input onto a Writer. This is intentionally final as its algorithm is
68 * tightly coupled with the abstract method of this class.
69 *
70 * @param input CharSequence that is being translated
71 * @param out Writer to translate the text to
72 * @throws IOException if and only if the Writer produces an IOException
73 */
74 public final void translate(CharSequence input, Writer out) throws IOException {
75 if (out == null) {
76 throw new IllegalArgumentException("The Writer must not be null");
77 }
78 if (input == null) {
79 return;
80 }
81 int pos = 0;
82 int len = input.length();
83 while (pos < len) {
84 int consumed = translate(input, pos, out);
85 if (consumed == 0) {
86 char[] c = Character.toChars(Character.codePointAt(input, pos));
87 out.write(c);
88 pos+= c.length;
89 continue;
90 }
91 // // contract with translators is that they have to understand codepoints
92 // // and they just took care of a surrogate pair
93 for (int pt = 0; pt < consumed; pt++) {
94 pos += Character.charCount(Character.codePointAt(input, pos));
95 }
96 }
97 }
98
99 /**
100 * Helper method to create a merger of this translator with another set of
101 * translators. Useful in customizing the standard functionality.
102 *
103 * @param translators CharSequenceTranslator array of translators to merge with this one
104 * @return CharSequenceTranslator merging this translator with the others
105 */
106 public final CharSequenceTranslator with(CharSequenceTranslator... translators) {
107 CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1];
108 newArray[0] = this;
109 System.arraycopy(translators, 0, newArray, 1, translators.length);
110 return new AggregateTranslator(newArray);
111 }
112
113 /**
114 * <p>Returns an upper case hexadecimal <code>String</code> for the given
115 * character.</p>
116 *
117 * @param codepoint The codepoint to convert.
118 * @return An upper case hexadecimal <code>String</code>
119 */
120 public static String hex(int codepoint) {
121 return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH);
122 }
123
124 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text.translate;
17
18 import java.io.IOException;
19 import java.io.Writer;
20
21 /**
22 * Helper subclass to CharSequenceTranslator to allow for translations that
23 * will replace up to one character at a time.
24 *
25 * @since 3.0
26 * @version $Id: CodePointTranslator.java 1139924 2011-06-26 19:32:14Z mbenson $
27 */
28 public abstract class CodePointTranslator extends CharSequenceTranslator {
29
30 /**
31 * Implementation of translate that maps onto the abstract translate(int, Writer) method.
32 * {@inheritDoc}
33 */
34 @Override
35 public final int translate(CharSequence input, int index, Writer out) throws IOException {
36 int codepoint = Character.codePointAt(input, index);
37 boolean consumed = translate(codepoint, out);
38 if (consumed) {
39 return 1;
40 } else {
41 return 0;
42 }
43 }
44
45 /**
46 * Translate the specified codepoint into another.
47 *
48 * @param codepoint int character input to translate
49 * @param out Writer to optionally push the translated output to
50 * @return boolean as to whether translation occurred or not
51 * @throws IOException if and only if the Writer produces an IOException
52 */
53 public abstract boolean translate(int codepoint, Writer out) throws IOException;
54
55 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text.translate;
17
18 /**
19 * Class holding various entity data for HTML and XML - generally for use with
20 * the LookupTranslator.
21 * All arrays are of length [*][2].
22 *
23 * @since 3.0
24 * @version $Id: EntityArrays.java 1088899 2011-04-05 05:31:27Z bayard $
25 */
26 public class EntityArrays {
27
28 /**
29 * Mapping to escape <a href="https://secure.wikimedia.org/wikipedia/en/wiki/ISO/IEC_8859-1">ISO-8859-1</a>
30 * characters to their named HTML 3.x equivalents.
31 * @return the mapping table
32 */
33 public static String[][] ISO8859_1_ESCAPE() { return ISO8859_1_ESCAPE.clone(); }
34 private static final String[][] ISO8859_1_ESCAPE = {
35 {"\u00A0", "&nbsp;"}, // non-breaking space
36 {"\u00A1", "&iexcl;"}, // inverted exclamation mark
37 {"\u00A2", "&cent;"}, // cent sign
38 {"\u00A3", "&pound;"}, // pound sign
39 {"\u00A4", "&curren;"}, // currency sign
40 {"\u00A5", "&yen;"}, // yen sign = yuan sign
41 {"\u00A6", "&brvbar;"}, // broken bar = broken vertical bar
42 {"\u00A7", "&sect;"}, // section sign
43 {"\u00A8", "&uml;"}, // diaeresis = spacing diaeresis
44 {"\u00A9", "&copy;"}, // © - copyright sign
45 {"\u00AA", "&ordf;"}, // feminine ordinal indicator
46 {"\u00AB", "&laquo;"}, // left-pointing double angle quotation mark = left pointing guillemet
47 {"\u00AC", "&not;"}, // not sign
48 {"\u00AD", "&shy;"}, // soft hyphen = discretionary hyphen
49 {"\u00AE", "&reg;"}, // ® - registered trademark sign
50 {"\u00AF", "&macr;"}, // macron = spacing macron = overline = APL overbar
51 {"\u00B0", "&deg;"}, // degree sign
52 {"\u00B1", "&plusmn;"}, // plus-minus sign = plus-or-minus sign
53 {"\u00B2", "&sup2;"}, // superscript two = superscript digit two = squared
54 {"\u00B3", "&sup3;"}, // superscript three = superscript digit three = cubed
55 {"\u00B4", "&acute;"}, // acute accent = spacing acute
56 {"\u00B5", "&micro;"}, // micro sign
57 {"\u00B6", "&para;"}, // pilcrow sign = paragraph sign
58 {"\u00B7", "&middot;"}, // middle dot = Georgian comma = Greek middle dot
59 {"\u00B8", "&cedil;"}, // cedilla = spacing cedilla
60 {"\u00B9", "&sup1;"}, // superscript one = superscript digit one
61 {"\u00BA", "&ordm;"}, // masculine ordinal indicator
62 {"\u00BB", "&raquo;"}, // right-pointing double angle quotation mark = right pointing guillemet
63 {"\u00BC", "&frac14;"}, // vulgar fraction one quarter = fraction one quarter
64 {"\u00BD", "&frac12;"}, // vulgar fraction one half = fraction one half
65 {"\u00BE", "&frac34;"}, // vulgar fraction three quarters = fraction three quarters
66 {"\u00BF", "&iquest;"}, // inverted question mark = turned question mark
67 {"\u00C0", "&Agrave;"}, // À - uppercase A, grave accent
68 {"\u00C1", "&Aacute;"}, // Á - uppercase A, acute accent
69 {"\u00C2", "&Acirc;"}, // Â - uppercase A, circumflex accent
70 {"\u00C3", "&Atilde;"}, // Ã - uppercase A, tilde
71 {"\u00C4", "&Auml;"}, // Ä - uppercase A, umlaut
72 {"\u00C5", "&Aring;"}, // Å - uppercase A, ring
73 {"\u00C6", "&AElig;"}, // Æ - uppercase AE
74 {"\u00C7", "&Ccedil;"}, // Ç - uppercase C, cedilla
75 {"\u00C8", "&Egrave;"}, // È - uppercase E, grave accent
76 {"\u00C9", "&Eacute;"}, // É - uppercase E, acute accent
77 {"\u00CA", "&Ecirc;"}, // Ê - uppercase E, circumflex accent
78 {"\u00CB", "&Euml;"}, // Ë - uppercase E, umlaut
79 {"\u00CC", "&Igrave;"}, // Ì - uppercase I, grave accent
80 {"\u00CD", "&Iacute;"}, // Í - uppercase I, acute accent
81 {"\u00CE", "&Icirc;"}, // Î - uppercase I, circumflex accent
82 {"\u00CF", "&Iuml;"}, // Ï - uppercase I, umlaut
83 {"\u00D0", "&ETH;"}, // Ð - uppercase Eth, Icelandic
84 {"\u00D1", "&Ntilde;"}, // Ñ - uppercase N, tilde
85 {"\u00D2", "&Ograve;"}, // Ò - uppercase O, grave accent
86 {"\u00D3", "&Oacute;"}, // Ó - uppercase O, acute accent
87 {"\u00D4", "&Ocirc;"}, // Ô - uppercase O, circumflex accent
88 {"\u00D5", "&Otilde;"}, // Õ - uppercase O, tilde
89 {"\u00D6", "&Ouml;"}, // Ö - uppercase O, umlaut
90 {"\u00D7", "&times;"}, // multiplication sign
91 {"\u00D8", "&Oslash;"}, // Ø - uppercase O, slash
92 {"\u00D9", "&Ugrave;"}, // Ù - uppercase U, grave accent
93 {"\u00DA", "&Uacute;"}, // Ú - uppercase U, acute accent
94 {"\u00DB", "&Ucirc;"}, // Û - uppercase U, circumflex accent
95 {"\u00DC", "&Uuml;"}, // Ü - uppercase U, umlaut
96 {"\u00DD", "&Yacute;"}, // Ý - uppercase Y, acute accent
97 {"\u00DE", "&THORN;"}, // Þ - uppercase THORN, Icelandic
98 {"\u00DF", "&szlig;"}, // ß - lowercase sharps, German
99 {"\u00E0", "&agrave;"}, // à - lowercase a, grave accent
100 {"\u00E1", "&aacute;"}, // á - lowercase a, acute accent
101 {"\u00E2", "&acirc;"}, // â - lowercase a, circumflex accent
102 {"\u00E3", "&atilde;"}, // ã - lowercase a, tilde
103 {"\u00E4", "&auml;"}, // ä - lowercase a, umlaut
104 {"\u00E5", "&aring;"}, // å - lowercase a, ring
105 {"\u00E6", "&aelig;"}, // æ - lowercase ae
106 {"\u00E7", "&ccedil;"}, // ç - lowercase c, cedilla
107 {"\u00E8", "&egrave;"}, // è - lowercase e, grave accent
108 {"\u00E9", "&eacute;"}, // é - lowercase e, acute accent
109 {"\u00EA", "&ecirc;"}, // ê - lowercase e, circumflex accent
110 {"\u00EB", "&euml;"}, // ë - lowercase e, umlaut
111 {"\u00EC", "&igrave;"}, // ì - lowercase i, grave accent
112 {"\u00ED", "&iacute;"}, // í - lowercase i, acute accent
113 {"\u00EE", "&icirc;"}, // î - lowercase i, circumflex accent
114 {"\u00EF", "&iuml;"}, // ï - lowercase i, umlaut
115 {"\u00F0", "&eth;"}, // ð - lowercase eth, Icelandic
116 {"\u00F1", "&ntilde;"}, // ñ - lowercase n, tilde
117 {"\u00F2", "&ograve;"}, // ò - lowercase o, grave accent
118 {"\u00F3", "&oacute;"}, // ó - lowercase o, acute accent
119 {"\u00F4", "&ocirc;"}, // ô - lowercase o, circumflex accent
120 {"\u00F5", "&otilde;"}, // õ - lowercase o, tilde
121 {"\u00F6", "&ouml;"}, // ö - lowercase o, umlaut
122 {"\u00F7", "&divide;"}, // division sign
123 {"\u00F8", "&oslash;"}, // ø - lowercase o, slash
124 {"\u00F9", "&ugrave;"}, // ù - lowercase u, grave accent
125 {"\u00FA", "&uacute;"}, // ú - lowercase u, acute accent
126 {"\u00FB", "&ucirc;"}, // û - lowercase u, circumflex accent
127 {"\u00FC", "&uuml;"}, // ü - lowercase u, umlaut
128 {"\u00FD", "&yacute;"}, // ý - lowercase y, acute accent
129 {"\u00FE", "&thorn;"}, // þ - lowercase thorn, Icelandic
130 {"\u00FF", "&yuml;"}, // ÿ - lowercase y, umlaut
131 };
132
133 /**
134 * Reverse of {@link #ISO8859_1_ESCAPE()} for unescaping purposes.
135 * @return the mapping table
136 */
137 public static String[][] ISO8859_1_UNESCAPE() { return ISO8859_1_UNESCAPE.clone(); }
138 private static final String[][] ISO8859_1_UNESCAPE = invert(ISO8859_1_ESCAPE);
139
140 /**
141 * Mapping to escape additional <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">character entity
142 * references</a>. Note that this must be used with {@link #ISO8859_1_ESCAPE()} to get the full list of
143 * HTML 4.0 character entities.
144 * @return the mapping table
145 */
146 public static String[][] HTML40_EXTENDED_ESCAPE() { return HTML40_EXTENDED_ESCAPE.clone(); }
147 private static final String[][] HTML40_EXTENDED_ESCAPE = {
148 // <!-- Latin Extended-B -->
149 {"\u0192", "&fnof;"}, // latin small f with hook = function= florin, U+0192 ISOtech -->
150 // <!-- Greek -->
151 {"\u0391", "&Alpha;"}, // greek capital letter alpha, U+0391 -->
152 {"\u0392", "&Beta;"}, // greek capital letter beta, U+0392 -->
153 {"\u0393", "&Gamma;"}, // greek capital letter gamma,U+0393 ISOgrk3 -->
154 {"\u0394", "&Delta;"}, // greek capital letter delta,U+0394 ISOgrk3 -->
155 {"\u0395", "&Epsilon;"}, // greek capital letter epsilon, U+0395 -->
156 {"\u0396", "&Zeta;"}, // greek capital letter zeta, U+0396 -->
157 {"\u0397", "&Eta;"}, // greek capital letter eta, U+0397 -->
158 {"\u0398", "&Theta;"}, // greek capital letter theta,U+0398 ISOgrk3 -->
159 {"\u0399", "&Iota;"}, // greek capital letter iota, U+0399 -->
160 {"\u039A", "&Kappa;"}, // greek capital letter kappa, U+039A -->
161 {"\u039B", "&Lambda;"}, // greek capital letter lambda,U+039B ISOgrk3 -->
162 {"\u039C", "&Mu;"}, // greek capital letter mu, U+039C -->
163 {"\u039D", "&Nu;"}, // greek capital letter nu, U+039D -->
164 {"\u039E", "&Xi;"}, // greek capital letter xi, U+039E ISOgrk3 -->
165 {"\u039F", "&Omicron;"}, // greek capital letter omicron, U+039F -->
166 {"\u03A0", "&Pi;"}, // greek capital letter pi, U+03A0 ISOgrk3 -->
167 {"\u03A1", "&Rho;"}, // greek capital letter rho, U+03A1 -->
168 // <!-- there is no Sigmaf, and no U+03A2 character either -->
169 {"\u03A3", "&Sigma;"}, // greek capital letter sigma,U+03A3 ISOgrk3 -->
170 {"\u03A4", "&Tau;"}, // greek capital letter tau, U+03A4 -->
171 {"\u03A5", "&Upsilon;"}, // greek capital letter upsilon,U+03A5 ISOgrk3 -->
172 {"\u03A6", "&Phi;"}, // greek capital letter phi,U+03A6 ISOgrk3 -->
173 {"\u03A7", "&Chi;"}, // greek capital letter chi, U+03A7 -->
174 {"\u03A8", "&Psi;"}, // greek capital letter psi,U+03A8 ISOgrk3 -->
175 {"\u03A9", "&Omega;"}, // greek capital letter omega,U+03A9 ISOgrk3 -->
176 {"\u03B1", "&alpha;"}, // greek small letter alpha,U+03B1 ISOgrk3 -->
177 {"\u03B2", "&beta;"}, // greek small letter beta, U+03B2 ISOgrk3 -->
178 {"\u03B3", "&gamma;"}, // greek small letter gamma,U+03B3 ISOgrk3 -->
179 {"\u03B4", "&delta;"}, // greek small letter delta,U+03B4 ISOgrk3 -->
180 {"\u03B5", "&epsilon;"}, // greek small letter epsilon,U+03B5 ISOgrk3 -->
181 {"\u03B6", "&zeta;"}, // greek small letter zeta, U+03B6 ISOgrk3 -->
182 {"\u03B7", "&eta;"}, // greek small letter eta, U+03B7 ISOgrk3 -->
183 {"\u03B8", "&theta;"}, // greek small letter theta,U+03B8 ISOgrk3 -->
184 {"\u03B9", "&iota;"}, // greek small letter iota, U+03B9 ISOgrk3 -->
185 {"\u03BA", "&kappa;"}, // greek small letter kappa,U+03BA ISOgrk3 -->
186 {"\u03BB", "&lambda;"}, // greek small letter lambda,U+03BB ISOgrk3 -->
187 {"\u03BC", "&mu;"}, // greek small letter mu, U+03BC ISOgrk3 -->
188 {"\u03BD", "&nu;"}, // greek small letter nu, U+03BD ISOgrk3 -->
189 {"\u03BE", "&xi;"}, // greek small letter xi, U+03BE ISOgrk3 -->
190 {"\u03BF", "&omicron;"}, // greek small letter omicron, U+03BF NEW -->
191 {"\u03C0", "&pi;"}, // greek small letter pi, U+03C0 ISOgrk3 -->
192 {"\u03C1", "&rho;"}, // greek small letter rho, U+03C1 ISOgrk3 -->
193 {"\u03C2", "&sigmaf;"}, // greek small letter final sigma,U+03C2 ISOgrk3 -->
194 {"\u03C3", "&sigma;"}, // greek small letter sigma,U+03C3 ISOgrk3 -->
195 {"\u03C4", "&tau;"}, // greek small letter tau, U+03C4 ISOgrk3 -->
196 {"\u03C5", "&upsilon;"}, // greek small letter upsilon,U+03C5 ISOgrk3 -->
197 {"\u03C6", "&phi;"}, // greek small letter phi, U+03C6 ISOgrk3 -->
198 {"\u03C7", "&chi;"}, // greek small letter chi, U+03C7 ISOgrk3 -->
199 {"\u03C8", "&psi;"}, // greek small letter psi, U+03C8 ISOgrk3 -->
200 {"\u03C9", "&omega;"}, // greek small letter omega,U+03C9 ISOgrk3 -->
201 {"\u03D1", "&thetasym;"}, // greek small letter theta symbol,U+03D1 NEW -->
202 {"\u03D2", "&upsih;"}, // greek upsilon with hook symbol,U+03D2 NEW -->
203 {"\u03D6", "&piv;"}, // greek pi symbol, U+03D6 ISOgrk3 -->
204 // <!-- General Punctuation -->
205 {"\u2022", "&bull;"}, // bullet = black small circle,U+2022 ISOpub -->
206 // <!-- bullet is NOT the same as bullet operator, U+2219 -->
207 {"\u2026", "&hellip;"}, // horizontal ellipsis = three dot leader,U+2026 ISOpub -->
208 {"\u2032", "&prime;"}, // prime = minutes = feet, U+2032 ISOtech -->
209 {"\u2033", "&Prime;"}, // double prime = seconds = inches,U+2033 ISOtech -->
210 {"\u203E", "&oline;"}, // overline = spacing overscore,U+203E NEW -->
211 {"\u2044", "&frasl;"}, // fraction slash, U+2044 NEW -->
212 // <!-- Letterlike Symbols -->
213 {"\u2118", "&weierp;"}, // script capital P = power set= Weierstrass p, U+2118 ISOamso -->
214 {"\u2111", "&image;"}, // blackletter capital I = imaginary part,U+2111 ISOamso -->
215 {"\u211C", "&real;"}, // blackletter capital R = real part symbol,U+211C ISOamso -->
216 {"\u2122", "&trade;"}, // trade mark sign, U+2122 ISOnum -->
217 {"\u2135", "&alefsym;"}, // alef symbol = first transfinite cardinal,U+2135 NEW -->
218 // <!-- alef symbol is NOT the same as hebrew letter alef,U+05D0 although the
219 // same glyph could be used to depict both characters -->
220 // <!-- Arrows -->
221 {"\u2190", "&larr;"}, // leftwards arrow, U+2190 ISOnum -->
222 {"\u2191", "&uarr;"}, // upwards arrow, U+2191 ISOnum-->
223 {"\u2192", "&rarr;"}, // rightwards arrow, U+2192 ISOnum -->
224 {"\u2193", "&darr;"}, // downwards arrow, U+2193 ISOnum -->
225 {"\u2194", "&harr;"}, // left right arrow, U+2194 ISOamsa -->
226 {"\u21B5", "&crarr;"}, // downwards arrow with corner leftwards= carriage return, U+21B5 NEW -->
227 {"\u21D0", "&lArr;"}, // leftwards double arrow, U+21D0 ISOtech -->
228 // <!-- ISO 10646 does not say that lArr is the same as the 'is implied by'
229 // arrow but also does not have any other character for that function.
230 // So ? lArr canbe used for 'is implied by' as ISOtech suggests -->
231 {"\u21D1", "&uArr;"}, // upwards double arrow, U+21D1 ISOamsa -->
232 {"\u21D2", "&rArr;"}, // rightwards double arrow,U+21D2 ISOtech -->
233 // <!-- ISO 10646 does not say this is the 'implies' character but does not
234 // have another character with this function so ?rArr can be used for
235 // 'implies' as ISOtech suggests -->
236 {"\u21D3", "&dArr;"}, // downwards double arrow, U+21D3 ISOamsa -->
237 {"\u21D4", "&hArr;"}, // left right double arrow,U+21D4 ISOamsa -->
238 // <!-- Mathematical Operators -->
239 {"\u2200", "&forall;"}, // for all, U+2200 ISOtech -->
240 {"\u2202", "&part;"}, // partial differential, U+2202 ISOtech -->
241 {"\u2203", "&exist;"}, // there exists, U+2203 ISOtech -->
242 {"\u2205", "&empty;"}, // empty set = null set = diameter,U+2205 ISOamso -->
243 {"\u2207", "&nabla;"}, // nabla = backward difference,U+2207 ISOtech -->
244 {"\u2208", "&isin;"}, // element of, U+2208 ISOtech -->
245 {"\u2209", "&notin;"}, // not an element of, U+2209 ISOtech -->
246 {"\u220B", "&ni;"}, // contains as member, U+220B ISOtech -->
247 // <!-- should there be a more memorable name than 'ni'? -->
248 {"\u220F", "&prod;"}, // n-ary product = product sign,U+220F ISOamsb -->
249 // <!-- prod is NOT the same character as U+03A0 'greek capital letter pi'
250 // though the same glyph might be used for both -->
251 {"\u2211", "&sum;"}, // n-ary summation, U+2211 ISOamsb -->
252 // <!-- sum is NOT the same character as U+03A3 'greek capital letter sigma'
253 // though the same glyph might be used for both -->
254 {"\u2212", "&minus;"}, // minus sign, U+2212 ISOtech -->
255 {"\u2217", "&lowast;"}, // asterisk operator, U+2217 ISOtech -->
256 {"\u221A", "&radic;"}, // square root = radical sign,U+221A ISOtech -->
257 {"\u221D", "&prop;"}, // proportional to, U+221D ISOtech -->
258 {"\u221E", "&infin;"}, // infinity, U+221E ISOtech -->
259 {"\u2220", "&ang;"}, // angle, U+2220 ISOamso -->
260 {"\u2227", "&and;"}, // logical and = wedge, U+2227 ISOtech -->
261 {"\u2228", "&or;"}, // logical or = vee, U+2228 ISOtech -->
262 {"\u2229", "&cap;"}, // intersection = cap, U+2229 ISOtech -->
263 {"\u222A", "&cup;"}, // union = cup, U+222A ISOtech -->
264 {"\u222B", "&int;"}, // integral, U+222B ISOtech -->
265 {"\u2234", "&there4;"}, // therefore, U+2234 ISOtech -->
266 {"\u223C", "&sim;"}, // tilde operator = varies with = similar to,U+223C ISOtech -->
267 // <!-- tilde operator is NOT the same character as the tilde, U+007E,although
268 // the same glyph might be used to represent both -->
269 {"\u2245", "&cong;"}, // approximately equal to, U+2245 ISOtech -->
270 {"\u2248", "&asymp;"}, // almost equal to = asymptotic to,U+2248 ISOamsr -->
271 {"\u2260", "&ne;"}, // not equal to, U+2260 ISOtech -->
272 {"\u2261", "&equiv;"}, // identical to, U+2261 ISOtech -->
273 {"\u2264", "&le;"}, // less-than or equal to, U+2264 ISOtech -->
274 {"\u2265", "&ge;"}, // greater-than or equal to,U+2265 ISOtech -->
275 {"\u2282", "&sub;"}, // subset of, U+2282 ISOtech -->
276 {"\u2283", "&sup;"}, // superset of, U+2283 ISOtech -->
277 // <!-- note that nsup, 'not a superset of, U+2283' is not covered by the
278 // Symbol font encoding and is not included. Should it be, for symmetry?
279 // It is in ISOamsn --> <!ENTITY nsub", "8836"},
280 // not a subset of, U+2284 ISOamsn -->
281 {"\u2286", "&sube;"}, // subset of or equal to, U+2286 ISOtech -->
282 {"\u2287", "&supe;"}, // superset of or equal to,U+2287 ISOtech -->
283 {"\u2295", "&oplus;"}, // circled plus = direct sum,U+2295 ISOamsb -->
284 {"\u2297", "&otimes;"}, // circled times = vector product,U+2297 ISOamsb -->
285 {"\u22A5", "&perp;"}, // up tack = orthogonal to = perpendicular,U+22A5 ISOtech -->
286 {"\u22C5", "&sdot;"}, // dot operator, U+22C5 ISOamsb -->
287 // <!-- dot operator is NOT the same character as U+00B7 middle dot -->
288 // <!-- Miscellaneous Technical -->
289 {"\u2308", "&lceil;"}, // left ceiling = apl upstile,U+2308 ISOamsc -->
290 {"\u2309", "&rceil;"}, // right ceiling, U+2309 ISOamsc -->
291 {"\u230A", "&lfloor;"}, // left floor = apl downstile,U+230A ISOamsc -->
292 {"\u230B", "&rfloor;"}, // right floor, U+230B ISOamsc -->
293 {"\u2329", "&lang;"}, // left-pointing angle bracket = bra,U+2329 ISOtech -->
294 // <!-- lang is NOT the same character as U+003C 'less than' or U+2039 'single left-pointing angle quotation
295 // mark' -->
296 {"\u232A", "&rang;"}, // right-pointing angle bracket = ket,U+232A ISOtech -->
297 // <!-- rang is NOT the same character as U+003E 'greater than' or U+203A
298 // 'single right-pointing angle quotation mark' -->
299 // <!-- Geometric Shapes -->
300 {"\u25CA", "&loz;"}, // lozenge, U+25CA ISOpub -->
301 // <!-- Miscellaneous Symbols -->
302 {"\u2660", "&spades;"}, // black spade suit, U+2660 ISOpub -->
303 // <!-- black here seems to mean filled as opposed to hollow -->
304 {"\u2663", "&clubs;"}, // black club suit = shamrock,U+2663 ISOpub -->
305 {"\u2665", "&hearts;"}, // black heart suit = valentine,U+2665 ISOpub -->
306 {"\u2666", "&diams;"}, // black diamond suit, U+2666 ISOpub -->
307
308 // <!-- Latin Extended-A -->
309 {"\u0152", "&OElig;"}, // -- latin capital ligature OE,U+0152 ISOlat2 -->
310 {"\u0153", "&oelig;"}, // -- latin small ligature oe, U+0153 ISOlat2 -->
311 // <!-- ligature is a misnomer, this is a separate character in some languages -->
312 {"\u0160", "&Scaron;"}, // -- latin capital letter S with caron,U+0160 ISOlat2 -->
313 {"\u0161", "&scaron;"}, // -- latin small letter s with caron,U+0161 ISOlat2 -->
314 {"\u0178", "&Yuml;"}, // -- latin capital letter Y with diaeresis,U+0178 ISOlat2 -->
315 // <!-- Spacing Modifier Letters -->
316 {"\u02C6", "&circ;"}, // -- modifier letter circumflex accent,U+02C6 ISOpub -->
317 {"\u02DC", "&tilde;"}, // small tilde, U+02DC ISOdia -->
318 // <!-- General Punctuation -->
319 {"\u2002", "&ensp;"}, // en space, U+2002 ISOpub -->
320 {"\u2003", "&emsp;"}, // em space, U+2003 ISOpub -->
321 {"\u2009", "&thinsp;"}, // thin space, U+2009 ISOpub -->
322 {"\u200C", "&zwnj;"}, // zero width non-joiner,U+200C NEW RFC 2070 -->
323 {"\u200D", "&zwj;"}, // zero width joiner, U+200D NEW RFC 2070 -->
324 {"\u200E", "&lrm;"}, // left-to-right mark, U+200E NEW RFC 2070 -->
325 {"\u200F", "&rlm;"}, // right-to-left mark, U+200F NEW RFC 2070 -->
326 {"\u2013", "&ndash;"}, // en dash, U+2013 ISOpub -->
327 {"\u2014", "&mdash;"}, // em dash, U+2014 ISOpub -->
328 {"\u2018", "&lsquo;"}, // left single quotation mark,U+2018 ISOnum -->
329 {"\u2019", "&rsquo;"}, // right single quotation mark,U+2019 ISOnum -->
330 {"\u201A", "&sbquo;"}, // single low-9 quotation mark, U+201A NEW -->
331 {"\u201C", "&ldquo;"}, // left double quotation mark,U+201C ISOnum -->
332 {"\u201D", "&rdquo;"}, // right double quotation mark,U+201D ISOnum -->
333 {"\u201E", "&bdquo;"}, // double low-9 quotation mark, U+201E NEW -->
334 {"\u2020", "&dagger;"}, // dagger, U+2020 ISOpub -->
335 {"\u2021", "&Dagger;"}, // double dagger, U+2021 ISOpub -->
336 {"\u2030", "&permil;"}, // per mille sign, U+2030 ISOtech -->
337 {"\u2039", "&lsaquo;"}, // single left-pointing angle quotation mark,U+2039 ISO proposed -->
338 // <!-- lsaquo is proposed but not yet ISO standardized -->
339 {"\u203A", "&rsaquo;"}, // single right-pointing angle quotation mark,U+203A ISO proposed -->
340 // <!-- rsaquo is proposed but not yet ISO standardized -->
341 {"\u20AC", "&euro;"}, // -- euro sign, U+20AC NEW -->
342 };
343
344 /**
345 * Reverse of {@link #HTML40_EXTENDED_ESCAPE()} for unescaping purposes.
346 * @return the mapping table
347 */
348 public static String[][] HTML40_EXTENDED_UNESCAPE() { return HTML40_EXTENDED_UNESCAPE.clone(); }
349 private static final String[][] HTML40_EXTENDED_UNESCAPE = invert(HTML40_EXTENDED_ESCAPE);
350
351 /**
352 * Mapping to escape the basic XML and HTML character entities.
353 *
354 * Namely: {@code " & < >}
355 * @return the mapping table
356 */
357 public static String[][] BASIC_ESCAPE() { return BASIC_ESCAPE.clone(); }
358 private static final String[][] BASIC_ESCAPE = {
359 {"\"", "&quot;"}, // " - double-quote
360 {"&", "&amp;"}, // & - ampersand
361 {"<", "&lt;"}, // < - less-than
362 {">", "&gt;"}, // > - greater-than
363 };
364
365 /**
366 * Reverse of {@link #BASIC_ESCAPE()} for unescaping purposes.
367 * @return the mapping table
368 */
369 public static String[][] BASIC_UNESCAPE() { return BASIC_UNESCAPE.clone(); }
370 private static final String[][] BASIC_UNESCAPE = invert(BASIC_ESCAPE);
371
372 /**
373 * Mapping to escape the apostrophe character to its XML character entity.
374 * @return the mapping table
375 */
376 public static String[][] APOS_ESCAPE() { return APOS_ESCAPE.clone(); }
377 private static final String[][] APOS_ESCAPE = {
378 {"'", "&apos;"}, // XML apostrophe
379 };
380
381 /**
382 * Reverse of {@link #APOS_ESCAPE()} for unescaping purposes.
383 * @return the mapping table
384 */
385 public static String[][] APOS_UNESCAPE() { return APOS_UNESCAPE.clone(); }
386 private static final String[][] APOS_UNESCAPE = invert(APOS_ESCAPE);
387
388 /**
389 * Mapping to escape the Java control characters.
390 *
391 * Namely: {@code \b \n \t \f \r}
392 * @return the mapping table
393 */
394 public static String[][] JAVA_CTRL_CHARS_ESCAPE() { return JAVA_CTRL_CHARS_ESCAPE.clone(); }
395 private static final String[][] JAVA_CTRL_CHARS_ESCAPE = {
396 {"\b", "\\b"},
397 {"\n", "\\n"},
398 {"\t", "\\t"},
399 {"\f", "\\f"},
400 {"\r", "\\r"}
401 };
402
403 /**
404 * Reverse of {@link #JAVA_CTRL_CHARS_ESCAPE()} for unescaping purposes.
405 * @return the mapping table
406 */
407 public static String[][] JAVA_CTRL_CHARS_UNESCAPE() { return JAVA_CTRL_CHARS_UNESCAPE.clone(); }
408 private static final String[][] JAVA_CTRL_CHARS_UNESCAPE = invert(JAVA_CTRL_CHARS_ESCAPE);
409
410 /**
411 * Used to invert an escape array into an unescape array
412 * @param array String[][] to be inverted
413 * @return String[][] inverted array
414 */
415 public static String[][] invert(String[][] array) {
416 String[][] newarray = new String[array.length][2];
417 for(int i = 0; i<array.length; i++) {
418 newarray[i][0] = array[i][1];
419 newarray[i][1] = array[i][0];
420 }
421 return newarray;
422 }
423
424 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text.translate;
17
18 import java.io.IOException;
19 import java.io.Writer;
20 import java.util.HashMap;
21
22 /**
23 * Translates a value using a lookup table.
24 *
25 * @since 3.0
26 * @version $Id: LookupTranslator.java 1091096 2011-04-11 15:07:29Z mbenson $
27 */
28 public class LookupTranslator extends CharSequenceTranslator {
29
30 private final HashMap<CharSequence, CharSequence> lookupMap;
31 private final int shortest;
32 private final int longest;
33
34 /**
35 * Define the lookup table to be used in translation
36 *
37 * @param lookup CharSequence[][] table of size [*][2]
38 */
39 public LookupTranslator(CharSequence[]... lookup) {
40 lookupMap = new HashMap<CharSequence, CharSequence>();
41 int _shortest = Integer.MAX_VALUE;
42 int _longest = 0;
43 if (lookup != null) {
44 for (CharSequence[] seq : lookup) {
45 this.lookupMap.put(seq[0], seq[1]);
46 int sz = seq[0].length();
47 if (sz < _shortest) {
48 _shortest = sz;
49 }
50 if (sz > _longest) {
51 _longest = sz;
52 }
53 }
54 }
55 shortest = _shortest;
56 longest = _longest;
57 }
58
59 /**
60 * {@inheritDoc}
61 */
62 @Override
63 public int translate(CharSequence input, int index, Writer out) throws IOException {
64 int max = longest;
65 if (index + longest > input.length()) {
66 max = input.length() - index;
67 }
68 // descend so as to get a greedy algorithm
69 for (int i = max; i >= shortest; i--) {
70 CharSequence subSeq = input.subSequence(index, index + i);
71 CharSequence result = lookupMap.get(subSeq);
72 if (result != null) {
73 out.write(result.toString());
74 return i;
75 }
76 }
77 return 0;
78 }
79 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text.translate;
17
18 import java.io.IOException;
19 import java.io.Writer;
20
21 /**
22 * Translates codepoints to their XML numeric entity escaped value.
23 *
24 * @since 3.0
25 * @version $Id: NumericEntityEscaper.java 1142151 2011-07-02 04:06:23Z bayard $
26 */
27 public class NumericEntityEscaper extends CodePointTranslator {
28
29 private final int below;
30 private final int above;
31 private final boolean between;
32
33 /**
34 * <p>Constructs a <code>NumericEntityEscaper</code> for the specified range. This is
35 * the underlying method for the other constructors/builders. The <code>below</code>
36 * and <code>above</code> boundaries are inclusive when <code>between</code> is
37 * <code>true</code> and exclusive when it is <code>false</code>. </p>
38 *
39 * @param below int value representing the lowest codepoint boundary
40 * @param above int value representing the highest codepoint boundary
41 * @param between whether to escape between the boundaries or outside them
42 */
43 private NumericEntityEscaper(int below, int above, boolean between) {
44 this.below = below;
45 this.above = above;
46 this.between = between;
47 }
48
49 /**
50 * <p>Constructs a <code>NumericEntityEscaper</code> for all characters. </p>
51 */
52 public NumericEntityEscaper() {
53 this(0, Integer.MAX_VALUE, true);
54 }
55
56 /**
57 * <p>Constructs a <code>NumericEntityEscaper</code> below the specified value (exclusive). </p>
58 *
59 * @param codepoint below which to escape
60 * @return the newly created {@code NumericEntityEscaper} instance
61 */
62 public static NumericEntityEscaper below(int codepoint) {
63 return outsideOf(codepoint, Integer.MAX_VALUE);
64 }
65
66 /**
67 * <p>Constructs a <code>NumericEntityEscaper</code> above the specified value (exclusive). </p>
68 *
69 * @param codepoint above which to escape
70 * @return the newly created {@code NumericEntityEscaper} instance
71 */
72 public static NumericEntityEscaper above(int codepoint) {
73 return outsideOf(0, codepoint);
74 }
75
76 /**
77 * <p>Constructs a <code>NumericEntityEscaper</code> between the specified values (inclusive). </p>
78 *
79 * @param codepointLow above which to escape
80 * @param codepointHigh below which to escape
81 * @return the newly created {@code NumericEntityEscaper} instance
82 */
83 public static NumericEntityEscaper between(int codepointLow, int codepointHigh) {
84 return new NumericEntityEscaper(codepointLow, codepointHigh, true);
85 }
86
87 /**
88 * <p>Constructs a <code>NumericEntityEscaper</code> outside of the specified values (exclusive). </p>
89 *
90 * @param codepointLow below which to escape
91 * @param codepointHigh above which to escape
92 * @return the newly created {@code NumericEntityEscaper} instance
93 */
94 public static NumericEntityEscaper outsideOf(int codepointLow, int codepointHigh) {
95 return new NumericEntityEscaper(codepointLow, codepointHigh, false);
96 }
97
98 /**
99 * {@inheritDoc}
100 */
101 @Override
102 public boolean translate(int codepoint, Writer out) throws IOException {
103 if(between) {
104 if (codepoint < below || codepoint > above) {
105 return false;
106 }
107 } else {
108 if (codepoint >= below && codepoint <= above) {
109 return false;
110 }
111 }
112
113 out.write("&#");
114 out.write(Integer.toString(codepoint, 10));
115 out.write(';');
116 return true;
117 }
118 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text.translate;
17
18 import java.io.IOException;
19 import java.io.Writer;
20 import java.util.Arrays;
21 import java.util.EnumSet;
22
23 /**
24 * Translate XML numeric entities of the form &#[xX]?\d+;? to
25 * the specific codepoint.
26 *
27 * Note that the semi-colon is optional.
28 *
29 * @since 3.0
30 * @version $Id: NumericEntityUnescaper.java 1143643 2011-07-07 03:47:17Z bayard $
31 */
32 public class NumericEntityUnescaper extends CharSequenceTranslator {
33
34 public static enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon }
35
36 // TODO?: Create an OptionsSet class to hide some of the conditional logic below
37 private final EnumSet<OPTION> options;
38
39 /**
40 * Create a UnicodeUnescaper.
41 *
42 * The constructor takes a list of options, only one type of which is currently
43 * available (whether to allow, error or ignore the semi-colon on the end of a
44 * numeric entity to being missing).
45 *
46 * For example, to support numeric entities without a ';':
47 * new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.semiColonOptional)
48 * and to throw an IllegalArgumentException when they're missing:
49 * new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.errorIfNoSemiColon)
50 *
51 * Note that the default behaviour is to ignore them.
52 *
53 * @param options to apply to this unescaper
54 */
55 public NumericEntityUnescaper(OPTION... options) {
56 if(options.length > 0) {
57 this.options = EnumSet.copyOf(Arrays.asList(options));
58 } else {
59 this.options = EnumSet.copyOf(Arrays.asList(new OPTION[] { OPTION.semiColonRequired }));
60 }
61 }
62
63 /**
64 * Whether the passed in option is currently set.
65 *
66 * @param option to check state of
67 * @return whether the option is set
68 */
69 public boolean isSet(OPTION option) {
70 return (options == null) ? false : options.contains(option);
71 }
72
73 /**
74 * {@inheritDoc}
75 */
76 @Override
77 public int translate(CharSequence input, int index, Writer out) throws IOException {
78 int seqEnd = input.length();
79 // Uses -2 to ensure there is something after the &#
80 if(input.charAt(index) == '&' && index < seqEnd - 2 && input.charAt(index + 1) == '#') {
81 int start = index + 2;
82 boolean isHex = false;
83
84 char firstChar = input.charAt(start);
85 if(firstChar == 'x' || firstChar == 'X') {
86 start++;
87 isHex = true;
88
89 // Check there's more than just an x after the &#
90 if(start == seqEnd) {
91 return 0;
92 }
93 }
94
95 int end = start;
96 // Note that this supports character codes without a ; on the end
97 while(end < seqEnd && ( (input.charAt(end) >= '0' && input.charAt(end) <= '9') ||
98 (input.charAt(end) >= 'a' && input.charAt(end) <= 'f') ||
99 (input.charAt(end) >= 'A' && input.charAt(end) <= 'F') ) )
100 {
101 end++;
102 }
103
104 boolean semiNext = (end != seqEnd) && (input.charAt(end) == ';');
105
106 if(!semiNext) {
107 if(isSet(OPTION.semiColonRequired)) {
108 return 0;
109 } else
110 if(isSet(OPTION.errorIfNoSemiColon)) {
111 throw new IllegalArgumentException("Semi-colon required at end of numeric entity");
112 }
113 }
114
115 int entityValue;
116 try {
117 if(isHex) {
118 entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 16);
119 } else {
120 entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 10);
121 }
122 } catch(NumberFormatException nfe) {
123 return 0;
124 }
125
126 if(entityValue > 0xFFFF) {
127 char[] chrs = Character.toChars(entityValue);
128 out.write(chrs[0]);
129 out.write(chrs[1]);
130 } else {
131 out.write(entityValue);
132 }
133
134 return 2 + (end - start) + (isHex ? 1 : 0) + (semiNext ? 1 : 0);
135 }
136 return 0;
137 }
138 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text.translate;
17
18 import java.io.IOException;
19 import java.io.Writer;
20
21 /**
22 * Translate escaped octal Strings back to their octal values.
23 *
24 * For example, "\45" should go back to being the specific value (a %).
25 *
26 * Note that this currently only supports the viable range of octal for Java; namely
27 * 1 to 377. This is both because parsing Java is the main use case and Integer.parseInt
28 * throws an exception when values are larger than octal 377.
29 *
30 * @since 3.0
31 * @version $Id: OctalUnescaper.java 967237 2010-07-23 20:08:57Z mbenson $
32 */
33 public class OctalUnescaper extends CharSequenceTranslator {
34
35 private static int OCTAL_MAX = 377;
36
37 /**
38 * {@inheritDoc}
39 */
40 @Override
41 public int translate(CharSequence input, int index, Writer out) throws IOException {
42 if(input.charAt(index) == '\\' && index < (input.length() - 1) && Character.isDigit(input.charAt(index + 1)) ) {
43 int start = index + 1;
44
45 int end = index + 2;
46 while ( end < input.length() && Character.isDigit(input.charAt(end)) ) {
47 end++;
48 if ( Integer.parseInt(input.subSequence(start, end).toString(), 10) > OCTAL_MAX) {
49 end--; // rollback
50 break;
51 }
52 }
53
54 out.write( Integer.parseInt(input.subSequence(start, end).toString(), 8) );
55 return 1 + end - start;
56 }
57 return 0;
58 }
59 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text.translate;
17
18 import java.io.IOException;
19 import java.io.Writer;
20
21 /**
22 * Translates codepoints to their Unicode escaped value.
23 *
24 * @since 3.0
25 * @version $Id: UnicodeEscaper.java 1148520 2011-07-19 20:53:23Z ggregory $
26 */
27 public class UnicodeEscaper extends CodePointTranslator {
28
29 private final int below;
30 private final int above;
31 private final boolean between;
32
33 /**
34 * <p>Constructs a <code>UnicodeEscaper</code> for all characters. </p>
35 */
36 public UnicodeEscaper(){
37 this(0, Integer.MAX_VALUE, true);
38 }
39
40 /**
41 * <p>Constructs a <code>UnicodeEscaper</code> for the specified range. This is
42 * the underlying method for the other constructors/builders. The <code>below</code>
43 * and <code>above</code> boundaries are inclusive when <code>between</code> is
44 * <code>true</code> and exclusive when it is <code>false</code>. </p>
45 *
46 * @param below int value representing the lowest codepoint boundary
47 * @param above int value representing the highest codepoint boundary
48 * @param between whether to escape between the boundaries or outside them
49 */
50 private UnicodeEscaper(int below, int above, boolean between) {
51 this.below = below;
52 this.above = above;
53 this.between = between;
54 }
55
56 /**
57 * <p>Constructs a <code>UnicodeEscaper</code> below the specified value (exclusive). </p>
58 *
59 * @param codepoint below which to escape
60 * @return the newly created {@code UnicodeEscaper} instance
61 */
62 public static UnicodeEscaper below(int codepoint) {
63 return outsideOf(codepoint, Integer.MAX_VALUE);
64 }
65
66 /**
67 * <p>Constructs a <code>UnicodeEscaper</code> above the specified value (exclusive). </p>
68 *
69 * @param codepoint above which to escape
70 * @return the newly created {@code UnicodeEscaper} instance
71 */
72 public static UnicodeEscaper above(int codepoint) {
73 return outsideOf(0, codepoint);
74 }
75
76 /**
77 * <p>Constructs a <code>UnicodeEscaper</code> outside of the specified values (exclusive). </p>
78 *
79 * @param codepointLow below which to escape
80 * @param codepointHigh above which to escape
81 * @return the newly created {@code UnicodeEscaper} instance
82 */
83 public static UnicodeEscaper outsideOf(int codepointLow, int codepointHigh) {
84 return new UnicodeEscaper(codepointLow, codepointHigh, false);
85 }
86
87 /**
88 * <p>Constructs a <code>UnicodeEscaper</code> between the specified values (inclusive). </p>
89 *
90 * @param codepointLow above which to escape
91 * @param codepointHigh below which to escape
92 * @return the newly created {@code UnicodeEscaper} instance
93 */
94 public static UnicodeEscaper between(int codepointLow, int codepointHigh) {
95 return new UnicodeEscaper(codepointLow, codepointHigh, true);
96 }
97
98 /**
99 * {@inheritDoc}
100 */
101 @Override
102 public boolean translate(int codepoint, Writer out) throws IOException {
103 if(between) {
104 if (codepoint < below || codepoint > above) {
105 return false;
106 }
107 } else {
108 if (codepoint >= below && codepoint <= above) {
109 return false;
110 }
111 }
112
113 // TODO: Handle potential + sign per various Unicode escape implementations
114 if (codepoint > 0xffff) {
115 // TODO: Figure out what to do. Output as two Unicodes?
116 // Does this make this a Java-specific output class?
117 out.write("\\u" + hex(codepoint));
118 } else if (codepoint > 0xfff) {
119 out.write("\\u" + hex(codepoint));
120 } else if (codepoint > 0xff) {
121 out.write("\\u0" + hex(codepoint));
122 } else if (codepoint > 0xf) {
123 out.write("\\u00" + hex(codepoint));
124 } else {
125 out.write("\\u000" + hex(codepoint));
126 }
127 return true;
128 }
129 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text.translate;
17
18 import java.io.IOException;
19 import java.io.Writer;
20
21 /**
22 * Translates escaped Unicode values of the form \\u+\d\d\d\d back to
23 * Unicode. It supports multiple 'u' characters and will work with or
24 * without the +.
25 *
26 * @since 3.0
27 * @version $Id: UnicodeUnescaper.java 1153241 2011-08-02 18:49:52Z ggregory $
28 */
29 public class UnicodeUnescaper extends CharSequenceTranslator {
30
31 /**
32 * {@inheritDoc}
33 */
34 @Override
35 public int translate(CharSequence input, int index, Writer out) throws IOException {
36 if (input.charAt(index) == '\\' && (index + 1 < input.length()) && input.charAt(index + 1) == 'u') {
37 // consume optional additional 'u' chars
38 int i = 2;
39 while ((index + i < input.length()) && input.charAt(index + i) == 'u') {
40 i++;
41 }
42
43 if ((index + i < input.length()) && (input.charAt(index + i) == '+')) {
44 i++;
45 }
46
47 if ((index + i + 4 <= input.length())) {
48 // Get 4 hex digits
49 CharSequence unicode = input.subSequence(index + i, index + i + 4);
50
51 try {
52 int value = Integer.parseInt(unicode.toString(), 16);
53 out.write((char) value);
54 } catch (NumberFormatException nfe) {
55 throw new IllegalArgumentException("Unable to parse unicode value: " + unicode, nfe);
56 }
57 return i + 4;
58 } else {
59 throw new IllegalArgumentException("Less than 4 hex digits in unicode value: '" + input.subSequence(index, input.length())
60 + "' due to end of CharSequence");
61 }
62 }
63 return 0;
64 }
65 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 <p>
19 An API for creating text translation routines from a set of smaller
20 building blocks. Initially created to make it possible for the user to
21 customize the rules in the StringEscapeUtils class.
22 </p>
23 @since 3.0
24 <p>These classes are immutable, and therefore thread-safe.</p>
25 </body>
26 </html>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import java.util.Calendar;
19 import java.util.Date;
20 import java.util.Locale;
21 import java.util.TimeZone;
22
23 /**
24 * <p>Date and time formatting utilities and constants.</p>
25 *
26 * <p>Formatting is performed using the thread-safe
27 * {@link org.apache.commons.lang3.time.FastDateFormat} class.</p>
28 *
29 * @since 2.0
30 * @version $Id: DateFormatUtils.java 1088899 2011-04-05 05:31:27Z bayard $
31 */
32 public class DateFormatUtils {
33
34 /**
35 * The UTC time zone (often referred to as GMT).
36 * This is private as it is mutable.
37 */
38 private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("GMT");
39 /**
40 * ISO8601 formatter for date-time without time zone.
41 * The format used is <tt>yyyy-MM-dd'T'HH:mm:ss</tt>.
42 */
43 public static final FastDateFormat ISO_DATETIME_FORMAT
44 = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
45
46 /**
47 * ISO8601 formatter for date-time with time zone.
48 * The format used is <tt>yyyy-MM-dd'T'HH:mm:ssZZ</tt>.
49 */
50 public static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT
51 = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ");
52
53 /**
54 * ISO8601 formatter for date without time zone.
55 * The format used is <tt>yyyy-MM-dd</tt>.
56 */
57 public static final FastDateFormat ISO_DATE_FORMAT
58 = FastDateFormat.getInstance("yyyy-MM-dd");
59
60 /**
61 * ISO8601-like formatter for date with time zone.
62 * The format used is <tt>yyyy-MM-ddZZ</tt>.
63 * This pattern does not comply with the formal ISO8601 specification
64 * as the standard does not allow a time zone without a time.
65 */
66 public static final FastDateFormat ISO_DATE_TIME_ZONE_FORMAT
67 = FastDateFormat.getInstance("yyyy-MM-ddZZ");
68
69 /**
70 * ISO8601 formatter for time without time zone.
71 * The format used is <tt>'T'HH:mm:ss</tt>.
72 */
73 public static final FastDateFormat ISO_TIME_FORMAT
74 = FastDateFormat.getInstance("'T'HH:mm:ss");
75
76 /**
77 * ISO8601 formatter for time with time zone.
78 * The format used is <tt>'T'HH:mm:ssZZ</tt>.
79 */
80 public static final FastDateFormat ISO_TIME_TIME_ZONE_FORMAT
81 = FastDateFormat.getInstance("'T'HH:mm:ssZZ");
82
83 /**
84 * ISO8601-like formatter for time without time zone.
85 * The format used is <tt>HH:mm:ss</tt>.
86 * This pattern does not comply with the formal ISO8601 specification
87 * as the standard requires the 'T' prefix for times.
88 */
89 public static final FastDateFormat ISO_TIME_NO_T_FORMAT
90 = FastDateFormat.getInstance("HH:mm:ss");
91
92 /**
93 * ISO8601-like formatter for time with time zone.
94 * The format used is <tt>HH:mm:ssZZ</tt>.
95 * This pattern does not comply with the formal ISO8601 specification
96 * as the standard requires the 'T' prefix for times.
97 */
98 public static final FastDateFormat ISO_TIME_NO_T_TIME_ZONE_FORMAT
99 = FastDateFormat.getInstance("HH:mm:ssZZ");
100
101 /**
102 * SMTP (and probably other) date headers.
103 * The format used is <tt>EEE, dd MMM yyyy HH:mm:ss Z</tt> in US locale.
104 */
105 public static final FastDateFormat SMTP_DATETIME_FORMAT
106 = FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
107
108 //-----------------------------------------------------------------------
109 /**
110 * <p>DateFormatUtils instances should NOT be constructed in standard programming.</p>
111 *
112 * <p>This constructor is public to permit tools that require a JavaBean instance
113 * to operate.</p>
114 */
115 public DateFormatUtils() {
116 super();
117 }
118
119 /**
120 * <p>Formats a date/time into a specific pattern using the UTC time zone.</p>
121 *
122 * @param millis the date to format expressed in milliseconds
123 * @param pattern the pattern to use to format the date, not null
124 * @return the formatted date
125 */
126 public static String formatUTC(long millis, String pattern) {
127 return format(new Date(millis), pattern, UTC_TIME_ZONE, null);
128 }
129
130 /**
131 * <p>Formats a date/time into a specific pattern using the UTC time zone.</p>
132 *
133 * @param date the date to format, not null
134 * @param pattern the pattern to use to format the date, not null
135 * @return the formatted date
136 */
137 public static String formatUTC(Date date, String pattern) {
138 return format(date, pattern, UTC_TIME_ZONE, null);
139 }
140
141 /**
142 * <p>Formats a date/time into a specific pattern using the UTC time zone.</p>
143 *
144 * @param millis the date to format expressed in milliseconds
145 * @param pattern the pattern to use to format the date, not null
146 * @param locale the locale to use, may be <code>null</code>
147 * @return the formatted date
148 */
149 public static String formatUTC(long millis, String pattern, Locale locale) {
150 return format(new Date(millis), pattern, UTC_TIME_ZONE, locale);
151 }
152
153 /**
154 * <p>Formats a date/time into a specific pattern using the UTC time zone.</p>
155 *
156 * @param date the date to format, not null
157 * @param pattern the pattern to use to format the date, not null
158 * @param locale the locale to use, may be <code>null</code>
159 * @return the formatted date
160 */
161 public static String formatUTC(Date date, String pattern, Locale locale) {
162 return format(date, pattern, UTC_TIME_ZONE, locale);
163 }
164
165 /**
166 * <p>Formats a date/time into a specific pattern.</p>
167 *
168 * @param millis the date to format expressed in milliseconds
169 * @param pattern the pattern to use to format the date, not null
170 * @return the formatted date
171 */
172 public static String format(long millis, String pattern) {
173 return format(new Date(millis), pattern, null, null);
174 }
175
176 /**
177 * <p>Formats a date/time into a specific pattern.</p>
178 *
179 * @param date the date to format, not null
180 * @param pattern the pattern to use to format the date, not null
181 * @return the formatted date
182 */
183 public static String format(Date date, String pattern) {
184 return format(date, pattern, null, null);
185 }
186
187 /**
188 * <p>Formats a calendar into a specific pattern.</p>
189 *
190 * @param calendar the calendar to format, not null
191 * @param pattern the pattern to use to format the calendar, not null
192 * @return the formatted calendar
193 * @see FastDateFormat#format(Calendar)
194 * @since 2.4
195 */
196 public static String format(Calendar calendar, String pattern) {
197 return format(calendar, pattern, null, null);
198 }
199
200 /**
201 * <p>Formats a date/time into a specific pattern in a time zone.</p>
202 *
203 * @param millis the time expressed in milliseconds
204 * @param pattern the pattern to use to format the date, not null
205 * @param timeZone the time zone to use, may be <code>null</code>
206 * @return the formatted date
207 */
208 public static String format(long millis, String pattern, TimeZone timeZone) {
209 return format(new Date(millis), pattern, timeZone, null);
210 }
211
212 /**
213 * <p>Formats a date/time into a specific pattern in a time zone.</p>
214 *
215 * @param date the date to format, not null
216 * @param pattern the pattern to use to format the date, not null
217 * @param timeZone the time zone to use, may be <code>null</code>
218 * @return the formatted date
219 */
220 public static String format(Date date, String pattern, TimeZone timeZone) {
221 return format(date, pattern, timeZone, null);
222 }
223
224 /**
225 * <p>Formats a calendar into a specific pattern in a time zone.</p>
226 *
227 * @param calendar the calendar to format, not null
228 * @param pattern the pattern to use to format the calendar, not null
229 * @param timeZone the time zone to use, may be <code>null</code>
230 * @return the formatted calendar
231 * @see FastDateFormat#format(Calendar)
232 * @since 2.4
233 */
234 public static String format(Calendar calendar, String pattern, TimeZone timeZone) {
235 return format(calendar, pattern, timeZone, null);
236 }
237
238 /**
239 * <p>Formats a date/time into a specific pattern in a locale.</p>
240 *
241 * @param millis the date to format expressed in milliseconds
242 * @param pattern the pattern to use to format the date, not null
243 * @param locale the locale to use, may be <code>null</code>
244 * @return the formatted date
245 */
246 public static String format(long millis, String pattern, Locale locale) {
247 return format(new Date(millis), pattern, null, locale);
248 }
249
250 /**
251 * <p>Formats a date/time into a specific pattern in a locale.</p>
252 *
253 * @param date the date to format, not null
254 * @param pattern the pattern to use to format the date, not null
255 * @param locale the locale to use, may be <code>null</code>
256 * @return the formatted date
257 */
258 public static String format(Date date, String pattern, Locale locale) {
259 return format(date, pattern, null, locale);
260 }
261
262 /**
263 * <p>Formats a calendar into a specific pattern in a locale.</p>
264 *
265 * @param calendar the calendar to format, not null
266 * @param pattern the pattern to use to format the calendar, not null
267 * @param locale the locale to use, may be <code>null</code>
268 * @return the formatted calendar
269 * @see FastDateFormat#format(Calendar)
270 * @since 2.4
271 */
272 public static String format(Calendar calendar, String pattern, Locale locale) {
273 return format(calendar, pattern, null, locale);
274 }
275
276 /**
277 * <p>Formats a date/time into a specific pattern in a time zone and locale.</p>
278 *
279 * @param millis the date to format expressed in milliseconds
280 * @param pattern the pattern to use to format the date, not null
281 * @param timeZone the time zone to use, may be <code>null</code>
282 * @param locale the locale to use, may be <code>null</code>
283 * @return the formatted date
284 */
285 public static String format(long millis, String pattern, TimeZone timeZone, Locale locale) {
286 return format(new Date(millis), pattern, timeZone, locale);
287 }
288
289 /**
290 * <p>Formats a date/time into a specific pattern in a time zone and locale.</p>
291 *
292 * @param date the date to format, not null
293 * @param pattern the pattern to use to format the date, not null, not null
294 * @param timeZone the time zone to use, may be <code>null</code>
295 * @param locale the locale to use, may be <code>null</code>
296 * @return the formatted date
297 */
298 public static String format(Date date, String pattern, TimeZone timeZone, Locale locale) {
299 FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
300 return df.format(date);
301 }
302
303 /**
304 * <p>Formats a calendar into a specific pattern in a time zone and locale.</p>
305 *
306 * @param calendar the calendar to format, not null
307 * @param pattern the pattern to use to format the calendar, not null
308 * @param timeZone the time zone to use, may be <code>null</code>
309 * @param locale the locale to use, may be <code>null</code>
310 * @return the formatted calendar
311 * @see FastDateFormat#format(Calendar)
312 * @since 2.4
313 */
314 public static String format(Calendar calendar, String pattern, TimeZone timeZone, Locale locale) {
315 FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
316 return df.format(calendar);
317 }
318
319 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import java.text.ParseException;
19 import java.text.ParsePosition;
20 import java.text.SimpleDateFormat;
21 import java.util.Calendar;
22 import java.util.Date;
23 import java.util.Iterator;
24 import java.util.NoSuchElementException;
25
26 /**
27 * <p>A suite of utilities surrounding the use of the
28 * {@link java.util.Calendar} and {@link java.util.Date} object.</p>
29 *
30 * <p>DateUtils contains a lot of common methods considering manipulations
31 * of Dates or Calendars. Some methods require some extra explanation.
32 * The truncate, ceiling and round methods could be considered the Math.floor(),
33 * Math.ceil() or Math.round versions for dates
34 * This way date-fields will be ignored in bottom-up order.
35 * As a complement to these methods we've introduced some fragment-methods.
36 * With these methods the Date-fields will be ignored in top-down order.
37 * Since a date without a year is not a valid date, you have to decide in what
38 * kind of date-field you want your result, for instance milliseconds or days.
39 * </p>
40 *
41 * @since 2.0
42 * @version $Id: DateUtils.java 1144992 2011-07-11 00:49:04Z ggregory $
43 */
44 public class DateUtils {
45
46 /**
47 * Number of milliseconds in a standard second.
48 * @since 2.1
49 */
50 public static final long MILLIS_PER_SECOND = 1000;
51 /**
52 * Number of milliseconds in a standard minute.
53 * @since 2.1
54 */
55 public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
56 /**
57 * Number of milliseconds in a standard hour.
58 * @since 2.1
59 */
60 public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
61 /**
62 * Number of milliseconds in a standard day.
63 * @since 2.1
64 */
65 public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
66
67 /**
68 * This is half a month, so this represents whether a date is in the top
69 * or bottom half of the month.
70 */
71 public static final int SEMI_MONTH = 1001;
72
73 private static final int[][] fields = {
74 {Calendar.MILLISECOND},
75 {Calendar.SECOND},
76 {Calendar.MINUTE},
77 {Calendar.HOUR_OF_DAY, Calendar.HOUR},
78 {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM
79 /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */
80 },
81 {Calendar.MONTH, DateUtils.SEMI_MONTH},
82 {Calendar.YEAR},
83 {Calendar.ERA}};
84
85 /**
86 * A week range, starting on Sunday.
87 */
88 public static final int RANGE_WEEK_SUNDAY = 1;
89 /**
90 * A week range, starting on Monday.
91 */
92 public static final int RANGE_WEEK_MONDAY = 2;
93 /**
94 * A week range, starting on the day focused.
95 */
96 public static final int RANGE_WEEK_RELATIVE = 3;
97 /**
98 * A week range, centered around the day focused.
99 */
100 public static final int RANGE_WEEK_CENTER = 4;
101 /**
102 * A month range, the week starting on Sunday.
103 */
104 public static final int RANGE_MONTH_SUNDAY = 5;
105 /**
106 * A month range, the week starting on Monday.
107 */
108 public static final int RANGE_MONTH_MONDAY = 6;
109
110 /**
111 * Constant marker for truncating.
112 * @since 3.0
113 */
114 private static final int MODIFY_TRUNCATE = 0;
115 /**
116 * Constant marker for rounding.
117 * @since 3.0
118 */
119 private static final int MODIFY_ROUND = 1;
120 /**
121 * Constant marker for ceiling.
122 * @since 3.0
123 */
124 private static final int MODIFY_CEILING = 2;
125
126 /**
127 * <p>{@code DateUtils} instances should NOT be constructed in
128 * standard programming. Instead, the static methods on the class should
129 * be used, such as {@code DateUtils.parseDate(str);}.</p>
130 *
131 * <p>This constructor is public to permit tools that require a JavaBean
132 * instance to operate.</p>
133 */
134 public DateUtils() {
135 super();
136 }
137
138 //-----------------------------------------------------------------------
139 /**
140 * <p>Checks if two date objects are on the same day ignoring time.</p>
141 *
142 * <p>28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true.
143 * 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false.
144 * </p>
145 *
146 * @param date1 the first date, not altered, not null
147 * @param date2 the second date, not altered, not null
148 * @return true if they represent the same day
149 * @throws IllegalArgumentException if either date is <code>null</code>
150 * @since 2.1
151 */
152 public static boolean isSameDay(Date date1, Date date2) {
153 if (date1 == null || date2 == null) {
154 throw new IllegalArgumentException("The date must not be null");
155 }
156 Calendar cal1 = Calendar.getInstance();
157 cal1.setTime(date1);
158 Calendar cal2 = Calendar.getInstance();
159 cal2.setTime(date2);
160 return isSameDay(cal1, cal2);
161 }
162
163 /**
164 * <p>Checks if two calendar objects are on the same day ignoring time.</p>
165 *
166 * <p>28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true.
167 * 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false.
168 * </p>
169 *
170 * @param cal1 the first calendar, not altered, not null
171 * @param cal2 the second calendar, not altered, not null
172 * @return true if they represent the same day
173 * @throws IllegalArgumentException if either calendar is <code>null</code>
174 * @since 2.1
175 */
176 public static boolean isSameDay(Calendar cal1, Calendar cal2) {
177 if (cal1 == null || cal2 == null) {
178 throw new IllegalArgumentException("The date must not be null");
179 }
180 return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
181 cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
182 cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));
183 }
184
185 //-----------------------------------------------------------------------
186 /**
187 * <p>Checks if two date objects represent the same instant in time.</p>
188 *
189 * <p>This method compares the long millisecond time of the two objects.</p>
190 *
191 * @param date1 the first date, not altered, not null
192 * @param date2 the second date, not altered, not null
193 * @return true if they represent the same millisecond instant
194 * @throws IllegalArgumentException if either date is <code>null</code>
195 * @since 2.1
196 */
197 public static boolean isSameInstant(Date date1, Date date2) {
198 if (date1 == null || date2 == null) {
199 throw new IllegalArgumentException("The date must not be null");
200 }
201 return date1.getTime() == date2.getTime();
202 }
203
204 /**
205 * <p>Checks if two calendar objects represent the same instant in time.</p>
206 *
207 * <p>This method compares the long millisecond time of the two objects.</p>
208 *
209 * @param cal1 the first calendar, not altered, not null
210 * @param cal2 the second calendar, not altered, not null
211 * @return true if they represent the same millisecond instant
212 * @throws IllegalArgumentException if either date is <code>null</code>
213 * @since 2.1
214 */
215 public static boolean isSameInstant(Calendar cal1, Calendar cal2) {
216 if (cal1 == null || cal2 == null) {
217 throw new IllegalArgumentException("The date must not be null");
218 }
219 return cal1.getTime().getTime() == cal2.getTime().getTime();
220 }
221
222 //-----------------------------------------------------------------------
223 /**
224 * <p>Checks if two calendar objects represent the same local time.</p>
225 *
226 * <p>This method compares the values of the fields of the two objects.
227 * In addition, both calendars must be the same of the same type.</p>
228 *
229 * @param cal1 the first calendar, not altered, not null
230 * @param cal2 the second calendar, not altered, not null
231 * @return true if they represent the same millisecond instant
232 * @throws IllegalArgumentException if either date is <code>null</code>
233 * @since 2.1
234 */
235 public static boolean isSameLocalTime(Calendar cal1, Calendar cal2) {
236 if (cal1 == null || cal2 == null) {
237 throw new IllegalArgumentException("The date must not be null");
238 }
239 return (cal1.get(Calendar.MILLISECOND) == cal2.get(Calendar.MILLISECOND) &&
240 cal1.get(Calendar.SECOND) == cal2.get(Calendar.SECOND) &&
241 cal1.get(Calendar.MINUTE) == cal2.get(Calendar.MINUTE) &&
242 cal1.get(Calendar.HOUR_OF_DAY) == cal2.get(Calendar.HOUR_OF_DAY) &&
243 cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) &&
244 cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
245 cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
246 cal1.getClass() == cal2.getClass());
247 }
248
249 //-----------------------------------------------------------------------
250 /**
251 * <p>Parses a string representing a date by trying a variety of different parsers.</p>
252 *
253 * <p>The parse will try each parse pattern in turn.
254 * A parse is only deemed successful if it parses the whole of the input string.
255 * If no parse patterns match, a ParseException is thrown.</p>
256 * The parser will be lenient toward the parsed date.
257 *
258 * @param str the date to parse, not null
259 * @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null
260 * @return the parsed date
261 * @throws IllegalArgumentException if the date string or pattern array is null
262 * @throws ParseException if none of the date patterns were suitable (or there were none)
263 */
264 public static Date parseDate(String str, String... parsePatterns) throws ParseException {
265 return parseDateWithLeniency(str, parsePatterns, true);
266 }
267
268 //-----------------------------------------------------------------------
269 /**
270 * <p>Parses a string representing a date by trying a variety of different parsers.</p>
271 *
272 * <p>The parse will try each parse pattern in turn.
273 * A parse is only deemed successful if it parses the whole of the input string.
274 * If no parse patterns match, a ParseException is thrown.</p>
275 * The parser parses strictly - it does not allow for dates such as "February 942, 1996".
276 *
277 * @param str the date to parse, not null
278 * @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null
279 * @return the parsed date
280 * @throws IllegalArgumentException if the date string or pattern array is null
281 * @throws ParseException if none of the date patterns were suitable
282 * @since 2.5
283 */
284 public static Date parseDateStrictly(String str, String... parsePatterns) throws ParseException {
285 return parseDateWithLeniency(str, parsePatterns, false);
286 }
287
288 /**
289 * <p>Parses a string representing a date by trying a variety of different parsers.</p>
290 *
291 * <p>The parse will try each parse pattern in turn.
292 * A parse is only deemed successful if it parses the whole of the input string.
293 * If no parse patterns match, a ParseException is thrown.</p>
294 *
295 * @param str the date to parse, not null
296 * @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null
297 * @param lenient Specify whether or not date/time parsing is to be lenient.
298 * @return the parsed date
299 * @throws IllegalArgumentException if the date string or pattern array is null
300 * @throws ParseException if none of the date patterns were suitable
301 * @see java.util.Calender#isLenient()
302 */
303 private static Date parseDateWithLeniency(
304 String str, String[] parsePatterns, boolean lenient) throws ParseException {
305 if (str == null || parsePatterns == null) {
306 throw new IllegalArgumentException("Date and Patterns must not be null");
307 }
308
309 SimpleDateFormat parser = new SimpleDateFormat();
310 parser.setLenient(lenient);
311 ParsePosition pos = new ParsePosition(0);
312 for (String parsePattern : parsePatterns) {
313
314 String pattern = parsePattern;
315
316 // LANG-530 - need to make sure 'ZZ' output doesn't get passed to SimpleDateFormat
317 if (parsePattern.endsWith("ZZ")) {
318 pattern = pattern.substring(0, pattern.length() - 1);
319 }
320
321 parser.applyPattern(pattern);
322 pos.setIndex(0);
323
324 String str2 = str;
325 // LANG-530 - need to make sure 'ZZ' output doesn't hit SimpleDateFormat as it will ParseException
326 if (parsePattern.endsWith("ZZ")) {
327 str2 = str.replaceAll("([-+][0-9][0-9]):([0-9][0-9])$", "$1$2");
328 }
329
330 Date date = parser.parse(str2, pos);
331 if (date != null && pos.getIndex() == str2.length()) {
332 return date;
333 }
334 }
335 throw new ParseException("Unable to parse the date: " + str, -1);
336 }
337
338 //-----------------------------------------------------------------------
339 /**
340 * Adds a number of years to a date returning a new object.
341 * The original {@code Date} is unchanged.
342 *
343 * @param date the date, not null
344 * @param amount the amount to add, may be negative
345 * @return the new {@code Date} with the amount added
346 * @throws IllegalArgumentException if the date is null
347 */
348 public static Date addYears(Date date, int amount) {
349 return add(date, Calendar.YEAR, amount);
350 }
351
352 //-----------------------------------------------------------------------
353 /**
354 * Adds a number of months to a date returning a new object.
355 * The original {@code Date} is unchanged.
356 *
357 * @param date the date, not null
358 * @param amount the amount to add, may be negative
359 * @return the new {@code Date} with the amount added
360 * @throws IllegalArgumentException if the date is null
361 */
362 public static Date addMonths(Date date, int amount) {
363 return add(date, Calendar.MONTH, amount);
364 }
365
366 //-----------------------------------------------------------------------
367 /**
368 * Adds a number of weeks to a date returning a new object.
369 * The original {@code Date} is unchanged.
370 *
371 * @param date the date, not null
372 * @param amount the amount to add, may be negative
373 * @return the new {@code Date} with the amount added
374 * @throws IllegalArgumentException if the date is null
375 */
376 public static Date addWeeks(Date date, int amount) {
377 return add(date, Calendar.WEEK_OF_YEAR, amount);
378 }
379
380 //-----------------------------------------------------------------------
381 /**
382 * Adds a number of days to a date returning a new object.
383 * The original {@code Date} is unchanged.
384 *
385 * @param date the date, not null
386 * @param amount the amount to add, may be negative
387 * @return the new {@code Date} with the amount added
388 * @throws IllegalArgumentException if the date is null
389 */
390 public static Date addDays(Date date, int amount) {
391 return add(date, Calendar.DAY_OF_MONTH, amount);
392 }
393
394 //-----------------------------------------------------------------------
395 /**
396 * Adds a number of hours to a date returning a new object.
397 * The original {@code Date} is unchanged.
398 *
399 * @param date the date, not null
400 * @param amount the amount to add, may be negative
401 * @return the new {@code Date} with the amount added
402 * @throws IllegalArgumentException if the date is null
403 */
404 public static Date addHours(Date date, int amount) {
405 return add(date, Calendar.HOUR_OF_DAY, amount);
406 }
407
408 //-----------------------------------------------------------------------
409 /**
410 * Adds a number of minutes to a date returning a new object.
411 * The original {@code Date} is unchanged.
412 *
413 * @param date the date, not null
414 * @param amount the amount to add, may be negative
415 * @return the new {@code Date} with the amount added
416 * @throws IllegalArgumentException if the date is null
417 */
418 public static Date addMinutes(Date date, int amount) {
419 return add(date, Calendar.MINUTE, amount);
420 }
421
422 //-----------------------------------------------------------------------
423 /**
424 * Adds a number of seconds to a date returning a new object.
425 * The original {@code Date} is unchanged.
426 *
427 * @param date the date, not null
428 * @param amount the amount to add, may be negative
429 * @return the new {@code Date} with the amount added
430 * @throws IllegalArgumentException if the date is null
431 */
432 public static Date addSeconds(Date date, int amount) {
433 return add(date, Calendar.SECOND, amount);
434 }
435
436 //-----------------------------------------------------------------------
437 /**
438 * Adds a number of milliseconds to a date returning a new object.
439 * The original {@code Date} is unchanged.
440 *
441 * @param date the date, not null
442 * @param amount the amount to add, may be negative
443 * @return the new {@code Date} with the amount added
444 * @throws IllegalArgumentException if the date is null
445 */
446 public static Date addMilliseconds(Date date, int amount) {
447 return add(date, Calendar.MILLISECOND, amount);
448 }
449
450 //-----------------------------------------------------------------------
451 /**
452 * Adds to a date returning a new object.
453 * The original {@code Date} is unchanged.
454 *
455 * @param date the date, not null
456 * @param calendarField the calendar field to add to
457 * @param amount the amount to add, may be negative
458 * @return the new {@code Date} with the amount added
459 * @throws IllegalArgumentException if the date is null
460 */
461 private static Date add(Date date, int calendarField, int amount) {
462 if (date == null) {
463 throw new IllegalArgumentException("The date must not be null");
464 }
465 Calendar c = Calendar.getInstance();
466 c.setTime(date);
467 c.add(calendarField, amount);
468 return c.getTime();
469 }
470
471 //-----------------------------------------------------------------------
472 /**
473 * Sets the years field to a date returning a new object.
474 * The original {@code Date} is unchanged.
475 *
476 * @param date the date, not null
477 * @param amount the amount to set
478 * @return a new {@code Date} set with the specified value
479 * @throws IllegalArgumentException if the date is null
480 * @since 2.4
481 */
482 public static Date setYears(Date date, int amount) {
483 return set(date, Calendar.YEAR, amount);
484 }
485
486 //-----------------------------------------------------------------------
487 /**
488 * Sets the months field to a date returning a new object.
489 * The original {@code Date} is unchanged.
490 *
491 * @param date the date, not null
492 * @param amount the amount to set
493 * @return a new {@code Date} set with the specified value
494 * @throws IllegalArgumentException if the date is null
495 * @since 2.4
496 */
497 public static Date setMonths(Date date, int amount) {
498 return set(date, Calendar.MONTH, amount);
499 }
500
501 //-----------------------------------------------------------------------
502 /**
503 * Sets the day of month field to a date returning a new object.
504 * The original {@code Date} is unchanged.
505 *
506 * @param date the date, not null
507 * @param amount the amount to set
508 * @return a new {@code Date} set with the specified value
509 * @throws IllegalArgumentException if the date is null
510 * @since 2.4
511 */
512 public static Date setDays(Date date, int amount) {
513 return set(date, Calendar.DAY_OF_MONTH, amount);
514 }
515
516 //-----------------------------------------------------------------------
517 /**
518 * Sets the hours field to a date returning a new object. Hours range
519 * from 0-23.
520 * The original {@code Date} is unchanged.
521 *
522 * @param date the date, not null
523 * @param amount the amount to set
524 * @return a new {@code Date} set with the specified value
525 * @throws IllegalArgumentException if the date is null
526 * @since 2.4
527 */
528 public static Date setHours(Date date, int amount) {
529 return set(date, Calendar.HOUR_OF_DAY, amount);
530 }
531
532 //-----------------------------------------------------------------------
533 /**
534 * Sets the minute field to a date returning a new object.
535 * The original {@code Date} is unchanged.
536 *
537 * @param date the date, not null
538 * @param amount the amount to set
539 * @return a new {@code Date} set with the specified value
540 * @throws IllegalArgumentException if the date is null
541 * @since 2.4
542 */
543 public static Date setMinutes(Date date, int amount) {
544 return set(date, Calendar.MINUTE, amount);
545 }
546
547 //-----------------------------------------------------------------------
548 /**
549 * Sets the seconds field to a date returning a new object.
550 * The original {@code Date} is unchanged.
551 *
552 * @param date the date, not null
553 * @param amount the amount to set
554 * @return a new {@code Date} set with the specified value
555 * @throws IllegalArgumentException if the date is null
556 * @since 2.4
557 */
558 public static Date setSeconds(Date date, int amount) {
559 return set(date, Calendar.SECOND, amount);
560 }
561
562 //-----------------------------------------------------------------------
563 /**
564 * Sets the miliseconds field to a date returning a new object.
565 * The original {@code Date} is unchanged.
566 *
567 * @param date the date, not null
568 * @param amount the amount to set
569 * @return a new {@code Date} set with the specified value
570 * @throws IllegalArgumentException if the date is null
571 * @since 2.4
572 */
573 public static Date setMilliseconds(Date date, int amount) {
574 return set(date, Calendar.MILLISECOND, amount);
575 }
576
577 //-----------------------------------------------------------------------
578 /**
579 * Sets the specified field to a date returning a new object.
580 * This does not use a lenient calendar.
581 * The original {@code Date} is unchanged.
582 *
583 * @param date the date, not null
584 * @param calendarField the {@code Calendar} field to set the amount to
585 * @param amount the amount to set
586 * @return a new {@code Date} set with the specified value
587 * @throws IllegalArgumentException if the date is null
588 * @since 2.4
589 */
590 private static Date set(Date date, int calendarField, int amount) {
591 if (date == null) {
592 throw new IllegalArgumentException("The date must not be null");
593 }
594 // getInstance() returns a new object, so this method is thread safe.
595 Calendar c = Calendar.getInstance();
596 c.setLenient(false);
597 c.setTime(date);
598 c.set(calendarField, amount);
599 return c.getTime();
600 }
601
602 //-----------------------------------------------------------------------
603 /**
604 * Convert a {@code Date} into a {@code Calendar}.
605 *
606 * @param date the date to convert to a Calendar
607 * @return the created Calendar
608 * @throws NullPointerException if null is passed in
609 * @since 3.0
610 */
611 public static Calendar toCalendar(Date date) {
612 Calendar c = Calendar.getInstance();
613 c.setTime(date);
614 return c;
615 }
616
617 //-----------------------------------------------------------------------
618 /**
619 * <p>Round this date, leaving the field specified as the most
620 * significant field.</p>
621 *
622 * <p>For example, if you had the datetime of 28 Mar 2002
623 * 13:45:01.231, if this was passed with HOUR, it would return
624 * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it
625 * would return 1 April 2002 0:00:00.000.</p>
626 *
627 * <p>For a date in a timezone that handles the change to daylight
628 * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows.
629 * Suppose daylight saving time begins at 02:00 on March 30. Rounding a
630 * date that crosses this time would produce the following values:
631 * <ul>
632 * <li>March 30, 2003 01:10 rounds to March 30, 2003 01:00</li>
633 * <li>March 30, 2003 01:40 rounds to March 30, 2003 03:00</li>
634 * <li>March 30, 2003 02:10 rounds to March 30, 2003 03:00</li>
635 * <li>March 30, 2003 02:40 rounds to March 30, 2003 04:00</li>
636 * </ul>
637 * </p>
638 *
639 * @param date the date to work with, not null
640 * @param field the field from {@code Calendar} or {@code SEMI_MONTH}
641 * @return the different rounded date, not null
642 * @throws ArithmeticException if the year is over 280 million
643 */
644 public static Date round(Date date, int field) {
645 if (date == null) {
646 throw new IllegalArgumentException("The date must not be null");
647 }
648 Calendar gval = Calendar.getInstance();
649 gval.setTime(date);
650 modify(gval, field, MODIFY_ROUND);
651 return gval.getTime();
652 }
653
654 /**
655 * <p>Round this date, leaving the field specified as the most
656 * significant field.</p>
657 *
658 * <p>For example, if you had the datetime of 28 Mar 2002
659 * 13:45:01.231, if this was passed with HOUR, it would return
660 * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it
661 * would return 1 April 2002 0:00:00.000.</p>
662 *
663 * <p>For a date in a timezone that handles the change to daylight
664 * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows.
665 * Suppose daylight saving time begins at 02:00 on March 30. Rounding a
666 * date that crosses this time would produce the following values:
667 * <ul>
668 * <li>March 30, 2003 01:10 rounds to March 30, 2003 01:00</li>
669 * <li>March 30, 2003 01:40 rounds to March 30, 2003 03:00</li>
670 * <li>March 30, 2003 02:10 rounds to March 30, 2003 03:00</li>
671 * <li>March 30, 2003 02:40 rounds to March 30, 2003 04:00</li>
672 * </ul>
673 * </p>
674 *
675 * @param date the date to work with, not null
676 * @param field the field from {@code Calendar} or <code>SEMI_MONTH</code>
677 * @return the different rounded date, not null
678 * @throws IllegalArgumentException if the date is <code>null</code>
679 * @throws ArithmeticException if the year is over 280 million
680 */
681 public static Calendar round(Calendar date, int field) {
682 if (date == null) {
683 throw new IllegalArgumentException("The date must not be null");
684 }
685 Calendar rounded = (Calendar) date.clone();
686 modify(rounded, field, MODIFY_ROUND);
687 return rounded;
688 }
689
690 /**
691 * <p>Round this date, leaving the field specified as the most
692 * significant field.</p>
693 *
694 * <p>For example, if you had the datetime of 28 Mar 2002
695 * 13:45:01.231, if this was passed with HOUR, it would return
696 * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it
697 * would return 1 April 2002 0:00:00.000.</p>
698 *
699 * <p>For a date in a timezone that handles the change to daylight
700 * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows.
701 * Suppose daylight saving time begins at 02:00 on March 30. Rounding a
702 * date that crosses this time would produce the following values:
703 * <ul>
704 * <li>March 30, 2003 01:10 rounds to March 30, 2003 01:00</li>
705 * <li>March 30, 2003 01:40 rounds to March 30, 2003 03:00</li>
706 * <li>March 30, 2003 02:10 rounds to March 30, 2003 03:00</li>
707 * <li>March 30, 2003 02:40 rounds to March 30, 2003 04:00</li>
708 * </ul>
709 * </p>
710 *
711 * @param date the date to work with, either {@code Date} or {@code Calendar}, not null
712 * @param field the field from {@code Calendar} or <code>SEMI_MONTH</code>
713 * @return the different rounded date, not null
714 * @throws IllegalArgumentException if the date is <code>null</code>
715 * @throws ClassCastException if the object type is not a {@code Date} or {@code Calendar}
716 * @throws ArithmeticException if the year is over 280 million
717 */
718 public static Date round(Object date, int field) {
719 if (date == null) {
720 throw new IllegalArgumentException("The date must not be null");
721 }
722 if (date instanceof Date) {
723 return round((Date) date, field);
724 } else if (date instanceof Calendar) {
725 return round((Calendar) date, field).getTime();
726 } else {
727 throw new ClassCastException("Could not round " + date);
728 }
729 }
730
731 //-----------------------------------------------------------------------
732 /**
733 * <p>Truncate this date, leaving the field specified as the most
734 * significant field.</p>
735 *
736 * <p>For example, if you had the datetime of 28 Mar 2002
737 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
738 * 2002 13:00:00.000. If this was passed with MONTH, it would
739 * return 1 Mar 2002 0:00:00.000.</p>
740 *
741 * @param date the date to work with, not null
742 * @param field the field from {@code Calendar} or <code>SEMI_MONTH</code>
743 * @return the different truncated date, not null
744 * @throws IllegalArgumentException if the date is <code>null</code>
745 * @throws ArithmeticException if the year is over 280 million
746 */
747 public static Date truncate(Date date, int field) {
748 if (date == null) {
749 throw new IllegalArgumentException("The date must not be null");
750 }
751 Calendar gval = Calendar.getInstance();
752 gval.setTime(date);
753 modify(gval, field, MODIFY_TRUNCATE);
754 return gval.getTime();
755 }
756
757 /**
758 * <p>Truncate this date, leaving the field specified as the most
759 * significant field.</p>
760 *
761 * <p>For example, if you had the datetime of 28 Mar 2002
762 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
763 * 2002 13:00:00.000. If this was passed with MONTH, it would
764 * return 1 Mar 2002 0:00:00.000.</p>
765 *
766 * @param date the date to work with, not null
767 * @param field the field from {@code Calendar} or <code>SEMI_MONTH</code>
768 * @return the different truncated date, not null
769 * @throws IllegalArgumentException if the date is <code>null</code>
770 * @throws ArithmeticException if the year is over 280 million
771 */
772 public static Calendar truncate(Calendar date, int field) {
773 if (date == null) {
774 throw new IllegalArgumentException("The date must not be null");
775 }
776 Calendar truncated = (Calendar) date.clone();
777 modify(truncated, field, MODIFY_TRUNCATE);
778 return truncated;
779 }
780
781 /**
782 * <p>Truncate this date, leaving the field specified as the most
783 * significant field.</p>
784 *
785 * <p>For example, if you had the datetime of 28 Mar 2002
786 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
787 * 2002 13:00:00.000. If this was passed with MONTH, it would
788 * return 1 Mar 2002 0:00:00.000.</p>
789 *
790 * @param date the date to work with, either {@code Date} or {@code Calendar}, not null
791 * @param field the field from {@code Calendar} or <code>SEMI_MONTH</code>
792 * @return the different truncated date, not null
793 * @throws IllegalArgumentException if the date is <code>null</code>
794 * @throws ClassCastException if the object type is not a {@code Date} or {@code Calendar}
795 * @throws ArithmeticException if the year is over 280 million
796 */
797 public static Date truncate(Object date, int field) {
798 if (date == null) {
799 throw new IllegalArgumentException("The date must not be null");
800 }
801 if (date instanceof Date) {
802 return truncate((Date) date, field);
803 } else if (date instanceof Calendar) {
804 return truncate((Calendar) date, field).getTime();
805 } else {
806 throw new ClassCastException("Could not truncate " + date);
807 }
808 }
809
810 //-----------------------------------------------------------------------
811 /**
812 * <p>Ceil this date, leaving the field specified as the most
813 * significant field.</p>
814 *
815 * <p>For example, if you had the datetime of 28 Mar 2002
816 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
817 * 2002 14:00:00.000. If this was passed with MONTH, it would
818 * return 1 Apr 2002 0:00:00.000.</p>
819 *
820 * @param date the date to work with, not null
821 * @param field the field from {@code Calendar} or <code>SEMI_MONTH</code>
822 * @return the different ceil date, not null
823 * @throws IllegalArgumentException if the date is <code>null</code>
824 * @throws ArithmeticException if the year is over 280 million
825 * @since 2.5
826 */
827 public static Date ceiling(Date date, int field) {
828 if (date == null) {
829 throw new IllegalArgumentException("The date must not be null");
830 }
831 Calendar gval = Calendar.getInstance();
832 gval.setTime(date);
833 modify(gval, field, MODIFY_CEILING);
834 return gval.getTime();
835 }
836
837 /**
838 * <p>Ceil this date, leaving the field specified as the most
839 * significant field.</p>
840 *
841 * <p>For example, if you had the datetime of 28 Mar 2002
842 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
843 * 2002 13:00:00.000. If this was passed with MONTH, it would
844 * return 1 Mar 2002 0:00:00.000.</p>
845 *
846 * @param date the date to work with, not null
847 * @param field the field from {@code Calendar} or <code>SEMI_MONTH</code>
848 * @return the different ceil date, not null
849 * @throws IllegalArgumentException if the date is <code>null</code>
850 * @throws ArithmeticException if the year is over 280 million
851 * @since 2.5
852 */
853 public static Calendar ceiling(Calendar date, int field) {
854 if (date == null) {
855 throw new IllegalArgumentException("The date must not be null");
856 }
857 Calendar ceiled = (Calendar) date.clone();
858 modify(ceiled, field, MODIFY_CEILING);
859 return ceiled;
860 }
861
862 /**
863 * <p>Ceil this date, leaving the field specified as the most
864 * significant field.</p>
865 *
866 * <p>For example, if you had the datetime of 28 Mar 2002
867 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
868 * 2002 13:00:00.000. If this was passed with MONTH, it would
869 * return 1 Mar 2002 0:00:00.000.</p>
870 *
871 * @param date the date to work with, either {@code Date} or {@code Calendar}, not null
872 * @param field the field from {@code Calendar} or <code>SEMI_MONTH</code>
873 * @return the different ceil date, not null
874 * @throws IllegalArgumentException if the date is <code>null</code>
875 * @throws ClassCastException if the object type is not a {@code Date} or {@code Calendar}
876 * @throws ArithmeticException if the year is over 280 million
877 * @since 2.5
878 */
879 public static Date ceiling(Object date, int field) {
880 if (date == null) {
881 throw new IllegalArgumentException("The date must not be null");
882 }
883 if (date instanceof Date) {
884 return ceiling((Date) date, field);
885 } else if (date instanceof Calendar) {
886 return ceiling((Calendar) date, field).getTime();
887 } else {
888 throw new ClassCastException("Could not find ceiling of for type: " + date.getClass());
889 }
890 }
891
892 //-----------------------------------------------------------------------
893 /**
894 * <p>Internal calculation method.</p>
895 *
896 * @param val the calendar, not null
897 * @param field the field constant
898 * @param modType type to truncate, round or ceiling
899 * @throws ArithmeticException if the year is over 280 million
900 */
901 private static void modify(Calendar val, int field, int modType) {
902 if (val.get(Calendar.YEAR) > 280000000) {
903 throw new ArithmeticException("Calendar value too large for accurate calculations");
904 }
905
906 if (field == Calendar.MILLISECOND) {
907 return;
908 }
909
910 // ----------------- Fix for LANG-59 ---------------------- START ---------------
911 // see http://issues.apache.org/jira/browse/LANG-59
912 //
913 // Manually truncate milliseconds, seconds and minutes, rather than using
914 // Calendar methods.
915
916 Date date = val.getTime();
917 long time = date.getTime();
918 boolean done = false;
919
920 // truncate milliseconds
921 int millisecs = val.get(Calendar.MILLISECOND);
922 if (MODIFY_TRUNCATE == modType || millisecs < 500) {
923 time = time - millisecs;
924 }
925 if (field == Calendar.SECOND) {
926 done = true;
927 }
928
929 // truncate seconds
930 int seconds = val.get(Calendar.SECOND);
931 if (!done && (MODIFY_TRUNCATE == modType || seconds < 30)) {
932 time = time - (seconds * 1000L);
933 }
934 if (field == Calendar.MINUTE) {
935 done = true;
936 }
937
938 // truncate minutes
939 int minutes = val.get(Calendar.MINUTE);
940 if (!done && (MODIFY_TRUNCATE == modType || minutes < 30)) {
941 time = time - (minutes * 60000L);
942 }
943
944 // reset time
945 if (date.getTime() != time) {
946 date.setTime(time);
947 val.setTime(date);
948 }
949 // ----------------- Fix for LANG-59 ----------------------- END ----------------
950
951 boolean roundUp = false;
952 for (int[] aField : fields) {
953 for (int element : aField) {
954 if (element == field) {
955 //This is our field... we stop looping
956 if (modType == MODIFY_CEILING || (modType == MODIFY_ROUND && roundUp)) {
957 if (field == DateUtils.SEMI_MONTH) {
958 //This is a special case that's hard to generalize
959 //If the date is 1, we round up to 16, otherwise
960 // we subtract 15 days and add 1 month
961 if (val.get(Calendar.DATE) == 1) {
962 val.add(Calendar.DATE, 15);
963 } else {
964 val.add(Calendar.DATE, -15);
965 val.add(Calendar.MONTH, 1);
966 }
967 // ----------------- Fix for LANG-440 ---------------------- START ---------------
968 } else if (field == Calendar.AM_PM) {
969 // This is a special case
970 // If the time is 0, we round up to 12, otherwise
971 // we subtract 12 hours and add 1 day
972 if (val.get(Calendar.HOUR_OF_DAY) == 0) {
973 val.add(Calendar.HOUR_OF_DAY, 12);
974 } else {
975 val.add(Calendar.HOUR_OF_DAY, -12);
976 val.add(Calendar.DATE, 1);
977 }
978 // ----------------- Fix for LANG-440 ---------------------- END ---------------
979 } else {
980 //We need at add one to this field since the
981 // last number causes us to round up
982 val.add(aField[0], 1);
983 }
984 }
985 return;
986 }
987 }
988 //We have various fields that are not easy roundings
989 int offset = 0;
990 boolean offsetSet = false;
991 //These are special types of fields that require different rounding rules
992 switch (field) {
993 case DateUtils.SEMI_MONTH:
994 if (aField[0] == Calendar.DATE) {
995 //If we're going to drop the DATE field's value,
996 // we want to do this our own way.
997 //We need to subtrace 1 since the date has a minimum of 1
998 offset = val.get(Calendar.DATE) - 1;
999 //If we're above 15 days adjustment, that means we're in the
1000 // bottom half of the month and should stay accordingly.
1001 if (offset >= 15) {
1002 offset -= 15;
1003 }
1004 //Record whether we're in the top or bottom half of that range
1005 roundUp = offset > 7;
1006 offsetSet = true;
1007 }
1008 break;
1009 case Calendar.AM_PM:
1010 if (aField[0] == Calendar.HOUR_OF_DAY) {
1011 //If we're going to drop the HOUR field's value,
1012 // we want to do this our own way.
1013 offset = val.get(Calendar.HOUR_OF_DAY);
1014 if (offset >= 12) {
1015 offset -= 12;
1016 }
1017 roundUp = offset >= 6;
1018 offsetSet = true;
1019 }
1020 break;
1021 }
1022 if (!offsetSet) {
1023 int min = val.getActualMinimum(aField[0]);
1024 int max = val.getActualMaximum(aField[0]);
1025 //Calculate the offset from the minimum allowed value
1026 offset = val.get(aField[0]) - min;
1027 //Set roundUp if this is more than half way between the minimum and maximum
1028 roundUp = offset > ((max - min) / 2);
1029 }
1030 //We need to remove this field
1031 if (offset != 0) {
1032 val.set(aField[0], val.get(aField[0]) - offset);
1033 }
1034 }
1035 throw new IllegalArgumentException("The field " + field + " is not supported");
1036
1037 }
1038
1039 //-----------------------------------------------------------------------
1040 /**
1041 * <p>This constructs an <code>Iterator</code> over each day in a date
1042 * range defined by a focus date and range style.</p>
1043 *
1044 * <p>For instance, passing Thursday, July 4, 2002 and a
1045 * <code>RANGE_MONTH_SUNDAY</code> will return an <code>Iterator</code>
1046 * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
1047 * 2002, returning a Calendar instance for each intermediate day.</p>
1048 *
1049 * <p>This method provides an iterator that returns Calendar objects.
1050 * The days are progressed using {@link Calendar#add(int, int)}.</p>
1051 *
1052 * @param focus the date to work with, not null
1053 * @param rangeStyle the style constant to use. Must be one of
1054 * {@link DateUtils#RANGE_MONTH_SUNDAY},
1055 * {@link DateUtils#RANGE_MONTH_MONDAY},
1056 * {@link DateUtils#RANGE_WEEK_SUNDAY},
1057 * {@link DateUtils#RANGE_WEEK_MONDAY},
1058 * {@link DateUtils#RANGE_WEEK_RELATIVE},
1059 * {@link DateUtils#RANGE_WEEK_CENTER}
1060 * @return the date iterator, not null, not null
1061 * @throws IllegalArgumentException if the date is <code>null</code>
1062 * @throws IllegalArgumentException if the rangeStyle is invalid
1063 */
1064 public static Iterator<Calendar> iterator(Date focus, int rangeStyle) {
1065 if (focus == null) {
1066 throw new IllegalArgumentException("The date must not be null");
1067 }
1068 Calendar gval = Calendar.getInstance();
1069 gval.setTime(focus);
1070 return iterator(gval, rangeStyle);
1071 }
1072
1073 /**
1074 * <p>This constructs an <code>Iterator</code> over each day in a date
1075 * range defined by a focus date and range style.</p>
1076 *
1077 * <p>For instance, passing Thursday, July 4, 2002 and a
1078 * <code>RANGE_MONTH_SUNDAY</code> will return an <code>Iterator</code>
1079 * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
1080 * 2002, returning a Calendar instance for each intermediate day.</p>
1081 *
1082 * <p>This method provides an iterator that returns Calendar objects.
1083 * The days are progressed using {@link Calendar#add(int, int)}.</p>
1084 *
1085 * @param focus the date to work with, not null
1086 * @param rangeStyle the style constant to use. Must be one of
1087 * {@link DateUtils#RANGE_MONTH_SUNDAY},
1088 * {@link DateUtils#RANGE_MONTH_MONDAY},
1089 * {@link DateUtils#RANGE_WEEK_SUNDAY},
1090 * {@link DateUtils#RANGE_WEEK_MONDAY},
1091 * {@link DateUtils#RANGE_WEEK_RELATIVE},
1092 * {@link DateUtils#RANGE_WEEK_CENTER}
1093 * @return the date iterator, not null
1094 * @throws IllegalArgumentException if the date is <code>null</code>
1095 * @throws IllegalArgumentException if the rangeStyle is invalid
1096 */
1097 public static Iterator<Calendar> iterator(Calendar focus, int rangeStyle) {
1098 if (focus == null) {
1099 throw new IllegalArgumentException("The date must not be null");
1100 }
1101 Calendar start = null;
1102 Calendar end = null;
1103 int startCutoff = Calendar.SUNDAY;
1104 int endCutoff = Calendar.SATURDAY;
1105 switch (rangeStyle) {
1106 case RANGE_MONTH_SUNDAY:
1107 case RANGE_MONTH_MONDAY:
1108 //Set start to the first of the month
1109 start = truncate(focus, Calendar.MONTH);
1110 //Set end to the last of the month
1111 end = (Calendar) start.clone();
1112 end.add(Calendar.MONTH, 1);
1113 end.add(Calendar.DATE, -1);
1114 //Loop start back to the previous sunday or monday
1115 if (rangeStyle == RANGE_MONTH_MONDAY) {
1116 startCutoff = Calendar.MONDAY;
1117 endCutoff = Calendar.SUNDAY;
1118 }
1119 break;
1120 case RANGE_WEEK_SUNDAY:
1121 case RANGE_WEEK_MONDAY:
1122 case RANGE_WEEK_RELATIVE:
1123 case RANGE_WEEK_CENTER:
1124 //Set start and end to the current date
1125 start = truncate(focus, Calendar.DATE);
1126 end = truncate(focus, Calendar.DATE);
1127 switch (rangeStyle) {
1128 case RANGE_WEEK_SUNDAY:
1129 //already set by default
1130 break;
1131 case RANGE_WEEK_MONDAY:
1132 startCutoff = Calendar.MONDAY;
1133 endCutoff = Calendar.SUNDAY;
1134 break;
1135 case RANGE_WEEK_RELATIVE:
1136 startCutoff = focus.get(Calendar.DAY_OF_WEEK);
1137 endCutoff = startCutoff - 1;
1138 break;
1139 case RANGE_WEEK_CENTER:
1140 startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3;
1141 endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3;
1142 break;
1143 }
1144 break;
1145 default:
1146 throw new IllegalArgumentException("The range style " + rangeStyle + " is not valid.");
1147 }
1148 if (startCutoff < Calendar.SUNDAY) {
1149 startCutoff += 7;
1150 }
1151 if (startCutoff > Calendar.SATURDAY) {
1152 startCutoff -= 7;
1153 }
1154 if (endCutoff < Calendar.SUNDAY) {
1155 endCutoff += 7;
1156 }
1157 if (endCutoff > Calendar.SATURDAY) {
1158 endCutoff -= 7;
1159 }
1160 while (start.get(Calendar.DAY_OF_WEEK) != startCutoff) {
1161 start.add(Calendar.DATE, -1);
1162 }
1163 while (end.get(Calendar.DAY_OF_WEEK) != endCutoff) {
1164 end.add(Calendar.DATE, 1);
1165 }
1166 return new DateIterator(start, end);
1167 }
1168
1169 /**
1170 * <p>This constructs an <code>Iterator</code> over each day in a date
1171 * range defined by a focus date and range style.</p>
1172 *
1173 * <p>For instance, passing Thursday, July 4, 2002 and a
1174 * <code>RANGE_MONTH_SUNDAY</code> will return an <code>Iterator</code>
1175 * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3,
1176 * 2002, returning a Calendar instance for each intermediate day.</p>
1177 *
1178 * @param focus the date to work with, either {@code Date} or {@code Calendar}, not null
1179 * @param rangeStyle the style constant to use. Must be one of the range
1180 * styles listed for the {@link #iterator(Calendar, int)} method.
1181 * @return the date iterator, not null
1182 * @throws IllegalArgumentException if the date is <code>null</code>
1183 * @throws ClassCastException if the object type is not a {@code Date} or {@code Calendar}
1184 */
1185 public static Iterator<?> iterator(Object focus, int rangeStyle) {
1186 if (focus == null) {
1187 throw new IllegalArgumentException("The date must not be null");
1188 }
1189 if (focus instanceof Date) {
1190 return iterator((Date) focus, rangeStyle);
1191 } else if (focus instanceof Calendar) {
1192 return iterator((Calendar) focus, rangeStyle);
1193 } else {
1194 throw new ClassCastException("Could not iterate based on " + focus);
1195 }
1196 }
1197
1198 /**
1199 * <p>Returns the number of milliseconds within the
1200 * fragment. All datefields greater than the fragment will be ignored.</p>
1201 *
1202 * <p>Asking the milliseconds of any date will only return the number of milliseconds
1203 * of the current second (resulting in a number between 0 and 999). This
1204 * method will retrieve the number of milliseconds for any fragment.
1205 * For example, if you want to calculate the number of milliseconds past today,
1206 * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will
1207 * be all milliseconds of the past hour(s), minutes(s) and second(s).</p>
1208 *
1209 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
1210 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
1211 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
1212 * A fragment less than or equal to a SECOND field will return 0.</p>
1213 *
1214 * <p>
1215 * <ul>
1216 * <li>January 1, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538</li>
1217 * <li>January 6, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538</li>
1218 * <li>January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10538 (10*1000 + 538)</li>
1219 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
1220 * (a millisecond cannot be split in milliseconds)</li>
1221 * </ul>
1222 * </p>
1223 *
1224 * @param date the date to work with, not null
1225 * @param fragment the {@code Calendar} field part of date to calculate
1226 * @return number of milliseconds within the fragment of date
1227 * @throws IllegalArgumentException if the date is <code>null</code> or
1228 * fragment is not supported
1229 * @since 2.4
1230 */
1231 public static long getFragmentInMilliseconds(Date date, int fragment) {
1232 return getFragment(date, fragment, Calendar.MILLISECOND);
1233 }
1234
1235 /**
1236 * <p>Returns the number of seconds within the
1237 * fragment. All datefields greater than the fragment will be ignored.</p>
1238 *
1239 * <p>Asking the seconds of any date will only return the number of seconds
1240 * of the current minute (resulting in a number between 0 and 59). This
1241 * method will retrieve the number of seconds for any fragment.
1242 * For example, if you want to calculate the number of seconds past today,
1243 * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will
1244 * be all seconds of the past hour(s) and minutes(s).</p>
1245 *
1246 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
1247 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
1248 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
1249 * A fragment less than or equal to a SECOND field will return 0.</p>
1250 *
1251 * <p>
1252 * <ul>
1253 * <li>January 1, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10
1254 * (equivalent to deprecated date.getSeconds())</li>
1255 * <li>January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10
1256 * (equivalent to deprecated date.getSeconds())</li>
1257 * <li>January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 26110
1258 * (7*3600 + 15*60 + 10)</li>
1259 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
1260 * (a millisecond cannot be split in seconds)</li>
1261 * </ul>
1262 * </p>
1263 *
1264 * @param date the date to work with, not null
1265 * @param fragment the {@code Calendar} field part of date to calculate
1266 * @return number of seconds within the fragment of date
1267 * @throws IllegalArgumentException if the date is <code>null</code> or
1268 * fragment is not supported
1269 * @since 2.4
1270 */
1271 public static long getFragmentInSeconds(Date date, int fragment) {
1272 return getFragment(date, fragment, Calendar.SECOND);
1273 }
1274
1275 /**
1276 * <p>Returns the number of minutes within the
1277 * fragment. All datefields greater than the fragment will be ignored.</p>
1278 *
1279 * <p>Asking the minutes of any date will only return the number of minutes
1280 * of the current hour (resulting in a number between 0 and 59). This
1281 * method will retrieve the number of minutes for any fragment.
1282 * For example, if you want to calculate the number of minutes past this month,
1283 * your fragment is Calendar.MONTH. The result will be all minutes of the
1284 * past day(s) and hour(s).</p>
1285 *
1286 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
1287 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
1288 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
1289 * A fragment less than or equal to a MINUTE field will return 0.</p>
1290 *
1291 * <p>
1292 * <ul>
1293 * <li>January 1, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15
1294 * (equivalent to deprecated date.getMinutes())</li>
1295 * <li>January 6, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15
1296 * (equivalent to deprecated date.getMinutes())</li>
1297 * <li>January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 15</li>
1298 * <li>January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 435 (7*60 + 15)</li>
1299 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
1300 * (a millisecond cannot be split in minutes)</li>
1301 * </ul>
1302 * </p>
1303 *
1304 * @param date the date to work with, not null
1305 * @param fragment the {@code Calendar} field part of date to calculate
1306 * @return number of minutes within the fragment of date
1307 * @throws IllegalArgumentException if the date is <code>null</code> or
1308 * fragment is not supported
1309 * @since 2.4
1310 */
1311 public static long getFragmentInMinutes(Date date, int fragment) {
1312 return getFragment(date, fragment, Calendar.MINUTE);
1313 }
1314
1315 /**
1316 * <p>Returns the number of hours within the
1317 * fragment. All datefields greater than the fragment will be ignored.</p>
1318 *
1319 * <p>Asking the hours of any date will only return the number of hours
1320 * of the current day (resulting in a number between 0 and 23). This
1321 * method will retrieve the number of hours for any fragment.
1322 * For example, if you want to calculate the number of hours past this month,
1323 * your fragment is Calendar.MONTH. The result will be all hours of the
1324 * past day(s).</p>
1325 *
1326 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
1327 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
1328 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
1329 * A fragment less than or equal to a HOUR field will return 0.</p>
1330 *
1331 * <p>
1332 * <ul>
1333 * <li>January 1, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7
1334 * (equivalent to deprecated date.getHours())</li>
1335 * <li>January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7
1336 * (equivalent to deprecated date.getHours())</li>
1337 * <li>January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 7</li>
1338 * <li>January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 127 (5*24 + 7)</li>
1339 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
1340 * (a millisecond cannot be split in hours)</li>
1341 * </ul>
1342 * </p>
1343 *
1344 * @param date the date to work with, not null
1345 * @param fragment the {@code Calendar} field part of date to calculate
1346 * @return number of hours within the fragment of date
1347 * @throws IllegalArgumentException if the date is <code>null</code> or
1348 * fragment is not supported
1349 * @since 2.4
1350 */
1351 public static long getFragmentInHours(Date date, int fragment) {
1352 return getFragment(date, fragment, Calendar.HOUR_OF_DAY);
1353 }
1354
1355 /**
1356 * <p>Returns the number of days within the
1357 * fragment. All datefields greater than the fragment will be ignored.</p>
1358 *
1359 * <p>Asking the days of any date will only return the number of days
1360 * of the current month (resulting in a number between 1 and 31). This
1361 * method will retrieve the number of days for any fragment.
1362 * For example, if you want to calculate the number of days past this year,
1363 * your fragment is Calendar.YEAR. The result will be all days of the
1364 * past month(s).</p>
1365 *
1366 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
1367 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
1368 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
1369 * A fragment less than or equal to a DAY field will return 0.</p>
1370 *
1371 * <p>
1372 * <ul>
1373 * <li>January 28, 2008 with Calendar.MONTH as fragment will return 28
1374 * (equivalent to deprecated date.getDay())</li>
1375 * <li>February 28, 2008 with Calendar.MONTH as fragment will return 28
1376 * (equivalent to deprecated date.getDay())</li>
1377 * <li>January 28, 2008 with Calendar.YEAR as fragment will return 28</li>
1378 * <li>February 28, 2008 with Calendar.YEAR as fragment will return 59</li>
1379 * <li>January 28, 2008 with Calendar.MILLISECOND as fragment will return 0
1380 * (a millisecond cannot be split in days)</li>
1381 * </ul>
1382 * </p>
1383 *
1384 * @param date the date to work with, not null
1385 * @param fragment the {@code Calendar} field part of date to calculate
1386 * @return number of days within the fragment of date
1387 * @throws IllegalArgumentException if the date is <code>null</code> or
1388 * fragment is not supported
1389 * @since 2.4
1390 */
1391 public static long getFragmentInDays(Date date, int fragment) {
1392 return getFragment(date, fragment, Calendar.DAY_OF_YEAR);
1393 }
1394
1395 /**
1396 * <p>Returns the number of milliseconds within the
1397 * fragment. All datefields greater than the fragment will be ignored.</p>
1398 *
1399 * <p>Asking the milliseconds of any date will only return the number of milliseconds
1400 * of the current second (resulting in a number between 0 and 999). This
1401 * method will retrieve the number of milliseconds for any fragment.
1402 * For example, if you want to calculate the number of seconds past today,
1403 * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will
1404 * be all seconds of the past hour(s), minutes(s) and second(s).</p>
1405 *
1406 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
1407 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
1408 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
1409 * A fragment less than or equal to a MILLISECOND field will return 0.</p>
1410 *
1411 * <p>
1412 * <ul>
1413 * <li>January 1, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538
1414 * (equivalent to calendar.get(Calendar.MILLISECOND))</li>
1415 * <li>January 6, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538
1416 * (equivalent to calendar.get(Calendar.MILLISECOND))</li>
1417 * <li>January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10538
1418 * (10*1000 + 538)</li>
1419 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
1420 * (a millisecond cannot be split in milliseconds)</li>
1421 * </ul>
1422 * </p>
1423 *
1424 * @param calendar the calendar to work with, not null
1425 * @param fragment the {@code Calendar} field part of calendar to calculate
1426 * @return number of milliseconds within the fragment of date
1427 * @throws IllegalArgumentException if the date is <code>null</code> or
1428 * fragment is not supported
1429 * @since 2.4
1430 */
1431 public static long getFragmentInMilliseconds(Calendar calendar, int fragment) {
1432 return getFragment(calendar, fragment, Calendar.MILLISECOND);
1433 }
1434 /**
1435 * <p>Returns the number of seconds within the
1436 * fragment. All datefields greater than the fragment will be ignored.</p>
1437 *
1438 * <p>Asking the seconds of any date will only return the number of seconds
1439 * of the current minute (resulting in a number between 0 and 59). This
1440 * method will retrieve the number of seconds for any fragment.
1441 * For example, if you want to calculate the number of seconds past today,
1442 * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will
1443 * be all seconds of the past hour(s) and minutes(s).</p>
1444 *
1445 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
1446 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
1447 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
1448 * A fragment less than or equal to a SECOND field will return 0.</p>
1449 *
1450 * <p>
1451 * <ul>
1452 * <li>January 1, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10
1453 * (equivalent to calendar.get(Calendar.SECOND))</li>
1454 * <li>January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10
1455 * (equivalent to calendar.get(Calendar.SECOND))</li>
1456 * <li>January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 26110
1457 * (7*3600 + 15*60 + 10)</li>
1458 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
1459 * (a millisecond cannot be split in seconds)</li>
1460 * </ul>
1461 * </p>
1462 *
1463 * @param calendar the calendar to work with, not null
1464 * @param fragment the {@code Calendar} field part of calendar to calculate
1465 * @return number of seconds within the fragment of date
1466 * @throws IllegalArgumentException if the date is <code>null</code> or
1467 * fragment is not supported
1468 * @since 2.4
1469 */
1470 public static long getFragmentInSeconds(Calendar calendar, int fragment) {
1471 return getFragment(calendar, fragment, Calendar.SECOND);
1472 }
1473
1474 /**
1475 * <p>Returns the number of minutes within the
1476 * fragment. All datefields greater than the fragment will be ignored.</p>
1477 *
1478 * <p>Asking the minutes of any date will only return the number of minutes
1479 * of the current hour (resulting in a number between 0 and 59). This
1480 * method will retrieve the number of minutes for any fragment.
1481 * For example, if you want to calculate the number of minutes past this month,
1482 * your fragment is Calendar.MONTH. The result will be all minutes of the
1483 * past day(s) and hour(s).</p>
1484 *
1485 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
1486 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
1487 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
1488 * A fragment less than or equal to a MINUTE field will return 0.</p>
1489 *
1490 * <p>
1491 * <ul>
1492 * <li>January 1, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15
1493 * (equivalent to calendar.get(Calendar.MINUTES))</li>
1494 * <li>January 6, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15
1495 * (equivalent to calendar.get(Calendar.MINUTES))</li>
1496 * <li>January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 15</li>
1497 * <li>January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 435 (7*60 + 15)</li>
1498 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
1499 * (a millisecond cannot be split in minutes)</li>
1500 * </ul>
1501 * </p>
1502 *
1503 * @param calendar the calendar to work with, not null
1504 * @param fragment the {@code Calendar} field part of calendar to calculate
1505 * @return number of minutes within the fragment of date
1506 * @throws IllegalArgumentException if the date is <code>null</code> or
1507 * fragment is not supported
1508 * @since 2.4
1509 */
1510 public static long getFragmentInMinutes(Calendar calendar, int fragment) {
1511 return getFragment(calendar, fragment, Calendar.MINUTE);
1512 }
1513
1514 /**
1515 * <p>Returns the number of hours within the
1516 * fragment. All datefields greater than the fragment will be ignored.</p>
1517 *
1518 * <p>Asking the hours of any date will only return the number of hours
1519 * of the current day (resulting in a number between 0 and 23). This
1520 * method will retrieve the number of hours for any fragment.
1521 * For example, if you want to calculate the number of hours past this month,
1522 * your fragment is Calendar.MONTH. The result will be all hours of the
1523 * past day(s).</p>
1524 *
1525 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
1526 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
1527 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
1528 * A fragment less than or equal to a HOUR field will return 0.</p>
1529 *
1530 * <p>
1531 * <ul>
1532 * <li>January 1, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7
1533 * (equivalent to calendar.get(Calendar.HOUR_OF_DAY))</li>
1534 * <li>January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7
1535 * (equivalent to calendar.get(Calendar.HOUR_OF_DAY))</li>
1536 * <li>January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 7</li>
1537 * <li>January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 127 (5*24 + 7)</li>
1538 * <li>January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0
1539 * (a millisecond cannot be split in hours)</li>
1540 * </ul>
1541 * </p>
1542 *
1543 * @param calendar the calendar to work with, not null
1544 * @param fragment the {@code Calendar} field part of calendar to calculate
1545 * @return number of hours within the fragment of date
1546 * @throws IllegalArgumentException if the date is <code>null</code> or
1547 * fragment is not supported
1548 * @since 2.4
1549 */
1550 public static long getFragmentInHours(Calendar calendar, int fragment) {
1551 return getFragment(calendar, fragment, Calendar.HOUR_OF_DAY);
1552 }
1553
1554 /**
1555 * <p>Returns the number of days within the
1556 * fragment. All datefields greater than the fragment will be ignored.</p>
1557 *
1558 * <p>Asking the days of any date will only return the number of days
1559 * of the current month (resulting in a number between 1 and 31). This
1560 * method will retrieve the number of days for any fragment.
1561 * For example, if you want to calculate the number of days past this year,
1562 * your fragment is Calendar.YEAR. The result will be all days of the
1563 * past month(s).</p>
1564 *
1565 * <p>Valid fragments are: Calendar.YEAR, Calendar.MONTH, both
1566 * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY,
1567 * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND
1568 * A fragment less than or equal to a DAY field will return 0.</p>
1569 *
1570 * <p>
1571 * <ul>
1572 * <li>January 28, 2008 with Calendar.MONTH as fragment will return 28
1573 * (equivalent to calendar.get(Calendar.DAY_OF_MONTH))</li>
1574 * <li>February 28, 2008 with Calendar.MONTH as fragment will return 28
1575 * (equivalent to calendar.get(Calendar.DAY_OF_MONTH))</li>
1576 * <li>January 28, 2008 with Calendar.YEAR as fragment will return 28
1577 * (equivalent to calendar.get(Calendar.DAY_OF_YEAR))</li>
1578 * <li>February 28, 2008 with Calendar.YEAR as fragment will return 59
1579 * (equivalent to calendar.get(Calendar.DAY_OF_YEAR))</li>
1580 * <li>January 28, 2008 with Calendar.MILLISECOND as fragment will return 0
1581 * (a millisecond cannot be split in days)</li>
1582 * </ul>
1583 * </p>
1584 *
1585 * @param calendar the calendar to work with, not null
1586 * @param fragment the {@code Calendar} field part of calendar to calculate
1587 * @return number of days within the fragment of date
1588 * @throws IllegalArgumentException if the date is <code>null</code> or
1589 * fragment is not supported
1590 * @since 2.4
1591 */
1592 public static long getFragmentInDays(Calendar calendar, int fragment) {
1593 return getFragment(calendar, fragment, Calendar.DAY_OF_YEAR);
1594 }
1595
1596 /**
1597 * Date-version for fragment-calculation in any unit
1598 *
1599 * @param date the date to work with, not null
1600 * @param fragment the Calendar field part of date to calculate
1601 * @param unit the {@code Calendar} field defining the unit
1602 * @return number of units within the fragment of the date
1603 * @throws IllegalArgumentException if the date is <code>null</code> or
1604 * fragment is not supported
1605 * @since 2.4
1606 */
1607 private static long getFragment(Date date, int fragment, int unit) {
1608 if(date == null) {
1609 throw new IllegalArgumentException("The date must not be null");
1610 }
1611 Calendar calendar = Calendar.getInstance();
1612 calendar.setTime(date);
1613 return getFragment(calendar, fragment, unit);
1614 }
1615
1616 /**
1617 * Calendar-version for fragment-calculation in any unit
1618 *
1619 * @param calendar the calendar to work with, not null
1620 * @param fragment the Calendar field part of calendar to calculate
1621 * @param unit the {@code Calendar} field defining the unit
1622 * @return number of units within the fragment of the calendar
1623 * @throws IllegalArgumentException if the date is <code>null</code> or
1624 * fragment is not supported
1625 * @since 2.4
1626 */
1627 private static long getFragment(Calendar calendar, int fragment, int unit) {
1628 if(calendar == null) {
1629 throw new IllegalArgumentException("The date must not be null");
1630 }
1631 long millisPerUnit = getMillisPerUnit(unit);
1632 long result = 0;
1633
1634 // Fragments bigger than a day require a breakdown to days
1635 switch (fragment) {
1636 case Calendar.YEAR:
1637 result += (calendar.get(Calendar.DAY_OF_YEAR) * MILLIS_PER_DAY) / millisPerUnit;
1638 break;
1639 case Calendar.MONTH:
1640 result += (calendar.get(Calendar.DAY_OF_MONTH) * MILLIS_PER_DAY) / millisPerUnit;
1641 break;
1642 }
1643
1644 switch (fragment) {
1645 // Number of days already calculated for these cases
1646 case Calendar.YEAR:
1647 case Calendar.MONTH:
1648
1649 // The rest of the valid cases
1650 case Calendar.DAY_OF_YEAR:
1651 case Calendar.DATE:
1652 result += (calendar.get(Calendar.HOUR_OF_DAY) * MILLIS_PER_HOUR) / millisPerUnit;
1653 //$FALL-THROUGH$
1654 case Calendar.HOUR_OF_DAY:
1655 result += (calendar.get(Calendar.MINUTE) * MILLIS_PER_MINUTE) / millisPerUnit;
1656 //$FALL-THROUGH$
1657 case Calendar.MINUTE:
1658 result += (calendar.get(Calendar.SECOND) * MILLIS_PER_SECOND) / millisPerUnit;
1659 //$FALL-THROUGH$
1660 case Calendar.SECOND:
1661 result += (calendar.get(Calendar.MILLISECOND) * 1) / millisPerUnit;
1662 break;
1663 case Calendar.MILLISECOND: break;//never useful
1664 default: throw new IllegalArgumentException("The fragment " + fragment + " is not supported");
1665 }
1666 return result;
1667 }
1668
1669 /**
1670 * Determines if two calendars are equal up to no more than the specified
1671 * most significant field.
1672 *
1673 * @param cal1 the first calendar, not <code>null</code>
1674 * @param cal2 the second calendar, not <code>null</code>
1675 * @param field the field from {@code Calendar}
1676 * @return <code>true</code> if equal; otherwise <code>false</code>
1677 * @throws IllegalArgumentException if any argument is <code>null</code>
1678 * @see #truncate(Calendar, int)
1679 * @see #truncatedEquals(Date, Date, int)
1680 * @since 3.0
1681 */
1682 public static boolean truncatedEquals(Calendar cal1, Calendar cal2, int field) {
1683 return truncatedCompareTo(cal1, cal2, field) == 0;
1684 }
1685
1686 /**
1687 * Determines if two dates are equal up to no more than the specified
1688 * most significant field.
1689 *
1690 * @param date1 the first date, not <code>null</code>
1691 * @param date2 the second date, not <code>null</code>
1692 * @param field the field from {@code Calendar}
1693 * @return <code>true</code> if equal; otherwise <code>false</code>
1694 * @throws IllegalArgumentException if any argument is <code>null</code>
1695 * @see #truncate(Date, int)
1696 * @see #truncatedEquals(Calendar, Calendar, int)
1697 * @since 3.0
1698 */
1699 public static boolean truncatedEquals(Date date1, Date date2, int field) {
1700 return truncatedCompareTo(date1, date2, field) == 0;
1701 }
1702
1703 /**
1704 * Determines how two calendars compare up to no more than the specified
1705 * most significant field.
1706 *
1707 * @param cal1 the first calendar, not <code>null</code>
1708 * @param cal2 the second calendar, not <code>null</code>
1709 * @param field the field from {@code Calendar}
1710 * @return a negative integer, zero, or a positive integer as the first
1711 * calendar is less than, equal to, or greater than the second.
1712 * @throws IllegalArgumentException if any argument is <code>null</code>
1713 * @see #truncate(Calendar, int)
1714 * @see #truncatedCompareTo(Date, Date, int)
1715 * @since 3.0
1716 */
1717 public static int truncatedCompareTo(Calendar cal1, Calendar cal2, int field) {
1718 Calendar truncatedCal1 = truncate(cal1, field);
1719 Calendar truncatedCal2 = truncate(cal2, field);
1720 return truncatedCal1.compareTo(truncatedCal2);
1721 }
1722
1723 /**
1724 * Determines how two dates compare up to no more than the specified
1725 * most significant field.
1726 *
1727 * @param date1 the first date, not <code>null</code>
1728 * @param date2 the second date, not <code>null</code>
1729 * @param field the field from <code>Calendar</code>
1730 * @return a negative integer, zero, or a positive integer as the first
1731 * date is less than, equal to, or greater than the second.
1732 * @throws IllegalArgumentException if any argument is <code>null</code>
1733 * @see #truncate(Calendar, int)
1734 * @see #truncatedCompareTo(Date, Date, int)
1735 * @since 3.0
1736 */
1737 public static int truncatedCompareTo(Date date1, Date date2, int field) {
1738 Date truncatedDate1 = truncate(date1, field);
1739 Date truncatedDate2 = truncate(date2, field);
1740 return truncatedDate1.compareTo(truncatedDate2);
1741 }
1742
1743 /**
1744 * Returns the number of milliseconds of a {@code Calendar} field, if this is a constant value.
1745 * This handles millisecond, second, minute, hour and day (even though days can very in length).
1746 *
1747 * @param unit a {@code Calendar} field constant which is a valid unit for a fragment
1748 * @return the number of milliseconds in the field
1749 * @throws IllegalArgumentException if date can't be represented in milliseconds
1750 * @since 2.4
1751 */
1752 private static long getMillisPerUnit(int unit) {
1753 long result = Long.MAX_VALUE;
1754 switch (unit) {
1755 case Calendar.DAY_OF_YEAR:
1756 case Calendar.DATE:
1757 result = MILLIS_PER_DAY;
1758 break;
1759 case Calendar.HOUR_OF_DAY:
1760 result = MILLIS_PER_HOUR;
1761 break;
1762 case Calendar.MINUTE:
1763 result = MILLIS_PER_MINUTE;
1764 break;
1765 case Calendar.SECOND:
1766 result = MILLIS_PER_SECOND;
1767 break;
1768 case Calendar.MILLISECOND:
1769 result = 1;
1770 break;
1771 default: throw new IllegalArgumentException("The unit " + unit + " cannot be represented is milleseconds");
1772 }
1773 return result;
1774 }
1775
1776 //-----------------------------------------------------------------------
1777 /**
1778 * <p>Date iterator.</p>
1779 */
1780 static class DateIterator implements Iterator<Calendar> {
1781 private final Calendar endFinal;
1782 private final Calendar spot;
1783
1784 /**
1785 * Constructs a DateIterator that ranges from one date to another.
1786 *
1787 * @param startFinal start date (inclusive)
1788 * @param endFinal end date (not inclusive)
1789 */
1790 DateIterator(Calendar startFinal, Calendar endFinal) {
1791 super();
1792 this.endFinal = endFinal;
1793 spot = startFinal;
1794 spot.add(Calendar.DATE, -1);
1795 }
1796
1797 /**
1798 * Has the iterator not reached the end date yet?
1799 *
1800 * @return <code>true</code> if the iterator has yet to reach the end date
1801 */
1802 public boolean hasNext() {
1803 return spot.before(endFinal);
1804 }
1805
1806 /**
1807 * Return the next calendar in the iteration
1808 *
1809 * @return Object calendar for the next date
1810 */
1811 public Calendar next() {
1812 if (spot.equals(endFinal)) {
1813 throw new NoSuchElementException();
1814 }
1815 spot.add(Calendar.DATE, 1);
1816 return (Calendar) spot.clone();
1817 }
1818
1819 /**
1820 * Always throws UnsupportedOperationException.
1821 *
1822 * @throws UnsupportedOperationException
1823 * @see java.util.Iterator#remove()
1824 */
1825 public void remove() {
1826 throw new UnsupportedOperationException();
1827 }
1828 }
1829
1830 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import java.util.ArrayList;
19 import java.util.Calendar;
20 import java.util.Date;
21 import java.util.GregorianCalendar;
22 import java.util.TimeZone;
23
24 import org.apache.commons.lang3.StringUtils;
25
26 /**
27 * <p>Duration formatting utilities and constants. The following table describes the tokens
28 * used in the pattern language for formatting. </p>
29 * <table border="1">
30 * <tr><th>character</th><th>duration element</th></tr>
31 * <tr><td>y</td><td>years</td></tr>
32 * <tr><td>M</td><td>months</td></tr>
33 * <tr><td>d</td><td>days</td></tr>
34 * <tr><td>H</td><td>hours</td></tr>
35 * <tr><td>m</td><td>minutes</td></tr>
36 * <tr><td>s</td><td>seconds</td></tr>
37 * <tr><td>S</td><td>milliseconds</td></tr>
38 * </table>
39 *
40 * @since 2.1
41 * @version $Id: DurationFormatUtils.java 1144993 2011-07-11 00:51:16Z ggregory $
42 */
43 public class DurationFormatUtils {
44
45 /**
46 * <p>DurationFormatUtils instances should NOT be constructed in standard programming.</p>
47 *
48 * <p>This constructor is public to permit tools that require a JavaBean instance
49 * to operate.</p>
50 */
51 public DurationFormatUtils() {
52 super();
53 }
54
55 /**
56 * <p>Pattern used with <code>FastDateFormat</code> and <code>SimpleDateFormat</code>
57 * for the ISO8601 period format used in durations.</p>
58 *
59 * @see org.apache.commons.lang3.time.FastDateFormat
60 * @see java.text.SimpleDateFormat
61 */
62 public static final String ISO_EXTENDED_FORMAT_PATTERN = "'P'yyyy'Y'M'M'd'DT'H'H'm'M's.S'S'";
63
64 //-----------------------------------------------------------------------
65 /**
66 * <p>Formats the time gap as a string.</p>
67 *
68 * <p>The format used is ISO8601-like:
69 * <i>H</i>:<i>m</i>:<i>s</i>.<i>S</i>.</p>
70 *
71 * @param durationMillis the duration to format
72 * @return the formatted duration, not null
73 */
74 public static String formatDurationHMS(long durationMillis) {
75 return formatDuration(durationMillis, "H:mm:ss.SSS");
76 }
77
78 /**
79 * <p>Formats the time gap as a string.</p>
80 *
81 * <p>The format used is the ISO8601 period format.</p>
82 *
83 * <p>This method formats durations using the days and lower fields of the
84 * ISO format pattern, such as P7D6TH5M4.321S.</p>
85 *
86 * @param durationMillis the duration to format
87 * @return the formatted duration, not null
88 */
89 public static String formatDurationISO(long durationMillis) {
90 return formatDuration(durationMillis, ISO_EXTENDED_FORMAT_PATTERN, false);
91 }
92
93 /**
94 * <p>Formats the time gap as a string, using the specified format, and padding with zeros and
95 * using the default timezone.</p>
96 *
97 * <p>This method formats durations using the days and lower fields of the
98 * format pattern. Months and larger are not used.</p>
99 *
100 * @param durationMillis the duration to format
101 * @param format the way in which to format the duration, not null
102 * @return the formatted duration, not null
103 */
104 public static String formatDuration(long durationMillis, String format) {
105 return formatDuration(durationMillis, format, true);
106 }
107
108 /**
109 * <p>Formats the time gap as a string, using the specified format.
110 * Padding the left hand side of numbers with zeroes is optional and
111 * the timezone may be specified.</p>
112 *
113 * <p>This method formats durations using the days and lower fields of the
114 * format pattern. Months and larger are not used.</p>
115 *
116 * @param durationMillis the duration to format
117 * @param format the way in which to format the duration, not null
118 * @param padWithZeros whether to pad the left hand side of numbers with 0's
119 * @return the formatted duration, not null
120 */
121 public static String formatDuration(long durationMillis, String format, boolean padWithZeros) {
122
123 Token[] tokens = lexx(format);
124
125 int days = 0;
126 int hours = 0;
127 int minutes = 0;
128 int seconds = 0;
129 int milliseconds = 0;
130
131 if (Token.containsTokenWithValue(tokens, d) ) {
132 days = (int) (durationMillis / DateUtils.MILLIS_PER_DAY);
133 durationMillis = durationMillis - (days * DateUtils.MILLIS_PER_DAY);
134 }
135 if (Token.containsTokenWithValue(tokens, H) ) {
136 hours = (int) (durationMillis / DateUtils.MILLIS_PER_HOUR);
137 durationMillis = durationMillis - (hours * DateUtils.MILLIS_PER_HOUR);
138 }
139 if (Token.containsTokenWithValue(tokens, m) ) {
140 minutes = (int) (durationMillis / DateUtils.MILLIS_PER_MINUTE);
141 durationMillis = durationMillis - (minutes * DateUtils.MILLIS_PER_MINUTE);
142 }
143 if (Token.containsTokenWithValue(tokens, s) ) {
144 seconds = (int) (durationMillis / DateUtils.MILLIS_PER_SECOND);
145 durationMillis = durationMillis - (seconds * DateUtils.MILLIS_PER_SECOND);
146 }
147 if (Token.containsTokenWithValue(tokens, S) ) {
148 milliseconds = (int) durationMillis;
149 }
150
151 return format(tokens, 0, 0, days, hours, minutes, seconds, milliseconds, padWithZeros);
152 }
153
154 /**
155 * <p>Formats an elapsed time into a plurialization correct string.</p>
156 *
157 * <p>This method formats durations using the days and lower fields of the
158 * format pattern. Months and larger are not used.</p>
159 *
160 * @param durationMillis the elapsed time to report in milliseconds
161 * @param suppressLeadingZeroElements suppresses leading 0 elements
162 * @param suppressTrailingZeroElements suppresses trailing 0 elements
163 * @return the formatted text in days/hours/minutes/seconds, not null
164 */
165 public static String formatDurationWords(
166 long durationMillis,
167 boolean suppressLeadingZeroElements,
168 boolean suppressTrailingZeroElements) {
169
170 // This method is generally replacable by the format method, but
171 // there are a series of tweaks and special cases that require
172 // trickery to replicate.
173 String duration = formatDuration(durationMillis, "d' days 'H' hours 'm' minutes 's' seconds'");
174 if (suppressLeadingZeroElements) {
175 // this is a temporary marker on the front. Like ^ in regexp.
176 duration = " " + duration;
177 String tmp = StringUtils.replaceOnce(duration, " 0 days", "");
178 if (tmp.length() != duration.length()) {
179 duration = tmp;
180 tmp = StringUtils.replaceOnce(duration, " 0 hours", "");
181 if (tmp.length() != duration.length()) {
182 duration = tmp;
183 tmp = StringUtils.replaceOnce(duration, " 0 minutes", "");
184 duration = tmp;
185 if (tmp.length() != duration.length()) {
186 duration = StringUtils.replaceOnce(tmp, " 0 seconds", "");
187 }
188 }
189 }
190 if (duration.length() != 0) {
191 // strip the space off again
192 duration = duration.substring(1);
193 }
194 }
195 if (suppressTrailingZeroElements) {
196 String tmp = StringUtils.replaceOnce(duration, " 0 seconds", "");
197 if (tmp.length() != duration.length()) {
198 duration = tmp;
199 tmp = StringUtils.replaceOnce(duration, " 0 minutes", "");
200 if (tmp.length() != duration.length()) {
201 duration = tmp;
202 tmp = StringUtils.replaceOnce(duration, " 0 hours", "");
203 if (tmp.length() != duration.length()) {
204 duration = StringUtils.replaceOnce(tmp, " 0 days", "");
205 }
206 }
207 }
208 }
209 // handle plurals
210 duration = " " + duration;
211 duration = StringUtils.replaceOnce(duration, " 1 seconds", " 1 second");
212 duration = StringUtils.replaceOnce(duration, " 1 minutes", " 1 minute");
213 duration = StringUtils.replaceOnce(duration, " 1 hours", " 1 hour");
214 duration = StringUtils.replaceOnce(duration, " 1 days", " 1 day");
215 return duration.trim();
216 }
217
218 //-----------------------------------------------------------------------
219 /**
220 * <p>Formats the time gap as a string.</p>
221 *
222 * <p>The format used is the ISO8601 period format.</p>
223 *
224 * @param startMillis the start of the duration to format
225 * @param endMillis the end of the duration to format
226 * @return the formatted duration, not null
227 */
228 public static String formatPeriodISO(long startMillis, long endMillis) {
229 return formatPeriod(startMillis, endMillis, ISO_EXTENDED_FORMAT_PATTERN, false, TimeZone.getDefault());
230 }
231
232 /**
233 * <p>Formats the time gap as a string, using the specified format.
234 * Padding the left hand side of numbers with zeroes is optional.
235 *
236 * @param startMillis the start of the duration
237 * @param endMillis the end of the duration
238 * @param format the way in which to format the duration, not null
239 * @return the formatted duration, not null
240 */
241 public static String formatPeriod(long startMillis, long endMillis, String format) {
242 return formatPeriod(startMillis, endMillis, format, true, TimeZone.getDefault());
243 }
244
245 /**
246 * <p>Formats the time gap as a string, using the specified format.
247 * Padding the left hand side of numbers with zeroes is optional and
248 * the timezone may be specified. </p>
249 *
250 * <p>When calculating the difference between months/days, it chooses to
251 * calculate months first. So when working out the number of months and
252 * days between January 15th and March 10th, it choose 1 month and
253 * 23 days gained by choosing January->February = 1 month and then
254 * calculating days forwards, and not the 1 month and 26 days gained by
255 * choosing March -> February = 1 month and then calculating days
256 * backwards. </p>
257 *
258 * <p>For more control, the <a href="http://joda-time.sf.net/">Joda-Time</a>
259 * library is recommended.</p>
260 *
261 * @param startMillis the start of the duration
262 * @param endMillis the end of the duration
263 * @param format the way in which to format the duration, not null
264 * @param padWithZeros whether to pad the left hand side of numbers with 0's
265 * @param timezone the millis are defined in
266 * @return the formatted duration, not null
267 */
268 public static String formatPeriod(long startMillis, long endMillis, String format, boolean padWithZeros,
269 TimeZone timezone) {
270
271 // Used to optimise for differences under 28 days and
272 // called formatDuration(millis, format); however this did not work
273 // over leap years.
274 // TODO: Compare performance to see if anything was lost by
275 // losing this optimisation.
276
277 Token[] tokens = lexx(format);
278
279 // timezones get funky around 0, so normalizing everything to GMT
280 // stops the hours being off
281 Calendar start = Calendar.getInstance(timezone);
282 start.setTime(new Date(startMillis));
283 Calendar end = Calendar.getInstance(timezone);
284 end.setTime(new Date(endMillis));
285
286 // initial estimates
287 int milliseconds = end.get(Calendar.MILLISECOND) - start.get(Calendar.MILLISECOND);
288 int seconds = end.get(Calendar.SECOND) - start.get(Calendar.SECOND);
289 int minutes = end.get(Calendar.MINUTE) - start.get(Calendar.MINUTE);
290 int hours = end.get(Calendar.HOUR_OF_DAY) - start.get(Calendar.HOUR_OF_DAY);
291 int days = end.get(Calendar.DAY_OF_MONTH) - start.get(Calendar.DAY_OF_MONTH);
292 int months = end.get(Calendar.MONTH) - start.get(Calendar.MONTH);
293 int years = end.get(Calendar.YEAR) - start.get(Calendar.YEAR);
294
295 // each initial estimate is adjusted in case it is under 0
296 while (milliseconds < 0) {
297 milliseconds += 1000;
298 seconds -= 1;
299 }
300 while (seconds < 0) {
301 seconds += 60;
302 minutes -= 1;
303 }
304 while (minutes < 0) {
305 minutes += 60;
306 hours -= 1;
307 }
308 while (hours < 0) {
309 hours += 24;
310 days -= 1;
311 }
312
313 if (Token.containsTokenWithValue(tokens, M)) {
314 while (days < 0) {
315 days += start.getActualMaximum(Calendar.DAY_OF_MONTH);
316 months -= 1;
317 start.add(Calendar.MONTH, 1);
318 }
319
320 while (months < 0) {
321 months += 12;
322 years -= 1;
323 }
324
325 if (!Token.containsTokenWithValue(tokens, y) && years != 0) {
326 while (years != 0) {
327 months += 12 * years;
328 years = 0;
329 }
330 }
331 } else {
332 // there are no M's in the format string
333
334 if( !Token.containsTokenWithValue(tokens, y) ) {
335 int target = end.get(Calendar.YEAR);
336 if (months < 0) {
337 // target is end-year -1
338 target -= 1;
339 }
340
341 while ( (start.get(Calendar.YEAR) != target)) {
342 days += start.getActualMaximum(Calendar.DAY_OF_YEAR) - start.get(Calendar.DAY_OF_YEAR);
343
344 // Not sure I grok why this is needed, but the brutal tests show it is
345 if (start instanceof GregorianCalendar &&
346 start.get(Calendar.MONTH) == Calendar.FEBRUARY &&
347 start.get(Calendar.DAY_OF_MONTH) == 29) {
348 days += 1;
349 }
350
351 start.add(Calendar.YEAR, 1);
352
353 days += start.get(Calendar.DAY_OF_YEAR);
354 }
355
356 years = 0;
357 }
358
359 while( start.get(Calendar.MONTH) != end.get(Calendar.MONTH) ) {
360 days += start.getActualMaximum(Calendar.DAY_OF_MONTH);
361 start.add(Calendar.MONTH, 1);
362 }
363
364 months = 0;
365
366 while (days < 0) {
367 days += start.getActualMaximum(Calendar.DAY_OF_MONTH);
368 months -= 1;
369 start.add(Calendar.MONTH, 1);
370 }
371
372 }
373
374 // The rest of this code adds in values that
375 // aren't requested. This allows the user to ask for the
376 // number of months and get the real count and not just 0->11.
377
378 if (!Token.containsTokenWithValue(tokens, d)) {
379 hours += 24 * days;
380 days = 0;
381 }
382 if (!Token.containsTokenWithValue(tokens, H)) {
383 minutes += 60 * hours;
384 hours = 0;
385 }
386 if (!Token.containsTokenWithValue(tokens, m)) {
387 seconds += 60 * minutes;
388 minutes = 0;
389 }
390 if (!Token.containsTokenWithValue(tokens, s)) {
391 milliseconds += 1000 * seconds;
392 seconds = 0;
393 }
394
395 return format(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros);
396 }
397
398 //-----------------------------------------------------------------------
399 /**
400 * <p>The internal method to do the formatting.</p>
401 *
402 * @param tokens the tokens
403 * @param years the number of years
404 * @param months the number of months
405 * @param days the number of days
406 * @param hours the number of hours
407 * @param minutes the number of minutes
408 * @param seconds the number of seconds
409 * @param milliseconds the number of millis
410 * @param padWithZeros whether to pad
411 * @return the formatted string
412 */
413 static String format(Token[] tokens, int years, int months, int days, int hours, int minutes, int seconds,
414 int milliseconds, boolean padWithZeros) {
415 StringBuffer buffer = new StringBuffer();
416 boolean lastOutputSeconds = false;
417 int sz = tokens.length;
418 for (int i = 0; i < sz; i++) {
419 Token token = tokens[i];
420 Object value = token.getValue();
421 int count = token.getCount();
422 if (value instanceof StringBuffer) {
423 buffer.append(value.toString());
424 } else {
425 if (value == y) {
426 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(years), count, '0') : Integer
427 .toString(years));
428 lastOutputSeconds = false;
429 } else if (value == M) {
430 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(months), count, '0') : Integer
431 .toString(months));
432 lastOutputSeconds = false;
433 } else if (value == d) {
434 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(days), count, '0') : Integer
435 .toString(days));
436 lastOutputSeconds = false;
437 } else if (value == H) {
438 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(hours), count, '0') : Integer
439 .toString(hours));
440 lastOutputSeconds = false;
441 } else if (value == m) {
442 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(minutes), count, '0') : Integer
443 .toString(minutes));
444 lastOutputSeconds = false;
445 } else if (value == s) {
446 buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(seconds), count, '0') : Integer
447 .toString(seconds));
448 lastOutputSeconds = true;
449 } else if (value == S) {
450 if (lastOutputSeconds) {
451 milliseconds += 1000;
452 String str = padWithZeros
453 ? StringUtils.leftPad(Integer.toString(milliseconds), count, '0')
454 : Integer.toString(milliseconds);
455 buffer.append(str.substring(1));
456 } else {
457 buffer.append(padWithZeros
458 ? StringUtils.leftPad(Integer.toString(milliseconds), count, '0')
459 : Integer.toString(milliseconds));
460 }
461 lastOutputSeconds = false;
462 }
463 }
464 }
465 return buffer.toString();
466 }
467
468 static final Object y = "y";
469 static final Object M = "M";
470 static final Object d = "d";
471 static final Object H = "H";
472 static final Object m = "m";
473 static final Object s = "s";
474 static final Object S = "S";
475
476 /**
477 * Parses a classic date format string into Tokens
478 *
479 * @param format the format to parse, not null
480 * @return array of Token[]
481 */
482 static Token[] lexx(String format) {
483 char[] array = format.toCharArray();
484 ArrayList<Token> list = new ArrayList<Token>(array.length);
485
486 boolean inLiteral = false;
487 StringBuffer buffer = null;
488 Token previous = null;
489 int sz = array.length;
490 for(int i=0; i<sz; i++) {
491 char ch = array[i];
492 if(inLiteral && ch != '\'') {
493 buffer.append(ch); // buffer can't be null if inLiteral is true
494 continue;
495 }
496 Object value = null;
497 switch(ch) {
498 // TODO: Need to handle escaping of '
499 case '\'' :
500 if(inLiteral) {
501 buffer = null;
502 inLiteral = false;
503 } else {
504 buffer = new StringBuffer();
505 list.add(new Token(buffer));
506 inLiteral = true;
507 }
508 break;
509 case 'y' : value = y; break;
510 case 'M' : value = M; break;
511 case 'd' : value = d; break;
512 case 'H' : value = H; break;
513 case 'm' : value = m; break;
514 case 's' : value = s; break;
515 case 'S' : value = S; break;
516 default :
517 if(buffer == null) {
518 buffer = new StringBuffer();
519 list.add(new Token(buffer));
520 }
521 buffer.append(ch);
522 }
523
524 if(value != null) {
525 if(previous != null && previous.getValue() == value) {
526 previous.increment();
527 } else {
528 Token token = new Token(value);
529 list.add(token);
530 previous = token;
531 }
532 buffer = null;
533 }
534 }
535 return list.toArray( new Token[list.size()] );
536 }
537
538 //-----------------------------------------------------------------------
539 /**
540 * Element that is parsed from the format pattern.
541 */
542 static class Token {
543
544 /**
545 * Helper method to determine if a set of tokens contain a value
546 *
547 * @param tokens set to look in
548 * @param value to look for
549 * @return boolean <code>true</code> if contained
550 */
551 static boolean containsTokenWithValue(Token[] tokens, Object value) {
552 int sz = tokens.length;
553 for (int i = 0; i < sz; i++) {
554 if (tokens[i].getValue() == value) {
555 return true;
556 }
557 }
558 return false;
559 }
560
561 private final Object value;
562 private int count;
563
564 /**
565 * Wraps a token around a value. A value would be something like a 'Y'.
566 *
567 * @param value to wrap
568 */
569 Token(Object value) {
570 this.value = value;
571 this.count = 1;
572 }
573
574 /**
575 * Wraps a token around a repeated number of a value, for example it would
576 * store 'yyyy' as a value for y and a count of 4.
577 *
578 * @param value to wrap
579 * @param count to wrap
580 */
581 Token(Object value, int count) {
582 this.value = value;
583 this.count = count;
584 }
585
586 /**
587 * Adds another one of the value
588 */
589 void increment() {
590 count++;
591 }
592
593 /**
594 * Gets the current number of values represented
595 *
596 * @return int number of values represented
597 */
598 int getCount() {
599 return count;
600 }
601
602 /**
603 * Gets the particular value this token represents.
604 *
605 * @return Object value
606 */
607 Object getValue() {
608 return value;
609 }
610
611 /**
612 * Supports equality of this Token to another Token.
613 *
614 * @param obj2 Object to consider equality of
615 * @return boolean <code>true</code> if equal
616 */
617 @Override
618 public boolean equals(Object obj2) {
619 if (obj2 instanceof Token) {
620 Token tok2 = (Token) obj2;
621 if (this.value.getClass() != tok2.value.getClass()) {
622 return false;
623 }
624 if (this.count != tok2.count) {
625 return false;
626 }
627 if (this.value instanceof StringBuffer) {
628 return this.value.toString().equals(tok2.value.toString());
629 } else if (this.value instanceof Number) {
630 return this.value.equals(tok2.value);
631 } else {
632 return this.value == tok2.value;
633 }
634 }
635 return false;
636 }
637
638 /**
639 * Returns a hash code for the token equal to the
640 * hash code for the token's value. Thus 'TT' and 'TTTT'
641 * will have the same hash code.
642 *
643 * @return The hash code for the token
644 */
645 @Override
646 public int hashCode() {
647 return this.value.hashCode();
648 }
649
650 /**
651 * Represents this token as a String.
652 *
653 * @return String representation of the token
654 */
655 @Override
656 public String toString() {
657 return StringUtils.repeat(this.value.toString(), this.count);
658 }
659 }
660
661 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import java.io.IOException;
19 import java.io.ObjectInputStream;
20 import java.text.DateFormat;
21 import java.text.DateFormatSymbols;
22 import java.text.FieldPosition;
23 import java.text.Format;
24 import java.text.ParsePosition;
25 import java.util.ArrayList;
26 import java.util.Calendar;
27 import java.util.Date;
28 import java.util.GregorianCalendar;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.TimeZone;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentMap;
34
35 import org.apache.commons.lang3.Validate;
36
37 /**
38 * <p>FastDateFormat is a fast and thread-safe version of
39 * {@link java.text.SimpleDateFormat}.</p>
40 *
41 * <p>This class can be used as a direct replacement to
42 * {@code SimpleDateFormat} in most formatting situations.
43 * This class is especially useful in multi-threaded server environments.
44 * {@code SimpleDateFormat} is not thread-safe in any JDK version,
45 * nor will it be as Sun have closed the bug/RFE.
46 * </p>
47 *
48 * <p>Only formatting is supported, but all patterns are compatible with
49 * SimpleDateFormat (except time zones and some year patterns - see below).</p>
50 *
51 * <p>Java 1.4 introduced a new pattern letter, {@code 'Z'}, to represent
52 * time zones in RFC822 format (eg. {@code +0800} or {@code -1100}).
53 * This pattern letter can be used here (on all JDK versions).</p>
54 *
55 * <p>In addition, the pattern {@code 'ZZ'} has been made to represent
56 * ISO8601 full format time zones (eg. {@code +08:00} or {@code -11:00}).
57 * This introduces a minor incompatibility with Java 1.4, but at a gain of
58 * useful functionality.</p>
59 *
60 * <p>Javadoc cites for the year pattern: <i>For formatting, if the number of
61 * pattern letters is 2, the year is truncated to 2 digits; otherwise it is
62 * interpreted as a number.</i> Starting with Java 1.7 a pattern of 'Y' or
63 * 'YYY' will be formatted as '2003', while it was '03' in former Java
64 * versions. FastDateFormat implements the behavior of Java 7.</p>
65 *
66 * @since 2.0
67 * @version $Id: FastDateFormat.java 1146138 2011-07-13 17:01:37Z joehni $
68 */
69 public class FastDateFormat extends Format {
70 // A lot of the speed in this class comes from caching, but some comes
71 // from the special int to StringBuffer conversion.
72 //
73 // The following produces a padded 2 digit number:
74 // buffer.append((char)(value / 10 + '0'));
75 // buffer.append((char)(value % 10 + '0'));
76 //
77 // Note that the fastest append to StringBuffer is a single char (used here).
78 // Note that Integer.toString() is not called, the conversion is simply
79 // taking the value and adding (mathematically) the ASCII value for '0'.
80 // So, don't change this code! It works and is very fast.
81
82 /**
83 * Required for serialization support.
84 *
85 * @see java.io.Serializable
86 */
87 private static final long serialVersionUID = 1L;
88
89 /**
90 * FULL locale dependent date or time style.
91 */
92 public static final int FULL = DateFormat.FULL;
93 /**
94 * LONG locale dependent date or time style.
95 */
96 public static final int LONG = DateFormat.LONG;
97 /**
98 * MEDIUM locale dependent date or time style.
99 */
100 public static final int MEDIUM = DateFormat.MEDIUM;
101 /**
102 * SHORT locale dependent date or time style.
103 */
104 public static final int SHORT = DateFormat.SHORT;
105
106 private static final FormatCache<FastDateFormat> cache= new FormatCache<FastDateFormat>() {
107 @Override
108 protected FastDateFormat createInstance(String pattern, TimeZone timeZone, Locale locale) {
109 return new FastDateFormat(pattern, timeZone, locale);
110 }
111 };
112
113 private static ConcurrentMap<TimeZoneDisplayKey, String> cTimeZoneDisplayCache =
114 new ConcurrentHashMap<TimeZoneDisplayKey, String>(7);
115
116 /**
117 * The pattern.
118 */
119 private final String mPattern;
120 /**
121 * The time zone.
122 */
123 private final TimeZone mTimeZone;
124 /**
125 * The locale.
126 */
127 private final Locale mLocale;
128 /**
129 * The parsed rules.
130 */
131 private transient Rule[] mRules;
132 /**
133 * The estimated maximum length.
134 */
135 private transient int mMaxLengthEstimate;
136
137 //-----------------------------------------------------------------------
138 /**
139 * <p>Gets a formatter instance using the default pattern in the
140 * default locale.</p>
141 *
142 * @return a date/time formatter
143 */
144 public static FastDateFormat getInstance() {
145 return cache.getDateTimeInstance(SHORT, SHORT, null, null);
146 }
147
148 /**
149 * <p>Gets a formatter instance using the specified pattern in the
150 * default locale.</p>
151 *
152 * @param pattern {@link java.text.SimpleDateFormat} compatible
153 * pattern
154 * @return a pattern based date/time formatter
155 * @throws IllegalArgumentException if pattern is invalid
156 */
157 public static FastDateFormat getInstance(String pattern) {
158 return cache.getInstance(pattern, null, null);
159 }
160
161 /**
162 * <p>Gets a formatter instance using the specified pattern and
163 * time zone.</p>
164 *
165 * @param pattern {@link java.text.SimpleDateFormat} compatible
166 * pattern
167 * @param timeZone optional time zone, overrides time zone of
168 * formatted date
169 * @return a pattern based date/time formatter
170 * @throws IllegalArgumentException if pattern is invalid
171 */
172 public static FastDateFormat getInstance(String pattern, TimeZone timeZone) {
173 return cache.getInstance(pattern, timeZone, null);
174 }
175
176 /**
177 * <p>Gets a formatter instance using the specified pattern and
178 * locale.</p>
179 *
180 * @param pattern {@link java.text.SimpleDateFormat} compatible
181 * pattern
182 * @param locale optional locale, overrides system locale
183 * @return a pattern based date/time formatter
184 * @throws IllegalArgumentException if pattern is invalid
185 */
186 public static FastDateFormat getInstance(String pattern, Locale locale) {
187 return cache.getInstance(pattern, null, locale);
188 }
189
190 /**
191 * <p>Gets a formatter instance using the specified pattern, time zone
192 * and locale.</p>
193 *
194 * @param pattern {@link java.text.SimpleDateFormat} compatible
195 * pattern
196 * @param timeZone optional time zone, overrides time zone of
197 * formatted date
198 * @param locale optional locale, overrides system locale
199 * @return a pattern based date/time formatter
200 * @throws IllegalArgumentException if pattern is invalid
201 * or {@code null}
202 */
203 public static FastDateFormat getInstance(String pattern, TimeZone timeZone, Locale locale) {
204 return cache.getInstance(pattern, timeZone, locale);
205 }
206
207 //-----------------------------------------------------------------------
208 /**
209 * <p>Gets a date formatter instance using the specified style in the
210 * default time zone and locale.</p>
211 *
212 * @param style date style: FULL, LONG, MEDIUM, or SHORT
213 * @return a localized standard date formatter
214 * @throws IllegalArgumentException if the Locale has no date
215 * pattern defined
216 * @since 2.1
217 */
218 public static FastDateFormat getDateInstance(int style) {
219 return cache.getDateTimeInstance(style, null, null, null);
220 }
221
222 /**
223 * <p>Gets a date formatter instance using the specified style and
224 * locale in the default time zone.</p>
225 *
226 * @param style date style: FULL, LONG, MEDIUM, or SHORT
227 * @param locale optional locale, overrides system locale
228 * @return a localized standard date formatter
229 * @throws IllegalArgumentException if the Locale has no date
230 * pattern defined
231 * @since 2.1
232 */
233 public static FastDateFormat getDateInstance(int style, Locale locale) {
234 return cache.getDateTimeInstance(style, null, null, locale);
235 }
236
237 /**
238 * <p>Gets a date formatter instance using the specified style and
239 * time zone in the default locale.</p>
240 *
241 * @param style date style: FULL, LONG, MEDIUM, or SHORT
242 * @param timeZone optional time zone, overrides time zone of
243 * formatted date
244 * @return a localized standard date formatter
245 * @throws IllegalArgumentException if the Locale has no date
246 * pattern defined
247 * @since 2.1
248 */
249 public static FastDateFormat getDateInstance(int style, TimeZone timeZone) {
250 return cache.getDateTimeInstance(style, null, timeZone, null);
251 }
252
253 /**
254 * <p>Gets a date formatter instance using the specified style, time
255 * zone and locale.</p>
256 *
257 * @param style date style: FULL, LONG, MEDIUM, or SHORT
258 * @param timeZone optional time zone, overrides time zone of
259 * formatted date
260 * @param locale optional locale, overrides system locale
261 * @return a localized standard date formatter
262 * @throws IllegalArgumentException if the Locale has no date
263 * pattern defined
264 */
265 public static FastDateFormat getDateInstance(int style, TimeZone timeZone, Locale locale) {
266 return cache.getDateTimeInstance(style, null, timeZone, locale);
267 }
268
269 //-----------------------------------------------------------------------
270 /**
271 * <p>Gets a time formatter instance using the specified style in the
272 * default time zone and locale.</p>
273 *
274 * @param style time style: FULL, LONG, MEDIUM, or SHORT
275 * @return a localized standard time formatter
276 * @throws IllegalArgumentException if the Locale has no time
277 * pattern defined
278 * @since 2.1
279 */
280 public static FastDateFormat getTimeInstance(int style) {
281 return cache.getDateTimeInstance(null, style, null, null);
282 }
283
284 /**
285 * <p>Gets a time formatter instance using the specified style and
286 * locale in the default time zone.</p>
287 *
288 * @param style time style: FULL, LONG, MEDIUM, or SHORT
289 * @param locale optional locale, overrides system locale
290 * @return a localized standard time formatter
291 * @throws IllegalArgumentException if the Locale has no time
292 * pattern defined
293 * @since 2.1
294 */
295 public static FastDateFormat getTimeInstance(int style, Locale locale) {
296 return cache.getDateTimeInstance(null, style, null, locale);
297 }
298
299 /**
300 * <p>Gets a time formatter instance using the specified style and
301 * time zone in the default locale.</p>
302 *
303 * @param style time style: FULL, LONG, MEDIUM, or SHORT
304 * @param timeZone optional time zone, overrides time zone of
305 * formatted time
306 * @return a localized standard time formatter
307 * @throws IllegalArgumentException if the Locale has no time
308 * pattern defined
309 * @since 2.1
310 */
311 public static FastDateFormat getTimeInstance(int style, TimeZone timeZone) {
312 return cache.getDateTimeInstance(null, style, timeZone, null);
313 }
314
315 /**
316 * <p>Gets a time formatter instance using the specified style, time
317 * zone and locale.</p>
318 *
319 * @param style time style: FULL, LONG, MEDIUM, or SHORT
320 * @param timeZone optional time zone, overrides time zone of
321 * formatted time
322 * @param locale optional locale, overrides system locale
323 * @return a localized standard time formatter
324 * @throws IllegalArgumentException if the Locale has no time
325 * pattern defined
326 */
327 public static FastDateFormat getTimeInstance(int style, TimeZone timeZone, Locale locale) {
328 return cache.getDateTimeInstance(null, style, timeZone, locale);
329 }
330
331 //-----------------------------------------------------------------------
332 /**
333 * <p>Gets a date/time formatter instance using the specified style
334 * in the default time zone and locale.</p>
335 *
336 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
337 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
338 * @return a localized standard date/time formatter
339 * @throws IllegalArgumentException if the Locale has no date/time
340 * pattern defined
341 * @since 2.1
342 */
343 public static FastDateFormat getDateTimeInstance(int dateStyle, int timeStyle) {
344 return cache.getDateTimeInstance(dateStyle, timeStyle, null, null);
345 }
346
347 /**
348 * <p>Gets a date/time formatter instance using the specified style and
349 * locale in the default time zone.</p>
350 *
351 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
352 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
353 * @param locale optional locale, overrides system locale
354 * @return a localized standard date/time formatter
355 * @throws IllegalArgumentException if the Locale has no date/time
356 * pattern defined
357 * @since 2.1
358 */
359 public static FastDateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) {
360 return cache.getDateTimeInstance(dateStyle, timeStyle, null, locale);
361 }
362
363 /**
364 * <p>Gets a date/time formatter instance using the specified style and
365 * time zone in the default locale.</p>
366 *
367 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
368 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
369 * @param timeZone optional time zone, overrides time zone of
370 * formatted date
371 * @return a localized standard date/time formatter
372 * @throws IllegalArgumentException if the Locale has no date/time
373 * pattern defined
374 * @since 2.1
375 */
376 public static FastDateFormat getDateTimeInstance(int dateStyle, int timeStyle, TimeZone timeZone) {
377 return getDateTimeInstance(dateStyle, timeStyle, timeZone, null);
378 }
379 /**
380 * <p>Gets a date/time formatter instance using the specified style,
381 * time zone and locale.</p>
382 *
383 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
384 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
385 * @param timeZone optional time zone, overrides time zone of
386 * formatted date
387 * @param locale optional locale, overrides system locale
388 * @return a localized standard date/time formatter
389 * @throws IllegalArgumentException if the Locale has no date/time
390 * pattern defined
391 */
392 public static FastDateFormat getDateTimeInstance(
393 int dateStyle, int timeStyle, TimeZone timeZone, Locale locale) {
394 return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
395 }
396
397 //-----------------------------------------------------------------------
398 /**
399 * <p>Gets the time zone display name, using a cache for performance.</p>
400 *
401 * @param tz the zone to query
402 * @param daylight true if daylight savings
403 * @param style the style to use {@code TimeZone.LONG} or {@code TimeZone.SHORT}
404 * @param locale the locale to use
405 * @return the textual name of the time zone
406 */
407 static String getTimeZoneDisplay(TimeZone tz, boolean daylight, int style, Locale locale) {
408 TimeZoneDisplayKey key = new TimeZoneDisplayKey(tz, daylight, style, locale);
409 String value = cTimeZoneDisplayCache.get(key);
410 if (value == null) {
411 // This is a very slow call, so cache the results.
412 value = tz.getDisplayName(daylight, style, locale);
413 String prior = cTimeZoneDisplayCache.putIfAbsent(key, value);
414 if (prior != null) {
415 value= prior;
416 }
417 }
418 return value;
419 }
420
421 // Constructor
422 //-----------------------------------------------------------------------
423 /**
424 * <p>Constructs a new FastDateFormat.</p>
425 *
426 * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
427 * @param timeZone non-null time zone to use
428 * @param locale non-null locale to use
429 * @throws NullPointerException if pattern, timeZone, or locale is null.
430 */
431 protected FastDateFormat(String pattern, TimeZone timeZone, Locale locale) {
432 mPattern = pattern;
433 mTimeZone = timeZone;
434 mLocale = locale;
435
436 init();
437 }
438
439 /**
440 * <p>Initializes the instance for first use.</p>
441 */
442 private void init() {
443 List<Rule> rulesList = parsePattern();
444 mRules = rulesList.toArray(new Rule[rulesList.size()]);
445
446 int len = 0;
447 for (int i=mRules.length; --i >= 0; ) {
448 len += mRules[i].estimateLength();
449 }
450
451 mMaxLengthEstimate = len;
452 }
453
454 // Parse the pattern
455 //-----------------------------------------------------------------------
456 /**
457 * <p>Returns a list of Rules given a pattern.</p>
458 *
459 * @return a {@code List} of Rule objects
460 * @throws IllegalArgumentException if pattern is invalid
461 */
462 protected List<Rule> parsePattern() {
463 DateFormatSymbols symbols = new DateFormatSymbols(mLocale);
464 List<Rule> rules = new ArrayList<Rule>();
465
466 String[] ERAs = symbols.getEras();
467 String[] months = symbols.getMonths();
468 String[] shortMonths = symbols.getShortMonths();
469 String[] weekdays = symbols.getWeekdays();
470 String[] shortWeekdays = symbols.getShortWeekdays();
471 String[] AmPmStrings = symbols.getAmPmStrings();
472
473 int length = mPattern.length();
474 int[] indexRef = new int[1];
475
476 for (int i = 0; i < length; i++) {
477 indexRef[0] = i;
478 String token = parseToken(mPattern, indexRef);
479 i = indexRef[0];
480
481 int tokenLen = token.length();
482 if (tokenLen == 0) {
483 break;
484 }
485
486 Rule rule;
487 char c = token.charAt(0);
488
489 switch (c) {
490 case 'G': // era designator (text)
491 rule = new TextField(Calendar.ERA, ERAs);
492 break;
493 case 'y': // year (number)
494 if (tokenLen == 2) {
495 rule = TwoDigitYearField.INSTANCE;
496 } else {
497 rule = selectNumberRule(Calendar.YEAR, tokenLen < 4 ? 4 : tokenLen);
498 }
499 break;
500 case 'M': // month in year (text and number)
501 if (tokenLen >= 4) {
502 rule = new TextField(Calendar.MONTH, months);
503 } else if (tokenLen == 3) {
504 rule = new TextField(Calendar.MONTH, shortMonths);
505 } else if (tokenLen == 2) {
506 rule = TwoDigitMonthField.INSTANCE;
507 } else {
508 rule = UnpaddedMonthField.INSTANCE;
509 }
510 break;
511 case 'd': // day in month (number)
512 rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen);
513 break;
514 case 'h': // hour in am/pm (number, 1..12)
515 rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen));
516 break;
517 case 'H': // hour in day (number, 0..23)
518 rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen);
519 break;
520 case 'm': // minute in hour (number)
521 rule = selectNumberRule(Calendar.MINUTE, tokenLen);
522 break;
523 case 's': // second in minute (number)
524 rule = selectNumberRule(Calendar.SECOND, tokenLen);
525 break;
526 case 'S': // millisecond (number)
527 rule = selectNumberRule(Calendar.MILLISECOND, tokenLen);
528 break;
529 case 'E': // day in week (text)
530 rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays);
531 break;
532 case 'D': // day in year (number)
533 rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen);
534 break;
535 case 'F': // day of week in month (number)
536 rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen);
537 break;
538 case 'w': // week in year (number)
539 rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen);
540 break;
541 case 'W': // week in month (number)
542 rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen);
543 break;
544 case 'a': // am/pm marker (text)
545 rule = new TextField(Calendar.AM_PM, AmPmStrings);
546 break;
547 case 'k': // hour in day (1..24)
548 rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen));
549 break;
550 case 'K': // hour in am/pm (0..11)
551 rule = selectNumberRule(Calendar.HOUR, tokenLen);
552 break;
553 case 'z': // time zone (text)
554 if (tokenLen >= 4) {
555 rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.LONG);
556 } else {
557 rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.SHORT);
558 }
559 break;
560 case 'Z': // time zone (value)
561 if (tokenLen == 1) {
562 rule = TimeZoneNumberRule.INSTANCE_NO_COLON;
563 } else {
564 rule = TimeZoneNumberRule.INSTANCE_COLON;
565 }
566 break;
567 case '\'': // literal text
568 String sub = token.substring(1);
569 if (sub.length() == 1) {
570 rule = new CharacterLiteral(sub.charAt(0));
571 } else {
572 rule = new StringLiteral(sub);
573 }
574 break;
575 default:
576 throw new IllegalArgumentException("Illegal pattern component: " + token);
577 }
578
579 rules.add(rule);
580 }
581
582 return rules;
583 }
584
585 /**
586 * <p>Performs the parsing of tokens.</p>
587 *
588 * @param pattern the pattern
589 * @param indexRef index references
590 * @return parsed token
591 */
592 protected String parseToken(String pattern, int[] indexRef) {
593 StringBuilder buf = new StringBuilder();
594
595 int i = indexRef[0];
596 int length = pattern.length();
597
598 char c = pattern.charAt(i);
599 if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') {
600 // Scan a run of the same character, which indicates a time
601 // pattern.
602 buf.append(c);
603
604 while (i + 1 < length) {
605 char peek = pattern.charAt(i + 1);
606 if (peek == c) {
607 buf.append(c);
608 i++;
609 } else {
610 break;
611 }
612 }
613 } else {
614 // This will identify token as text.
615 buf.append('\'');
616
617 boolean inLiteral = false;
618
619 for (; i < length; i++) {
620 c = pattern.charAt(i);
621
622 if (c == '\'') {
623 if (i + 1 < length && pattern.charAt(i + 1) == '\'') {
624 // '' is treated as escaped '
625 i++;
626 buf.append(c);
627 } else {
628 inLiteral = !inLiteral;
629 }
630 } else if (!inLiteral &&
631 (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) {
632 i--;
633 break;
634 } else {
635 buf.append(c);
636 }
637 }
638 }
639
640 indexRef[0] = i;
641 return buf.toString();
642 }
643
644 /**
645 * <p>Gets an appropriate rule for the padding required.</p>
646 *
647 * @param field the field to get a rule for
648 * @param padding the padding required
649 * @return a new rule with the correct padding
650 */
651 protected NumberRule selectNumberRule(int field, int padding) {
652 switch (padding) {
653 case 1:
654 return new UnpaddedNumberField(field);
655 case 2:
656 return new TwoDigitNumberField(field);
657 default:
658 return new PaddedNumberField(field, padding);
659 }
660 }
661
662 // Format methods
663 //-----------------------------------------------------------------------
664 /**
665 * <p>Formats a {@code Date}, {@code Calendar} or
666 * {@code Long} (milliseconds) object.</p>
667 *
668 * @param obj the object to format
669 * @param toAppendTo the buffer to append to
670 * @param pos the position - ignored
671 * @return the buffer passed in
672 */
673 @Override
674 public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
675 if (obj instanceof Date) {
676 return format((Date) obj, toAppendTo);
677 } else if (obj instanceof Calendar) {
678 return format((Calendar) obj, toAppendTo);
679 } else if (obj instanceof Long) {
680 return format(((Long) obj).longValue(), toAppendTo);
681 } else {
682 throw new IllegalArgumentException("Unknown class: " +
683 (obj == null ? "<null>" : obj.getClass().getName()));
684 }
685 }
686
687 /**
688 * <p>Formats a millisecond {@code long} value.</p>
689 *
690 * @param millis the millisecond value to format
691 * @return the formatted string
692 * @since 2.1
693 */
694 public String format(long millis) {
695 return format(new Date(millis));
696 }
697
698 /**
699 * <p>Formats a {@code Date} object using a {@code GregorianCalendar}.</p>
700 *
701 * @param date the date to format
702 * @return the formatted string
703 */
704 public String format(Date date) {
705 Calendar c = new GregorianCalendar(mTimeZone, mLocale); // hard code GregorianCalendar
706 c.setTime(date);
707 return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString();
708 }
709
710 /**
711 * <p>Formats a {@code Calendar} object.</p>
712 *
713 * @param calendar the calendar to format
714 * @return the formatted string
715 */
716 public String format(Calendar calendar) {
717 return format(calendar, new StringBuffer(mMaxLengthEstimate)).toString();
718 }
719
720 /**
721 * <p>Formats a milliseond {@code long} value into the
722 * supplied {@code StringBuffer}.</p>
723 *
724 * @param millis the millisecond value to format
725 * @param buf the buffer to format into
726 * @return the specified string buffer
727 * @since 2.1
728 */
729 public StringBuffer format(long millis, StringBuffer buf) {
730 return format(new Date(millis), buf);
731 }
732
733 /**
734 * <p>Formats a {@code Date} object into the
735 * supplied {@code StringBuffer} using a {@code GregorianCalendar}.</p>
736 *
737 * @param date the date to format
738 * @param buf the buffer to format into
739 * @return the specified string buffer
740 */
741 public StringBuffer format(Date date, StringBuffer buf) {
742 Calendar c = new GregorianCalendar(mTimeZone, mLocale); // hard code GregorianCalendar
743 c.setTime(date);
744 return applyRules(c, buf);
745 }
746
747 /**
748 * <p>Formats a {@code Calendar} object into the
749 * supplied {@code StringBuffer}.</p>
750 *
751 * @param calendar the calendar to format
752 * @param buf the buffer to format into
753 * @return the specified string buffer
754 */
755 public StringBuffer format(Calendar calendar, StringBuffer buf) {
756 return applyRules(calendar, buf);
757 }
758
759 /**
760 * <p>Performs the formatting by applying the rules to the
761 * specified calendar.</p>
762 *
763 * @param calendar the calendar to format
764 * @param buf the buffer to format into
765 * @return the specified string buffer
766 */
767 protected StringBuffer applyRules(Calendar calendar, StringBuffer buf) {
768 for (Rule rule : mRules) {
769 rule.appendTo(buf, calendar);
770 }
771 return buf;
772 }
773
774 // Parsing
775 //-----------------------------------------------------------------------
776 /**
777 * <p>Parsing is not supported.</p>
778 *
779 * @param source the string to parse
780 * @param pos the parsing position
781 * @return {@code null} as not supported
782 */
783 @Override
784 public Object parseObject(String source, ParsePosition pos) {
785 pos.setIndex(0);
786 pos.setErrorIndex(0);
787 return null;
788 }
789
790 // Accessors
791 //-----------------------------------------------------------------------
792 /**
793 * <p>Gets the pattern used by this formatter.</p>
794 *
795 * @return the pattern, {@link java.text.SimpleDateFormat} compatible
796 */
797 public String getPattern() {
798 return mPattern;
799 }
800
801 /**
802 * <p>Gets the time zone used by this formatter.</p>
803 *
804 * <p>This zone is always used for {@code Date} formatting. </p>
805 *
806 * @return the time zone
807 */
808 public TimeZone getTimeZone() {
809 return mTimeZone;
810 }
811
812 /**
813 * <p>Gets the locale used by this formatter.</p>
814 *
815 * @return the locale
816 */
817 public Locale getLocale() {
818 return mLocale;
819 }
820
821 /**
822 * <p>Gets an estimate for the maximum string length that the
823 * formatter will produce.</p>
824 *
825 * <p>The actual formatted length will almost always be less than or
826 * equal to this amount.</p>
827 *
828 * @return the maximum formatted length
829 */
830 public int getMaxLengthEstimate() {
831 return mMaxLengthEstimate;
832 }
833
834 // Basics
835 //-----------------------------------------------------------------------
836 /**
837 * <p>Compares two objects for equality.</p>
838 *
839 * @param obj the object to compare to
840 * @return {@code true} if equal
841 */
842 @Override
843 public boolean equals(Object obj) {
844 if (obj instanceof FastDateFormat == false) {
845 return false;
846 }
847 FastDateFormat other = (FastDateFormat) obj;
848 return mPattern.equals(other.mPattern)
849 && mTimeZone.equals(other.mTimeZone)
850 && mLocale.equals(other.mLocale);
851 }
852
853 /**
854 * <p>Returns a hashcode compatible with equals.</p>
855 *
856 * @return a hashcode compatible with equals
857 */
858 @Override
859 public int hashCode() {
860 return mPattern.hashCode() + 13 * (mTimeZone.hashCode() + 13 * mLocale.hashCode());
861 }
862
863 /**
864 * <p>Gets a debugging string version of this formatter.</p>
865 *
866 * @return a debugging string
867 */
868 @Override
869 public String toString() {
870 return "FastDateFormat[" + mPattern + "]";
871 }
872
873 // Serializing
874 //-----------------------------------------------------------------------
875 /**
876 * Create the object after serialization. This implementation reinitializes the
877 * transient properties.
878 *
879 * @param in ObjectInputStream from which the object is being deserialized.
880 * @throws IOException if there is an IO issue.
881 * @throws ClassNotFoundException if a class cannot be found.
882 */
883 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
884 in.defaultReadObject();
885 init();
886 }
887
888 // Rules
889 //-----------------------------------------------------------------------
890 /**
891 * <p>Inner class defining a rule.</p>
892 */
893 private interface Rule {
894 /**
895 * Returns the estimated lentgh of the result.
896 *
897 * @return the estimated length
898 */
899 int estimateLength();
900
901 /**
902 * Appends the value of the specified calendar to the output buffer based on the rule implementation.
903 *
904 * @param buffer the output buffer
905 * @param calendar calendar to be appended
906 */
907 void appendTo(StringBuffer buffer, Calendar calendar);
908 }
909
910 /**
911 * <p>Inner class defining a numeric rule.</p>
912 */
913 private interface NumberRule extends Rule {
914 /**
915 * Appends the specified value to the output buffer based on the rule implementation.
916 *
917 * @param buffer the output buffer
918 * @param value the value to be appended
919 */
920 void appendTo(StringBuffer buffer, int value);
921 }
922
923 /**
924 * <p>Inner class to output a constant single character.</p>
925 */
926 private static class CharacterLiteral implements Rule {
927 private final char mValue;
928
929 /**
930 * Constructs a new instance of {@code CharacterLiteral}
931 * to hold the specified value.
932 *
933 * @param value the character literal
934 */
935 CharacterLiteral(char value) {
936 mValue = value;
937 }
938
939 /**
940 * {@inheritDoc}
941 */
942 public int estimateLength() {
943 return 1;
944 }
945
946 /**
947 * {@inheritDoc}
948 */
949 public void appendTo(StringBuffer buffer, Calendar calendar) {
950 buffer.append(mValue);
951 }
952 }
953
954 /**
955 * <p>Inner class to output a constant string.</p>
956 */
957 private static class StringLiteral implements Rule {
958 private final String mValue;
959
960 /**
961 * Constructs a new instance of {@code StringLiteral}
962 * to hold the specified value.
963 *
964 * @param value the string literal
965 */
966 StringLiteral(String value) {
967 mValue = value;
968 }
969
970 /**
971 * {@inheritDoc}
972 */
973 public int estimateLength() {
974 return mValue.length();
975 }
976
977 /**
978 * {@inheritDoc}
979 */
980 public void appendTo(StringBuffer buffer, Calendar calendar) {
981 buffer.append(mValue);
982 }
983 }
984
985 /**
986 * <p>Inner class to output one of a set of values.</p>
987 */
988 private static class TextField implements Rule {
989 private final int mField;
990 private final String[] mValues;
991
992 /**
993 * Constructs an instance of {@code TextField}
994 * with the specified field and values.
995 *
996 * @param field the field
997 * @param values the field values
998 */
999 TextField(int field, String[] values) {
1000 mField = field;
1001 mValues = values;
1002 }
1003
1004 /**
1005 * {@inheritDoc}
1006 */
1007 public int estimateLength() {
1008 int max = 0;
1009 for (int i=mValues.length; --i >= 0; ) {
1010 int len = mValues[i].length();
1011 if (len > max) {
1012 max = len;
1013 }
1014 }
1015 return max;
1016 }
1017
1018 /**
1019 * {@inheritDoc}
1020 */
1021 public void appendTo(StringBuffer buffer, Calendar calendar) {
1022 buffer.append(mValues[calendar.get(mField)]);
1023 }
1024 }
1025
1026 /**
1027 * <p>Inner class to output an unpadded number.</p>
1028 */
1029 private static class UnpaddedNumberField implements NumberRule {
1030 private final int mField;
1031
1032 /**
1033 * Constructs an instance of {@code UnpadedNumberField} with the specified field.
1034 *
1035 * @param field the field
1036 */
1037 UnpaddedNumberField(int field) {
1038 mField = field;
1039 }
1040
1041 /**
1042 * {@inheritDoc}
1043 */
1044 public int estimateLength() {
1045 return 4;
1046 }
1047
1048 /**
1049 * {@inheritDoc}
1050 */
1051 public void appendTo(StringBuffer buffer, Calendar calendar) {
1052 appendTo(buffer, calendar.get(mField));
1053 }
1054
1055 /**
1056 * {@inheritDoc}
1057 */
1058 public final void appendTo(StringBuffer buffer, int value) {
1059 if (value < 10) {
1060 buffer.append((char)(value + '0'));
1061 } else if (value < 100) {
1062 buffer.append((char)(value / 10 + '0'));
1063 buffer.append((char)(value % 10 + '0'));
1064 } else {
1065 buffer.append(Integer.toString(value));
1066 }
1067 }
1068 }
1069
1070 /**
1071 * <p>Inner class to output an unpadded month.</p>
1072 */
1073 private static class UnpaddedMonthField implements NumberRule {
1074 static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField();
1075
1076 /**
1077 * Constructs an instance of {@code UnpaddedMonthField}.
1078 *
1079 */
1080 UnpaddedMonthField() {
1081 super();
1082 }
1083
1084 /**
1085 * {@inheritDoc}
1086 */
1087 public int estimateLength() {
1088 return 2;
1089 }
1090
1091 /**
1092 * {@inheritDoc}
1093 */
1094 public void appendTo(StringBuffer buffer, Calendar calendar) {
1095 appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
1096 }
1097
1098 /**
1099 * {@inheritDoc}
1100 */
1101 public final void appendTo(StringBuffer buffer, int value) {
1102 if (value < 10) {
1103 buffer.append((char)(value + '0'));
1104 } else {
1105 buffer.append((char)(value / 10 + '0'));
1106 buffer.append((char)(value % 10 + '0'));
1107 }
1108 }
1109 }
1110
1111 /**
1112 * <p>Inner class to output a padded number.</p>
1113 */
1114 private static class PaddedNumberField implements NumberRule {
1115 private final int mField;
1116 private final int mSize;
1117
1118 /**
1119 * Constructs an instance of {@code PaddedNumberField}.
1120 *
1121 * @param field the field
1122 * @param size size of the output field
1123 */
1124 PaddedNumberField(int field, int size) {
1125 if (size < 3) {
1126 // Should use UnpaddedNumberField or TwoDigitNumberField.
1127 throw new IllegalArgumentException();
1128 }
1129 mField = field;
1130 mSize = size;
1131 }
1132
1133 /**
1134 * {@inheritDoc}
1135 */
1136 public int estimateLength() {
1137 return 4;
1138 }
1139
1140 /**
1141 * {@inheritDoc}
1142 */
1143 public void appendTo(StringBuffer buffer, Calendar calendar) {
1144 appendTo(buffer, calendar.get(mField));
1145 }
1146
1147 /**
1148 * {@inheritDoc}
1149 */
1150 public final void appendTo(StringBuffer buffer, int value) {
1151 if (value < 100) {
1152 for (int i = mSize; --i >= 2; ) {
1153 buffer.append('0');
1154 }
1155 buffer.append((char)(value / 10 + '0'));
1156 buffer.append((char)(value % 10 + '0'));
1157 } else {
1158 int digits;
1159 if (value < 1000) {
1160 digits = 3;
1161 } else {
1162 Validate.isTrue(value > -1, "Negative values should not be possible", value);
1163 digits = Integer.toString(value).length();
1164 }
1165 for (int i = mSize; --i >= digits; ) {
1166 buffer.append('0');
1167 }
1168 buffer.append(Integer.toString(value));
1169 }
1170 }
1171 }
1172
1173 /**
1174 * <p>Inner class to output a two digit number.</p>
1175 */
1176 private static class TwoDigitNumberField implements NumberRule {
1177 private final int mField;
1178
1179 /**
1180 * Constructs an instance of {@code TwoDigitNumberField} with the specified field.
1181 *
1182 * @param field the field
1183 */
1184 TwoDigitNumberField(int field) {
1185 mField = field;
1186 }
1187
1188 /**
1189 * {@inheritDoc}
1190 */
1191 public int estimateLength() {
1192 return 2;
1193 }
1194
1195 /**
1196 * {@inheritDoc}
1197 */
1198 public void appendTo(StringBuffer buffer, Calendar calendar) {
1199 appendTo(buffer, calendar.get(mField));
1200 }
1201
1202 /**
1203 * {@inheritDoc}
1204 */
1205 public final void appendTo(StringBuffer buffer, int value) {
1206 if (value < 100) {
1207 buffer.append((char)(value / 10 + '0'));
1208 buffer.append((char)(value % 10 + '0'));
1209 } else {
1210 buffer.append(Integer.toString(value));
1211 }
1212 }
1213 }
1214
1215 /**
1216 * <p>Inner class to output a two digit year.</p>
1217 */
1218 private static class TwoDigitYearField implements NumberRule {
1219 static final TwoDigitYearField INSTANCE = new TwoDigitYearField();
1220
1221 /**
1222 * Constructs an instance of {@code TwoDigitYearField}.
1223 */
1224 TwoDigitYearField() {
1225 super();
1226 }
1227
1228 /**
1229 * {@inheritDoc}
1230 */
1231 public int estimateLength() {
1232 return 2;
1233 }
1234
1235 /**
1236 * {@inheritDoc}
1237 */
1238 public void appendTo(StringBuffer buffer, Calendar calendar) {
1239 appendTo(buffer, calendar.get(Calendar.YEAR) % 100);
1240 }
1241
1242 /**
1243 * {@inheritDoc}
1244 */
1245 public final void appendTo(StringBuffer buffer, int value) {
1246 buffer.append((char)(value / 10 + '0'));
1247 buffer.append((char)(value % 10 + '0'));
1248 }
1249 }
1250
1251 /**
1252 * <p>Inner class to output a two digit month.</p>
1253 */
1254 private static class TwoDigitMonthField implements NumberRule {
1255 static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField();
1256
1257 /**
1258 * Constructs an instance of {@code TwoDigitMonthField}.
1259 */
1260 TwoDigitMonthField() {
1261 super();
1262 }
1263
1264 /**
1265 * {@inheritDoc}
1266 */
1267 public int estimateLength() {
1268 return 2;
1269 }
1270
1271 /**
1272 * {@inheritDoc}
1273 */
1274 public void appendTo(StringBuffer buffer, Calendar calendar) {
1275 appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
1276 }
1277
1278 /**
1279 * {@inheritDoc}
1280 */
1281 public final void appendTo(StringBuffer buffer, int value) {
1282 buffer.append((char)(value / 10 + '0'));
1283 buffer.append((char)(value % 10 + '0'));
1284 }
1285 }
1286
1287 /**
1288 * <p>Inner class to output the twelve hour field.</p>
1289 */
1290 private static class TwelveHourField implements NumberRule {
1291 private final NumberRule mRule;
1292
1293 /**
1294 * Constructs an instance of {@code TwelveHourField} with the specified
1295 * {@code NumberRule}.
1296 *
1297 * @param rule the rule
1298 */
1299 TwelveHourField(NumberRule rule) {
1300 mRule = rule;
1301 }
1302
1303 /**
1304 * {@inheritDoc}
1305 */
1306 public int estimateLength() {
1307 return mRule.estimateLength();
1308 }
1309
1310 /**
1311 * {@inheritDoc}
1312 */
1313 public void appendTo(StringBuffer buffer, Calendar calendar) {
1314 int value = calendar.get(Calendar.HOUR);
1315 if (value == 0) {
1316 value = calendar.getLeastMaximum(Calendar.HOUR) + 1;
1317 }
1318 mRule.appendTo(buffer, value);
1319 }
1320
1321 /**
1322 * {@inheritDoc}
1323 */
1324 public void appendTo(StringBuffer buffer, int value) {
1325 mRule.appendTo(buffer, value);
1326 }
1327 }
1328
1329 /**
1330 * <p>Inner class to output the twenty four hour field.</p>
1331 */
1332 private static class TwentyFourHourField implements NumberRule {
1333 private final NumberRule mRule;
1334
1335 /**
1336 * Constructs an instance of {@code TwentyFourHourField} with the specified
1337 * {@code NumberRule}.
1338 *
1339 * @param rule the rule
1340 */
1341 TwentyFourHourField(NumberRule rule) {
1342 mRule = rule;
1343 }
1344
1345 /**
1346 * {@inheritDoc}
1347 */
1348 public int estimateLength() {
1349 return mRule.estimateLength();
1350 }
1351
1352 /**
1353 * {@inheritDoc}
1354 */
1355 public void appendTo(StringBuffer buffer, Calendar calendar) {
1356 int value = calendar.get(Calendar.HOUR_OF_DAY);
1357 if (value == 0) {
1358 value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1;
1359 }
1360 mRule.appendTo(buffer, value);
1361 }
1362
1363 /**
1364 * {@inheritDoc}
1365 */
1366 public void appendTo(StringBuffer buffer, int value) {
1367 mRule.appendTo(buffer, value);
1368 }
1369 }
1370
1371 /**
1372 * <p>Inner class to output a time zone name.</p>
1373 */
1374 private static class TimeZoneNameRule implements Rule {
1375 private final TimeZone mTimeZone;
1376 private final String mStandard;
1377 private final String mDaylight;
1378
1379 /**
1380 * Constructs an instance of {@code TimeZoneNameRule} with the specified properties.
1381 *
1382 * @param timeZone the time zone
1383 * @param locale the locale
1384 * @param style the style
1385 */
1386 TimeZoneNameRule(TimeZone timeZone, Locale locale, int style) {
1387 mTimeZone = timeZone;
1388
1389 mStandard = getTimeZoneDisplay(timeZone, false, style, locale);
1390 mDaylight = getTimeZoneDisplay(timeZone, true, style, locale);
1391 }
1392
1393 /**
1394 * {@inheritDoc}
1395 */
1396 public int estimateLength() {
1397 return Math.max(mStandard.length(), mDaylight.length());
1398 }
1399
1400 /**
1401 * {@inheritDoc}
1402 */
1403 public void appendTo(StringBuffer buffer, Calendar calendar) {
1404 if (mTimeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) {
1405 buffer.append(mDaylight);
1406 } else {
1407 buffer.append(mStandard);
1408 }
1409 }
1410 }
1411
1412 /**
1413 * <p>Inner class to output a time zone as a number {@code +/-HHMM}
1414 * or {@code +/-HH:MM}.</p>
1415 */
1416 private static class TimeZoneNumberRule implements Rule {
1417 static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true);
1418 static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false);
1419
1420 final boolean mColon;
1421
1422 /**
1423 * Constructs an instance of {@code TimeZoneNumberRule} with the specified properties.
1424 *
1425 * @param colon add colon between HH and MM in the output if {@code true}
1426 */
1427 TimeZoneNumberRule(boolean colon) {
1428 mColon = colon;
1429 }
1430
1431 /**
1432 * {@inheritDoc}
1433 */
1434 public int estimateLength() {
1435 return 5;
1436 }
1437
1438 /**
1439 * {@inheritDoc}
1440 */
1441 public void appendTo(StringBuffer buffer, Calendar calendar) {
1442 int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
1443
1444 if (offset < 0) {
1445 buffer.append('-');
1446 offset = -offset;
1447 } else {
1448 buffer.append('+');
1449 }
1450
1451 int hours = offset / (60 * 60 * 1000);
1452 buffer.append((char)(hours / 10 + '0'));
1453 buffer.append((char)(hours % 10 + '0'));
1454
1455 if (mColon) {
1456 buffer.append(':');
1457 }
1458
1459 int minutes = offset / (60 * 1000) - 60 * hours;
1460 buffer.append((char)(minutes / 10 + '0'));
1461 buffer.append((char)(minutes % 10 + '0'));
1462 }
1463 }
1464
1465 // ----------------------------------------------------------------------
1466 /**
1467 * <p>Inner class that acts as a compound key for time zone names.</p>
1468 */
1469 private static class TimeZoneDisplayKey {
1470 private final TimeZone mTimeZone;
1471 private final int mStyle;
1472 private final Locale mLocale;
1473
1474 /**
1475 * Constructs an instance of {@code TimeZoneDisplayKey} with the specified properties.
1476 *
1477 * @param timeZone the time zone
1478 * @param daylight adjust the style for daylight saving time if {@code true}
1479 * @param style the timezone style
1480 * @param locale the timezone locale
1481 */
1482 TimeZoneDisplayKey(TimeZone timeZone,
1483 boolean daylight, int style, Locale locale) {
1484 mTimeZone = timeZone;
1485 if (daylight) {
1486 style |= 0x80000000;
1487 }
1488 mStyle = style;
1489 mLocale = locale;
1490 }
1491
1492 /**
1493 * {@inheritDoc}
1494 */
1495 @Override
1496 public int hashCode() {
1497 return (mStyle * 31 + mLocale.hashCode() ) * 31 + mTimeZone.hashCode();
1498 }
1499
1500 /**
1501 * {@inheritDoc}
1502 */
1503 @Override
1504 public boolean equals(Object obj) {
1505 if (this == obj) {
1506 return true;
1507 }
1508 if (obj instanceof TimeZoneDisplayKey) {
1509 TimeZoneDisplayKey other = (TimeZoneDisplayKey)obj;
1510 return
1511 mTimeZone.equals(other.mTimeZone) &&
1512 mStyle == other.mStyle &&
1513 mLocale.equals(other.mLocale);
1514 }
1515 return false;
1516 }
1517 }
1518 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import java.text.DateFormat;
19 import java.text.Format;
20 import java.text.SimpleDateFormat;
21 import java.util.Arrays;
22 import java.util.Locale;
23 import java.util.TimeZone;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26
27 /**
28 * <p>FormatCache is a cache and factory for {@link Format}s.</p>
29 *
30 * @since 3.0
31 * @version $Id: FormatCache 892161 2009-12-18 07:21:10Z $
32 */
33 // TODO: Before making public move from getDateTimeInstance(Integer,...) to int; or some other approach.
34 abstract class FormatCache<F extends Format> {
35 /**
36 * No date or no time. Used in same parameters as DateFormat.SHORT or DateFormat.LONG
37 */
38 static final int NONE= -1;
39
40 private final ConcurrentMap<MultipartKey, F> cInstanceCache
41 = new ConcurrentHashMap<MultipartKey, F>(7);
42
43 private final ConcurrentMap<MultipartKey, String> cDateTimeInstanceCache
44 = new ConcurrentHashMap<MultipartKey, String>(7);
45
46 /**
47 * <p>Gets a formatter instance using the default pattern in the
48 * default timezone and locale.</p>
49 *
50 * @return a date/time formatter
51 */
52 public F getInstance() {
53 return getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, TimeZone.getDefault(), Locale.getDefault());
54 }
55
56 /**
57 * <p>Gets a formatter instance using the specified pattern, time zone
58 * and locale.</p>
59 *
60 * @param pattern {@link java.text.SimpleDateFormat} compatible
61 * pattern
62 * @param timeZone the non-null time zone
63 * @param locale the non-null locale
64 * @return a pattern based date/time formatter
65 * @throws IllegalArgumentException if pattern is invalid
66 * or <code>null</code>
67 */
68 public F getInstance(String pattern, TimeZone timeZone, Locale locale) {
69 if (pattern == null) {
70 throw new NullPointerException("pattern must not be null");
71 }
72 if (timeZone == null) {
73 timeZone = TimeZone.getDefault();
74 }
75 if (locale == null) {
76 locale = Locale.getDefault();
77 }
78 MultipartKey key = new MultipartKey(pattern, timeZone, locale);
79 F format = cInstanceCache.get(key);
80 if (format == null) {
81 format = createInstance(pattern, timeZone, locale);
82 F previousValue= cInstanceCache.putIfAbsent(key, format);
83 if (previousValue != null) {
84 // another thread snuck in and did the same work
85 // we should return the instance that is in ConcurrentMap
86 format= previousValue;
87 }
88 }
89 return format;
90 }
91
92 /**
93 * <p>Create a format instance using the specified pattern, time zone
94 * and locale.</p>
95 *
96 * @param pattern {@link java.text.SimpleDateFormat} compatible pattern, this will not be null.
97 * @param timeZone time zone, this will not be null.
98 * @param locale locale, this will not be null.
99 * @return a pattern based date/time formatter
100 * @throws IllegalArgumentException if pattern is invalid
101 * or <code>null</code>
102 */
103 abstract protected F createInstance(String pattern, TimeZone timeZone, Locale locale);
104
105 /**
106 * <p>Gets a date/time formatter instance using the specified style,
107 * time zone and locale.</p>
108 *
109 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
110 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
111 * @param timeZone optional time zone, overrides time zone of
112 * formatted date
113 * @param locale optional locale, overrides system locale
114 * @return a localized standard date/time formatter
115 * @throws IllegalArgumentException if the Locale has no date/time
116 * pattern defined
117 */
118 public F getDateTimeInstance(Integer dateStyle, Integer timeStyle, TimeZone timeZone, Locale locale) {
119 if (locale == null) {
120 locale = Locale.getDefault();
121 }
122 MultipartKey key = new MultipartKey(dateStyle, timeStyle, locale);
123
124 String pattern = cDateTimeInstanceCache.get(key);
125 if (pattern == null) {
126 try {
127 DateFormat formatter;
128 if (dateStyle == null) {
129 formatter = DateFormat.getTimeInstance(timeStyle, locale);
130 }
131 else if (timeStyle == null) {
132 formatter = DateFormat.getDateInstance(dateStyle, locale);
133 }
134 else {
135 formatter = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
136 }
137 pattern = ((SimpleDateFormat)formatter).toPattern();
138 String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern);
139 if (previous != null) {
140 // even though it doesn't matter if another thread put the pattern
141 // it's still good practice to return the String instance that is
142 // actually in the ConcurrentMap
143 pattern= previous;
144 }
145 } catch (ClassCastException ex) {
146 throw new IllegalArgumentException("No date time pattern for locale: " + locale);
147 }
148 }
149
150 return getInstance(pattern, timeZone, locale);
151 }
152
153 // ----------------------------------------------------------------------
154 /**
155 * <p>Helper class to hold multi-part Map keys</p>
156 */
157 private static class MultipartKey {
158 private final Object[] keys;
159 private int hashCode;
160
161 /**
162 * Constructs an instance of <code>MultipartKey</code> to hold the specified objects.
163 * @param keys the set of objects that make up the key. Each key may be null.
164 */
165 public MultipartKey(Object... keys) {
166 this.keys = keys;
167 }
168
169 /**
170 * {@inheritDoc}
171 */
172 @Override
173 public boolean equals(Object obj) {
174 if (this == obj) {
175 return true;
176 }
177 if ( obj instanceof MultipartKey == false ) {
178 return false;
179 }
180 return Arrays.equals(keys, ((MultipartKey)obj).keys);
181 }
182
183 /**
184 * {@inheritDoc}
185 */
186 @Override
187 public int hashCode() {
188 if(hashCode==0) {
189 int rc= 0;
190 for(Object key : keys) {
191 if(key!=null) {
192 rc= rc*7 + key.hashCode();
193 }
194 }
195 hashCode= rc;
196 }
197 return hashCode;
198 }
199 }
200
201 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.time;
18
19 /**
20 * <p>
21 * <code>StopWatch</code> provides a convenient API for timings.
22 * </p>
23 *
24 * <p>
25 * To start the watch, call {@link #start()}. At this point you can:
26 * </p>
27 * <ul>
28 * <li>{@link #split()} the watch to get the time whilst the watch continues in the background. {@link #unsplit()} will
29 * remove the effect of the split. At this point, these three options are available again.</li>
30 * <li>{@link #suspend()} the watch to pause it. {@link #resume()} allows the watch to continue. Any time between the
31 * suspend and resume will not be counted in the total. At this point, these three options are available again.</li>
32 * <li>{@link #stop()} the watch to complete the timing session.</li>
33 * </ul>
34 *
35 * <p>
36 * It is intended that the output methods {@link #toString()} and {@link #getTime()} should only be called after stop,
37 * split or suspend, however a suitable result will be returned at other points.
38 * </p>
39 *
40 * <p>
41 * NOTE: As from v2.1, the methods protect against inappropriate calls. Thus you cannot now call stop before start,
42 * resume before suspend or unsplit before split.
43 * </p>
44 *
45 * <p>
46 * 1. split(), suspend(), or stop() cannot be invoked twice<br />
47 * 2. unsplit() may only be called if the watch has been split()<br />
48 * 3. resume() may only be called if the watch has been suspend()<br />
49 * 4. start() cannot be called twice without calling reset()
50 * </p>
51 *
52 * <p>This class is not thread-safe</p>
53 *
54 * @since 2.0
55 * @version $Id: StopWatch.java 1088899 2011-04-05 05:31:27Z bayard $
56 */
57 public class StopWatch {
58
59 private static final long NANO_2_MILLIS = 1000000L;
60
61 // running states
62 private static final int STATE_UNSTARTED = 0;
63
64 private static final int STATE_RUNNING = 1;
65
66 private static final int STATE_STOPPED = 2;
67
68 private static final int STATE_SUSPENDED = 3;
69
70 // split state
71 private static final int STATE_UNSPLIT = 10;
72
73 private static final int STATE_SPLIT = 11;
74
75 /**
76 * The current running state of the StopWatch.
77 */
78 private int runningState = STATE_UNSTARTED;
79
80 /**
81 * Whether the stopwatch has a split time recorded.
82 */
83 private int splitState = STATE_UNSPLIT;
84
85 /**
86 * The start time.
87 */
88 private long startTime;
89
90 /**
91 * The start time in Millis - nanoTime is only for elapsed time so we
92 * need to also store the currentTimeMillis to maintain the old
93 * getStartTime API.
94 */
95 private long startTimeMillis;
96
97 /**
98 * The stop time.
99 */
100 private long stopTime;
101
102 /**
103 * <p>
104 * Constructor.
105 * </p>
106 */
107 public StopWatch() {
108 super();
109 }
110
111 /**
112 * <p>
113 * Start the stopwatch.
114 * </p>
115 *
116 * <p>
117 * This method starts a new timing session, clearing any previous values.
118 * </p>
119 *
120 * @throws IllegalStateException
121 * if the StopWatch is already running.
122 */
123 public void start() {
124 if (this.runningState == STATE_STOPPED) {
125 throw new IllegalStateException("Stopwatch must be reset before being restarted. ");
126 }
127 if (this.runningState != STATE_UNSTARTED) {
128 throw new IllegalStateException("Stopwatch already started. ");
129 }
130 this.startTime = System.nanoTime();
131 this.startTimeMillis = System.currentTimeMillis();
132 this.runningState = STATE_RUNNING;
133 }
134
135 /**
136 * <p>
137 * Stop the stopwatch.
138 * </p>
139 *
140 * <p>
141 * This method ends a new timing session, allowing the time to be retrieved.
142 * </p>
143 *
144 * @throws IllegalStateException
145 * if the StopWatch is not running.
146 */
147 public void stop() {
148 if (this.runningState != STATE_RUNNING && this.runningState != STATE_SUSPENDED) {
149 throw new IllegalStateException("Stopwatch is not running. ");
150 }
151 if (this.runningState == STATE_RUNNING) {
152 this.stopTime = System.nanoTime();
153 }
154 this.runningState = STATE_STOPPED;
155 }
156
157 /**
158 * <p>
159 * Resets the stopwatch. Stops it if need be.
160 * </p>
161 *
162 * <p>
163 * This method clears the internal values to allow the object to be reused.
164 * </p>
165 */
166 public void reset() {
167 this.runningState = STATE_UNSTARTED;
168 this.splitState = STATE_UNSPLIT;
169 }
170
171 /**
172 * <p>
173 * Split the time.
174 * </p>
175 *
176 * <p>
177 * This method sets the stop time of the watch to allow a time to be extracted. The start time is unaffected,
178 * enabling {@link #unsplit()} to continue the timing from the original start point.
179 * </p>
180 *
181 * @throws IllegalStateException
182 * if the StopWatch is not running.
183 */
184 public void split() {
185 if (this.runningState != STATE_RUNNING) {
186 throw new IllegalStateException("Stopwatch is not running. ");
187 }
188 this.stopTime = System.nanoTime();
189 this.splitState = STATE_SPLIT;
190 }
191
192 /**
193 * <p>
194 * Remove a split.
195 * </p>
196 *
197 * <p>
198 * This method clears the stop time. The start time is unaffected, enabling timing from the original start point to
199 * continue.
200 * </p>
201 *
202 * @throws IllegalStateException
203 * if the StopWatch has not been split.
204 */
205 public void unsplit() {
206 if (this.splitState != STATE_SPLIT) {
207 throw new IllegalStateException("Stopwatch has not been split. ");
208 }
209 this.splitState = STATE_UNSPLIT;
210 }
211
212 /**
213 * <p>
214 * Suspend the stopwatch for later resumption.
215 * </p>
216 *
217 * <p>
218 * This method suspends the watch until it is resumed. The watch will not include time between the suspend and
219 * resume calls in the total time.
220 * </p>
221 *
222 * @throws IllegalStateException
223 * if the StopWatch is not currently running.
224 */
225 public void suspend() {
226 if (this.runningState != STATE_RUNNING) {
227 throw new IllegalStateException("Stopwatch must be running to suspend. ");
228 }
229 this.stopTime = System.nanoTime();
230 this.runningState = STATE_SUSPENDED;
231 }
232
233 /**
234 * <p>
235 * Resume the stopwatch after a suspend.
236 * </p>
237 *
238 * <p>
239 * This method resumes the watch after it was suspended. The watch will not include time between the suspend and
240 * resume calls in the total time.
241 * </p>
242 *
243 * @throws IllegalStateException
244 * if the StopWatch has not been suspended.
245 */
246 public void resume() {
247 if (this.runningState != STATE_SUSPENDED) {
248 throw new IllegalStateException("Stopwatch must be suspended to resume. ");
249 }
250 this.startTime += (System.nanoTime() - this.stopTime);
251 this.runningState = STATE_RUNNING;
252 }
253
254 /**
255 * <p>
256 * Get the time on the stopwatch.
257 * </p>
258 *
259 * <p>
260 * This is either the time between the start and the moment this method is called, or the amount of time between
261 * start and stop.
262 * </p>
263 *
264 * @return the time in milliseconds
265 */
266 public long getTime() {
267 return getNanoTime() / NANO_2_MILLIS;
268 }
269 /**
270 * <p>
271 * Get the time on the stopwatch in nanoseconds.
272 * </p>
273 *
274 * <p>
275 * This is either the time between the start and the moment this method is called, or the amount of time between
276 * start and stop.
277 * </p>
278 *
279 * @return the time in nanoseconds
280 * @since 3.0
281 */
282 public long getNanoTime() {
283 if (this.runningState == STATE_STOPPED || this.runningState == STATE_SUSPENDED) {
284 return this.stopTime - this.startTime;
285 } else if (this.runningState == STATE_UNSTARTED) {
286 return 0;
287 } else if (this.runningState == STATE_RUNNING) {
288 return System.nanoTime() - this.startTime;
289 }
290 throw new RuntimeException("Illegal running state has occured. ");
291 }
292
293 /**
294 * <p>
295 * Get the split time on the stopwatch.
296 * </p>
297 *
298 * <p>
299 * This is the time between start and latest split.
300 * </p>
301 *
302 * @return the split time in milliseconds
303 *
304 * @throws IllegalStateException
305 * if the StopWatch has not yet been split.
306 * @since 2.1
307 */
308 public long getSplitTime() {
309 return getSplitNanoTime() / NANO_2_MILLIS;
310 }
311 /**
312 * <p>
313 * Get the split time on the stopwatch in nanoseconds.
314 * </p>
315 *
316 * <p>
317 * This is the time between start and latest split.
318 * </p>
319 *
320 * @return the split time in nanoseconds
321 *
322 * @throws IllegalStateException
323 * if the StopWatch has not yet been split.
324 * @since 3.0
325 */
326 public long getSplitNanoTime() {
327 if (this.splitState != STATE_SPLIT) {
328 throw new IllegalStateException("Stopwatch must be split to get the split time. ");
329 }
330 return this.stopTime - this.startTime;
331 }
332
333 /**
334 * Returns the time this stopwatch was started.
335 *
336 * @return the time this stopwatch was started
337 * @throws IllegalStateException
338 * if this StopWatch has not been started
339 * @since 2.4
340 */
341 public long getStartTime() {
342 if (this.runningState == STATE_UNSTARTED) {
343 throw new IllegalStateException("Stopwatch has not been started");
344 }
345 // System.nanoTime is for elapsed time
346 return this.startTimeMillis;
347 }
348
349 /**
350 * <p>
351 * Gets a summary of the time that the stopwatch recorded as a string.
352 * </p>
353 *
354 * <p>
355 * The format used is ISO8601-like, <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.
356 * </p>
357 *
358 * @return the time as a String
359 */
360 @Override
361 public String toString() {
362 return DurationFormatUtils.formatDurationHMS(getTime());
363 }
364
365 /**
366 * <p>
367 * Gets a summary of the split time that the stopwatch recorded as a string.
368 * </p>
369 *
370 * <p>
371 * The format used is ISO8601-like, <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.
372 * </p>
373 *
374 * @return the split time as a String
375 * @since 2.1
376 */
377 public String toSplitString() {
378 return DurationFormatUtils.formatDurationHMS(getSplitTime());
379 }
380
381 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 Provides classes and methods to work with dates and durations.
19 @since 2.0
20 <p>These classes are immutable (and therefore thread-safe) apart from {@link org.apache.commons.lang3.time.StopWatch}.</p>
21 </body>
22 </html>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.tuple;
17
18 /**
19 * <p>An immutable pair consisting of two {@code Object} elements.</p>
20 *
21 * <p>Although the implementation is immutable, there is no restriction on the objects
22 * that may be stored. If mutable objects are stored in the pair, then the pair
23 * itself effectively becomes mutable. The class is also not {@code final}, so a subclass
24 * could add undesirable behaviour.</p>
25 *
26 * <p>#ThreadSafe# if the objects are threadsafe</p>
27 *
28 * @param <L> the left element type
29 * @param <R> the right element type
30 *
31 * @since Lang 3.0
32 * @version $Id: ImmutablePair.java 1127544 2011-05-25 14:35:42Z scolebourne $
33 */
34 public final class ImmutablePair<L, R> extends Pair<L, R> {
35
36 /** Serialization version */
37 private static final long serialVersionUID = 4954918890077093841L;
38
39 /** Left object */
40 public final L left;
41 /** Right object */
42 public final R right;
43
44 /**
45 * <p>Obtains an immutable pair of from two objects inferring the generic types.</p>
46 *
47 * <p>This factory allows the pair to be created using inference to
48 * obtain the generic types.</p>
49 *
50 * @param <L> the left element type
51 * @param <R> the right element type
52 * @param left the left element, may be null
53 * @param right the right element, may be null
54 * @return a pair formed from the two parameters, not null
55 */
56 public static <L, R> ImmutablePair<L, R> of(L left, R right) {
57 return new ImmutablePair<L, R>(left, right);
58 }
59
60 /**
61 * Create a new pair instance.
62 *
63 * @param left the left value, may be null
64 * @param right the right value, may be null
65 */
66 public ImmutablePair(L left, R right) {
67 super();
68 this.left = left;
69 this.right = right;
70 }
71
72 //-----------------------------------------------------------------------
73 /**
74 * {@inheritDoc}
75 */
76 @Override
77 public L getLeft() {
78 return left;
79 }
80
81 /**
82 * {@inheritDoc}
83 */
84 @Override
85 public R getRight() {
86 return right;
87 }
88
89 /**
90 * <p>Throws {@code UnsupportedOperationException}.</p>
91 *
92 * <p>This pair is immutable, so this operation is not supported.</p>
93 *
94 * @param value the value to set
95 * @return never
96 * @throws UnsupportedOperationException as this operation is not supported
97 */
98 public R setValue(R value) {
99 throw new UnsupportedOperationException();
100 }
101
102 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.tuple;
17
18 /**
19 * <p>A mutable pair consisting of two {@code Object} elements.</p>
20 *
21 * <p>Not #ThreadSafe#</p>
22 *
23 * @param <L> the left element type
24 * @param <R> the right element type
25 *
26 * @since Lang 3.0
27 * @version $Id: MutablePair.java 1127544 2011-05-25 14:35:42Z scolebourne $
28 */
29 public class MutablePair<L, R> extends Pair<L, R> {
30
31 /** Serialization version */
32 private static final long serialVersionUID = 4954918890077093841L;
33
34 /** Left object */
35 public L left;
36 /** Right object */
37 public R right;
38
39 /**
40 * <p>Obtains an immutable pair of from two objects inferring the generic types.</p>
41 *
42 * <p>This factory allows the pair to be created using inference to
43 * obtain the generic types.</p>
44 *
45 * @param <L> the left element type
46 * @param <R> the right element type
47 * @param left the left element, may be null
48 * @param right the right element, may be null
49 * @return a pair formed from the two parameters, not null
50 */
51 public static <L, R> MutablePair<L, R> of(L left, R right) {
52 return new MutablePair<L, R>(left, right);
53 }
54
55 /**
56 * Create a new pair instance of two nulls.
57 */
58 public MutablePair() {
59 super();
60 }
61
62 /**
63 * Create a new pair instance.
64 *
65 * @param left the left value, may be null
66 * @param right the right value, may be null
67 */
68 public MutablePair(L left, R right) {
69 super();
70 this.left = left;
71 this.right = right;
72 }
73
74 //-----------------------------------------------------------------------
75 /**
76 * {@inheritDoc}
77 */
78 @Override
79 public L getLeft() {
80 return left;
81 }
82
83 /**
84 * Sets the left element of the pair.
85 *
86 * @param left the new value of the left element, may be null
87 */
88 public void setLeft(L left) {
89 this.left = left;
90 }
91
92 /**
93 * {@inheritDoc}
94 */
95 @Override
96 public R getRight() {
97 return right;
98 }
99
100 /**
101 * Sets the right element of the pair.
102 *
103 * @param right the new value of the right element, may be null
104 */
105 public void setRight(R right) {
106 this.right = right;
107 }
108
109 /**
110 * Sets the {@code Map.Entry} value.
111 * This sets the right element of the pair.
112 *
113 * @param value the right value to set, not null
114 * @return the old value for the right element
115 */
116 public R setValue(R value) {
117 R result = getRight();
118 setRight(value);
119 return result;
120 }
121
122 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.tuple;
17
18 import java.io.Serializable;
19 import java.util.Map;
20
21 import org.apache.commons.lang3.ObjectUtils;
22 import org.apache.commons.lang3.builder.CompareToBuilder;
23
24 /**
25 * <p>A pair consisting of two elements.</p>
26 *
27 * <p>This class is an abstract implementation defining the basic API.
28 * It refers to the elements as 'left' and 'right'. It also implements the
29 * {@code Map.Entry} interface where the key is 'left' and the value is 'right'.</p>
30 *
31 * <p>Subclass implementations may be mutable or immutable.
32 * However, there is no restriction on the type of the stored objects that may be stored.
33 * If mutable objects are stored in the pair, then the pair itself effectively becomes mutable.</p>
34 *
35 * @param <L> the left element type
36 * @param <R> the right element type
37 *
38 * @since Lang 3.0
39 * @version $Id: Pair.java 1142401 2011-07-03 08:30:12Z bayard $
40 */
41 public abstract class Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable {
42
43 /** Serialization version */
44 private static final long serialVersionUID = 4954918890077093841L;
45
46 /**
47 * <p>Obtains an immutable pair of from two objects inferring the generic types.</p>
48 *
49 * <p>This factory allows the pair to be created using inference to
50 * obtain the generic types.</p>
51 *
52 * @param <L> the left element type
53 * @param <R> the right element type
54 * @param left the left element, may be null
55 * @param right the right element, may be null
56 * @return a pair formed from the two parameters, not null
57 */
58 public static <L, R> Pair<L, R> of(L left, R right) {
59 return new ImmutablePair<L, R>(left, right);
60 }
61
62 //-----------------------------------------------------------------------
63 /**
64 * <p>Gets the left element from this pair.</p>
65 *
66 * <p>When treated as a key-value pair, this is the key.</p>
67 *
68 * @return the left element, may be null
69 */
70 public abstract L getLeft();
71
72 /**
73 * <p>Gets the right element from this pair.</p>
74 *
75 * <p>When treated as a key-value pair, this is the value.</p>
76 *
77 * @return the right element, may be null
78 */
79 public abstract R getRight();
80
81 /**
82 * <p>Gets the key from this pair.</p>
83 *
84 * <p>This method implements the {@code Map.Entry} interface returning the
85 * left element as the key.</p>
86 *
87 * @return the left element as the key, may be null
88 */
89 public final L getKey() {
90 return getLeft();
91 }
92
93 /**
94 * <p>Gets the value from this pair.</p>
95 *
96 * <p>This method implements the {@code Map.Entry} interface returning the
97 * right element as the value.</p>
98 *
99 * @return the right element as the value, may be null
100 */
101 public R getValue() {
102 return getRight();
103 }
104
105 //-----------------------------------------------------------------------
106 /**
107 * <p>Compares the pair based on the left element followed by the right element.
108 * The types must be {@code Comparable}.</p>
109 *
110 * @param other the other pair, not null
111 * @return negative if this is less, zero if equal, positive if greater
112 */
113 public int compareTo(Pair<L, R> other) {
114 return new CompareToBuilder().append(getLeft(), other.getLeft())
115 .append(getRight(), other.getRight()).toComparison();
116 }
117
118 /**
119 * <p>Compares this pair to another based on the two elements.</p>
120 *
121 * @param obj the object to compare to, null returns false
122 * @return true if the elements of the pair are equal
123 */
124 @Override
125 public boolean equals(Object obj) {
126 if (obj == this) {
127 return true;
128 }
129 if (obj instanceof Map.Entry<?, ?>) {
130 Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
131 return ObjectUtils.equals(getKey(), other.getKey())
132 && ObjectUtils.equals(getValue(), other.getValue());
133 }
134 return false;
135 }
136
137 /**
138 * <p>Returns a suitable hash code.
139 * The hash code follows the definition in {@code Map.Entry}.</p>
140 *
141 * @return the hash code
142 */
143 @Override
144 public int hashCode() {
145 // see Map.Entry API specification
146 return (getKey() == null ? 0 : getKey().hashCode()) ^
147 (getValue() == null ? 0 : getValue().hashCode());
148 }
149
150 /**
151 * <p>Returns a String representation of this pair using the format {@code ($left,$right)}.</p>
152 *
153 * @return a string describing this object, not null
154 */
155 @Override
156 public String toString() {
157 return new StringBuilder().append('(').append(getLeft()).append(',').append(getRight()).append(')').toString();
158 }
159
160 /**
161 * <p>Formats the receiver using the given format.</p>
162 *
163 * <p>This uses {@link java.util.Formattable} to perform the formatting. Two variables may
164 * be used to embed the left and right elements. Use {@code %1$s} for the left
165 * element (key) and {@code %2$s} for the right element (value).
166 * The default format used by {@code toString()} is {@code (%1$s,%2$s)}.</p>
167 *
168 * @param format the format string, optionally containing {@code %1$s} and {@code %2$s}, not null
169 * @return the formatted string, not null
170 */
171 public String toString(String format) {
172 return String.format(format, getLeft(), getRight());
173 }
174
175 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <html>
17 <body>
18 Tuple classes, starting with a Pair class in version 3.0.
19 @since 3.0
20 </body>
21 </html>
Binary diff not shown
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>Commons Lang Changes</title>
20 </properties>
21 <body>
22
23 <release version="3.0.1" date="Unreleased" description="Next 3.x release">
24 <action type="fix" issue="LANG-626">SerializationUtils.clone: Fallback to context classloader if class not found in current classloader.</action>
25 <action type="fix" issue="LANG-727">ToStringBuilderTest.testReflectionHierarchyArrayList fails with IBM JDK 6.</action>
26 <action type="fix" issue="LANG-720">StringEscapeUtils.escapeXml(input) wrong when input contains characters in Supplementary Planes.</action>
27 <action type="fix" issue="LANG-708">StringEscapeUtils.escapeEcmaScript from lang3 cuts off long unicode string.</action>
28 <action type="update" issue="LANG-686">Improve exception message when StringUtils.replaceEachRepeatedly detects recursion.</action>
29 <action type="update" issue="LANG-717">Specify source encoding for Ant build.</action>
30 <action type="add" issue="LANG-721">Complement ArrayUtils.addAll() variants with by-index and by-value removal methods.</action>
31 <action type="add" issue="LANG-726">Add Range&lt;T&gt; Range&lt;T&gt;.intersectionWith(Range&lt;T&gt;).</action>
32 <action type="add" issue="LANG-723">Add mode and median Comparable... methods to ObjectUtils.</action>
33 <action type="add" issue="LANG-722">Add BooleanUtils.and + or varargs methods.</action>
34 <action type="add" issue="LANG-730">EnumSet -&gt; bit vector.</action>
35 <action type="fix" issue="LANG-734">The CHAR_ARRAY cache in CharUtils duplicates the cache in java.lang.Character.</action>
36 <action type="update" issue="LANG-735">Deprecate CharUtils.toCharacterObject(char) in favor of java.lang.Character.valueOf(char).</action>
37 <action type="add" issue="LANG-737">Missing method getRawMessage for ContextedException and ContextedRuntimeException.</action>
38 <action type="fix" issue="LANG-738">Use internal Java's Number caches instead creating new objects.</action>
39 </release>
40
41 <release version="3.0" date="2011-07-18" description="Backwards incompatible update of Commons Lang to Java 5">
42 <action type="fix" issue="LANG-720">StringEscapeUtils.escapeXml(input) outputs wrong results when an input contains characters in Supplementary Planes.</action>
43 <action type="update" issue="LANG-718">build.xml Java 1.5+ updates.</action>
44 <action type="fix" issue="LANG-716">swapCase and *capitalize speedups.</action>
45 <action type="fix" issue="LANG-715">CharSetUtils.squeeze() speedup.</action>
46 <action type="fix" issue="LANG-714">StringUtils doc/comment spelling fixes.</action>
47 <action type="update" issue="LANG-713">Increase test coverage of FieldUtils read methods and tweak javadoc.</action>
48 <action type="fix" issue="LANG-711">Add includeantruntime=false to javac targets to quell warnings in ant 1.8.1 and better (and modest performance gain).</action>
49 <action type="fix" issue="LANG-710">StringIndexOutOfBoundsException when calling unescapeHtml4("&amp;#03").</action>
50 <action type="fix" issue="LANG-708">StringEscapeUtils.escapeEcmaScript from lang3 cuts off long Unicode string.</action>
51 <action type="fix" issue="LANG-703">StringUtils.join throws NPE when toString returns null for one of objects in collection.</action>
52 <action type="add" issue="LANG-697">Add FormattableUtils class.</action>
53 <action type="add">Add ClassUtils.getSimpleName() methods.</action>
54 <action type="add" issue="LANG-692">Add hashCodeMulti varargs method.</action>
55 <action type="remove" issue="LANG-691">Removed DateUtils.UTC_TIME_ZONE.</action>
56 <action type="update" issues="LANG-687">Convert more of the StringUtils API to take CharSequence.</action>
57 <action type="fix" issue="LANG-685">EqualsBuilder synchronizes on HashCodeBuilder.</action>
58 <action type="fix" issue="LANG-428">StringUtils.isAlpha, isAlphanumeric and isNumeric now return false for "".</action>
59 <action type="add" issue="LANG-678">Add support for ConcurrentMap.putIfAbsent().</action>
60 <action type="add" issue="LANG-676">Documented potential NPE if auto-boxing occurs for some BooleanUtils methods.</action>
61 <action type="fix" issue="LANG-677">DateUtils.isSameLocalTime compares using 12 hour clock and not 24 hour.</action>
62 <action type="add" issue="LANG-610">Extend exception handling in ConcurrentUtils to runtime exceptions.</action>
63 <action type="fix" issue="LANG-624">SystemUtils.getJavaVersionAsFloat throws StringIndexOutOfBoundsException on Android runtime/Dalvik VM.</action>
64 <action type="remove" issue="LANG-673">WordUtils.abbreviate() removed.</action>
65 <action type="fix" issue="LANG-672">Doc bug in DateUtils#ceiling.</action>
66 <action type="fix" issue="LANG-646">StringEscapeUtils.unescapeJava doesn't handle octal escapes and Unicode with extra u.</action>
67 <action type="fix" issue="LANG-662">org.apache.commons.lang3.math.Fraction does not reduce (Integer.MIN_VALUE, 2^k).</action>
68 <action type="fix" issue="LANG-663">org.apache.commons.lang3.math.Fraction does not always succeed in multiplyBy and divideBy.</action>
69 <action type="update" issue="LANG-668">Change ObjectUtils min() &amp; max() functions to use varargs rather than just two parameters.</action>
70 <action type="add" issue="LANG-667">Add a Null-safe compare() method to ObjectUtils.</action>
71 <action type="fix" issue="LANG-664">NumberUtils.isNumber(String) is not right when the String is "1.1L".</action>
72 <action type="fix" issue="LANG-659">EntityArrays typo: {"\u2122", "&amp;minus;"}, // minus sign, U+2212 ISOtech.</action>
73 <action type="fix" issue="LANG-658">Some Entitys like &amp;Ouml; are not matched properly against its ISO8859-1 representation.</action>
74 <action type="fix" issue="LANG-656">Example StringUtils.indexOfAnyBut("zzabyycdxx", '') = 0 incorrect.</action>
75 <action type="add" issue="LANG-655">Add StringUtils.defaultIfBlank().</action>
76 <action type="add" issue="LANG-653">Provide a very basic ConcurrentInitializer implementation.</action>
77 <action type="add" issue="LANG-609">Support lazy initialization using atomic variables.</action>
78 <action type="add" issue="LANG-482">Enhance StrSubstitutor to support nested ${var-${subvr}} expansion.</action>
79 <action type="add" issue="LANG-644">Provide documentation about the new concurrent package.</action>
80 <action type="fix" issue="LANG-629">Charset may not be threadsafe, because the HashSet is not synch.</action>
81 <action type="fix" issue="LANG-617">StringEscapeUtils.escapeXML() can't process UTF-16 supplementary characters.</action>
82 <action type="add" issue="LANG-614">StringUtils.endsWithAny method.</action>
83 <action type="add" issue="LANG-651">Add AnnotationUtils.</action>
84 <action type="add" issue="LANG-649">BooleanUtils.toBooleanObject to support single character input.</action>
85 <action type="fix" issue="LANG-645">FastDateFormat.format() outputs incorrect week of year because locale isn't respected.</action>
86 <action type="fix" issue="LANG-596">StrSubstitutor should also handle the default properties of a java.util.Properties class.</action>
87 <action type="fix" issue="LANG-643">Javadoc StringUtils.left() claims to throw on negative len, but doesn't.</action>
88 <action type="add" issue="LANG-640">Add normalizeSpace to StringUtils.</action>
89 <action type="fix" issue="LANG-638">NumberUtils createNumber throws a StringIndexOutOfBoundsException when argument containing "e" and "E" is passed in.</action>
90 <!-- 3.0 beta below here -->
91 <action>NOTE: The below were included in the Commons Lang 3.0-beta release.</action>
92 <action type="update" issues="LANG-510">Convert StringUtils API to take CharSequence.</action>
93 <action type="update">Push down WordUtils to "text" sub-package.</action>
94 <action type="add" issue="LANG-610">Extend exception handling in ConcurrentUtils to runtime exceptions.</action>
95 <action type="fix" issue="LANG-608">Some StringUtils methods should take an int character instead of char to use String API features.</action>
96 <action type="fix" issue="LANG-606">EqualsBuilder causes StackOverflowException.</action>
97 <action type="update" issue="LANG-605">DefaultExceptionContext overwrites values in recursive situations.</action>
98 <action type="fix" issue="LANG-602">ContextedRuntimeException no longer an 'unchecked' exception.</action>
99 <action type="add" issue="LANG-601">Add Builder Interface / Update Builders to Implement It.</action>
100 <action type="fix" issue="LANG-600">Javadoc is incorrect for public static int lastIndexOf(String str, String searchStr).</action>
101 <action type="update" issue="LANG-599">ClassUtils.getClass(): Allow Dots as Inner Class Separators.</action>
102 <action type="add" issue="LANG-594">DateUtils equal &amp; compare functions up to most significant field.</action>
103 <action type="remove" issue="LANG-590">Remove JDK 1.2/1.3 bug handling in StringUtils.indexOf(String, String, int).</action>
104 <action type="add" issue="LANG-588">Create a basic Pair&lt;L, R&gt; class.</action>
105 <action type="fix" issue="LANG-585">exception.DefaultExceptionContext.getFormattedExceptionMessage catches Throwable.</action>
106 <action type="add" issue="LANG-582">Provide an implementation of the ThreadFactory interface.</action>
107 <action type="update" issue="LANG-579">Add new Validate methods.</action>
108 <action type="fix" issue="LANG-571">ArrayUtils.add(T[] array, T element) can create unexpected ClassCastException.</action>
109 <action type="update" issue="LANG-570">Do the test cases really still require main() and suite() methods?.</action>
110 <action type="fix" issue="LANG-568">@SuppressWarnings("unchecked") is used too generally.</action>
111 <action type="fix" issue="LANG-564">Improve StrLookup API documentation.</action>
112 <action type="update" issue="LANG-563">Change Java package name.</action>
113 <action type="update" issue="LANG-562">Change Maven groupId.</action>
114 <action type="add" issue="LANG-560">New TimedSemaphore class.</action>
115 <action type="add" issue="LANG-559">Added validState validation method.</action>
116 <action type="add" issue="LANG-559">Added isAssignableFrom and isInstanceOf validation methods.</action>
117 <action type="add" issue="LANG-553">Add TypeUtils class to provide utility code for working with generic types.</action>
118 <action type="update" issue="LANG-551">Replace Range classes with generic version.</action>
119 <action type="update" issue="LANG-548">Use Iterable on API instead of Collection.</action>
120 <action type="add" issue="LANG-546">Add methods to Validate to check whether the index is valid for the array/list/string.</action>
121 <action type="add" issue="LANG-545">Add ability to create a Future for a constant.</action>
122 <action type="update" issue="LANG-541">Replace StringBuffer with StringBuilder.</action>
123 <action type="update" issue="LANG-540">Make NumericEntityEscaper immutable.</action>
124 <action type="update" issue="LANG-539">Compile commons.lang for CDC 1.1/Foundation 1.1.</action>
125 <action type="add" issue="LANG-537">Add ArrayUtils.toArray to create generic arrays.</action>
126 <action type="add" issue="LANG-533">Validate: support for validating blank strings.</action>
127 <action type="add" issue="LANG-529">Add a concurrent package.</action>
128 <action type="update" issue="LANG-528">Mutable classes should implement an appropriately typed Mutable interface.</action>
129 <action type="update" issue="LANG-513">Better EnumUtils.</action>
130 <action type="update" issue="LANG-507">StringEscapeUtils.unescapeJava should support \u+ notation.</action>
131 <action type="update" issue="LANG-505">Rewrite StringEscapeUtils.</action>
132 <action type="update" issue="LANG-504">bring ArrayUtils.isEmpty to the generics world.</action>
133 <action type="add" issue="LANG-501">Add support for background initialization.</action>
134 <action type="add" issue="LANG-499">Add support for the handling of ExecutionExceptions.</action>
135 <action type="add" issue="LANG-498">Add StringEscapeUtils.escapeText() methods.</action>
136 <action type="add" issue="LANG-497">Addition of ContextedException and ContextedRuntimeException.</action>
137 <action type="add" issue="LANG-496">A generic implementation of the Lazy initialization pattern.</action>
138 <action type="remove" issue="LANG-493">Remove code that does not hold enough value to remain.</action>
139 <action type="remove" issue="LANG-492">Remove code handled now by the JDK.</action>
140 <action type="add" issue="LANG-482">StrSubstitutor now supports substitution in variable names.</action>
141 <action type="fix" issue="LANG-481">Possible race-conditions in hashCode of the range classes.</action>
142 <action type="fix" issue="LANG-480">StringEscapeUtils.escapeHtml incorrectly converts Unicode characters above U+00FFFF into 2 characters.</action>
143 <action type="update" issue="LANG-479">Document where in SVN trunk is.</action>
144 <action type="fix" issue="LANG-478">StopWatch does not resist to system time changes.</action>
145 <action type="fix" issue="LANG-474">Fixes for thread safety.</action>
146 <action type="update" issue="LANG-458">Refactor Validate.java to eliminate code redundancy.</action>
147 <action type="fix" issue="LANG-448">Lower Ascii Characters don't get encoded by Entities.java.</action>
148 <action type="add" issue="LANG-444">StringUtils.emptyToNull.</action>
149 <action type="fix" issue="LANG-439">StringEscapeUtils.escapeHTML() does not escape chars (0x00-0x20).</action>
150 <action type="remove" issue="LANG-438">Remove @deprecateds.</action>
151 <action type="add" issue="LANG-435">Add ClassUtils.isAssignable() variants with autoboxing.</action>
152 <action type="update" issue="LANG-424">Improve Javadoc for StringUtils class.</action>
153 <action type="fix" issue="LANG-418">Javadoc incorrect for StringUtils.endsWithIgnoreCase.</action>
154 <action type="update" issue="LANG-396">Investigate for vararg usages.</action>
155 <action type="fix" issue="LANG-468">JDK 1.5 build/runtime failure on LANG-393 (EqualsBuilder).</action>
156 <action type="add" issue="LANG-386">LeftOf/RightOfNumber in Range convenience methods necessary.</action>
157 <action type="fix" issue="LANG-369">ExceptionUtils not thread-safe.</action>
158 <action type="add" issue="LANG-358">ObjectUtils.coalesce.</action>
159 <action type="update" issue="LANG-355">StrBuilder should implement CharSequence and Appendable.</action>
160 <action type="fix" issue="LANG-339">StringEscapeUtils.escapeHtml() escapes multibyte characters like Chinese, Japanes, etc.</action>
161 <action type="update" issue="LANG-336">Finally start using generics.</action>
162 <action type="fix" issue="LANG-302">StrBuilder does not implement clone().</action>
163 <action type="update" issue="LANG-290">EnumUtils for JDK 5.0.</action>
164 <action type="add" issue="LANG-285">Wish : method unaccent.</action>
165 <action type="add" issue="LANG-276">MutableBigDecimal and MutableBigInteger.</action>
166 <action type="fix" issue="LANG-66">StringEscaper.escapeXml() escapes characters &gt; 0x7f.</action>
167 <action type="fix" issue="LANG-11">Depend on JDK 1.5+.</action>
168 </release>
169
170 <release version="2.6" date="2011-01-16" description="Bug Fixes/Enhancements for the 2.6 release (requires minimum of Java 1.3)">
171 <action type="update" issue="LANG-633">BooleanUtils: use same optimization in toBooleanObject(String) as in toBoolean(String).</action>
172 <action type="update" issue="LANG-599">ClassUtils: allow Dots as Inner Class Separators in getClass().</action>
173 <action type="add" issue="LANG-594">DateUtils: equal and compare functions up to most significant field.</action>
174 <action type="add" issue="LANG-632">DateUtils: provide a Date to Calendar convenience method.</action>
175 <action type="add" issue="LANG-576">ObjectUtils: add clone methods to ObjectUtils.</action>
176 <action type="add" issue="LANG-667">ObjectUtils: add a Null-safe compare() method.</action>
177 <action type="add" issue="LANG-670">ObjectUtils: add notEqual() method.</action>
178 <action type="add" issue="LANG-302">StrBuilder: implement clone() method.</action>
179 <action type="add" issue="LANG-640">StringUtils: add a normalizeSpace() method.</action>
180 <action type="add" issue="LANG-614">StringUtils: add endsWithAny() method.</action>
181 <action type="add" issue="LANG-655">StringUtils: add defaultIfBlank() method.</action>
182 <action type="add" issue="LANG-596">StrSubstitutor: add a replace(String, Properties) variant.</action>
183 <action type="add" issue="LANG-482">StrSubstitutor: support substitution in variable names.</action>
184 <action type="update" issue="LANG-669">Use StrBuilder instead of StringBuffer to improve performance where sync. is not an issue.</action>
185 <action type="fix" issue="LANG-629">CharSet: make the underlying set synchronized.</action>
186 <action type="fix" issue="LANG-635">CompareToBuilder: fix passing along compareTransients to the reflectionCompare method.</action>
187 <action type="fix" issue="LANG-636">ExtendedMessageFormat doesn't override equals(Object).</action>
188 <action type="fix" issue="LANG-645">FastDateFormat: fix to properly include the locale when formatting a Date.</action>
189 <action type="fix" issue="LANG-638">NumberUtils: createNumber() throws a StringIndexOutOfBoundsException when argument containing "e" and "E" is passed in.</action>
190 <action type="fix" issue="LANG-607">StringUtils methods do not handle Unicode 2.0+ supplementary characters correctly.</action>
191 <action type="fix" issue="LANG-624">SystemUtils: getJavaVersionAsFloat throws StringIndexOutOfBoundsException on Android runtime/Dalvik VM.</action>
192 <action type="fix" issue="BEANUTILS-381">MemberUtils: getMatchingAccessibleMethod does not correctly handle inheritance and method overloading.</action>
193 <action type="update" issue="LANG-600">Javadoc is incorrect for lastIndexOf() method.</action>
194 <action type="update" issue="LANG-628">Javadoc for HashCodeBuilder.append(boolean) does not match implementation.</action>
195 <action type="update" issue="LANG-643">Javadoc StringUtils.left() claims to throw an exception on negative lenth, but doesn't.</action>
196 <action type="update" issue="LANG-370">Javadoc - document thread safety.</action>
197 <action type="update" issue="LANG-623">Test for StringUtils replaceChars() icelandic characters.</action>
198 </release>
199
200 <release version="2.5" date="2010-02-25" description="">
201 <action type="add" issue="LANG-583">ArrayUtils - add isNotEmpty() methods.</action>
202 <action type="add" issue="LANG-534">ArrayUtils - add nullToEmpty() methods.</action>
203 <action type="add" issue="LANG-454">CharRange - provide an iterator that lets you walk the chars in the range.</action>
204 <action type="add" issue="LANG-514">CharRange - add more readable static builder methods.</action>
205 <action type="add">ClassUtils - new isAssignable() methods with autoboxing.</action>
206 <action type="add" issue="LANG-535">ClassUtils - add support to getShortClassName and getPackageName for arrays.</action>
207 <action type="add" issue="LANG-434">DateUtils - add ceiling() method.</action>
208 <action type="add" issue="LANG-486">DateUtils - add parseDateStrictly() method.</action>
209 <action type="add" issue="LANG-466">EqualsBuilder - add reset() method.</action>
210 <action type="add" issue="LANG-461">NumberUtils - add toByte() and toShort() methods.</action>
211 <action type="add" issue="LANG-522">Mutable numbers - add string constructors.</action>
212 <action type="add">MutableBoolean - add toBoolean(), isTrue() and isFalse() methods.</action>
213 <action type="add" issue="LANG-422">StrBuilder - add appendSeparator() methods with an alternative default separator if the StrBuilder is currently empty.</action>
214 <action type="add" issue="LANG-555">SystemUtils - add IS_OS_WINDOWS_7 constant.</action>
215 <action type="add" issue="LANG-554">SystemUtils - add IS_JAVA_1_7 constant for JDK 1.7.</action>
216 <action type="add" issue="LANG-405">StringUtils - add abbreviateMiddle() method.</action>
217 <action type="add" issue="LANG-569">StringUtils - add indexOfIgnoreCase() and lastIndexOfIgnoreCase() methods.</action>
218 <action type="add" issue="LANG-471">StringUtils - add isAllUpperCase() and isAllLowerCase() methods.</action>
219 <action type="add" issue="LANG-469">StringUtils - add lastOrdinalIndexOf() method to complement the existing ordinalIndexOf() method.</action>
220 <action type="add" issue="LANG-348">StringUtils - add repeat() method.</action>
221 <action type="add" issue="LANG-445">StringUtils - add startsWithAny() method.</action>
222 <action type="add" issue="LANG-430">StringUtils - add upperCase(String, Locale) and lowerCase(String, Locale) methods.</action>
223 <action type="add" issue="LANG-416">New Reflection package containing ConstructorUtils, FieldUtils, MemberUtils and MethodUtils.</action>
224 <action type="fix" issue="LANG-567">ArrayUtils - addAll() does not handle mixed types very well.</action>
225 <action type="fix" issue="LANG-494">CharSet - Synchronizing the COMMON Map so that getInstance doesn't miss a put from a subclass in another thread.</action>
226 <action type="fix" issue="LANG-500">ClassUtils - improving performance of getAllInterfaces.</action>
227 <action type="fix" issue="LANG-587">ClassUtils - toClass() throws NullPointerException on null array element.</action>
228 <action type="fix" issue="LANG-530">DateUtils - Fix parseDate() cannot parse ISO8601 dates produced by FastDateFormat.</action>
229 <action type="fix" issue="LANG-440">DateUtils - round() doesn't work correct for Calendar.AM_PM.</action>
230 <action type="fix" issue="LANG-443">DateUtils - improve tests.</action>
231 <action type="fix" issue="LANG-204">Entities - multithreaded initialization.</action>
232 <action type="fix" issue="LANG-506">Entities - missing final modifiers; thread-safety issues.</action>
233 <action type="fix" issue="LANG-76">EnumUtils - getEnum() doesn't work well in 1.5+.</action>
234 <action type="fix" issue="LANG-584">ExceptionUtils - use immutable lock target.</action>
235 <action type="fix" issue="LANG-477">ExtendedMessageFormat - OutOfMemory with a pattern containing single quotes.</action>
236 <action type="fix" issue="LANG-538">FastDateFormat - call getTime() on a calendar to ensure timezone is in the right state.</action>
237 <action type="fix" issue="LANG-547">FastDateFormat - Remove unused field.</action>
238 <action type="fix" issue="LANG-511">LocaleUtils - Initialization of available locales in LocaleUtils can be deferred.</action>
239 <action type="fix" issue="LANG-457">NumberUtils - createNumber() thows a StringIndexOutOfBoundsException when only an "l" is passed in.</action>
240 <action type="fix" issue="LANG-521">NumberUtils - isNumber(String) and createNumber(String) both modified to support '2.'.</action>
241 <action type="fix" issue="LANG-432">StringUtils - improve handling of case-insensitive Strings.</action>
242 <action type="fix" issue="LANG-552">StringUtils - replaceEach() no longer NPEs when null appears in the last String[].</action>
243 <action type="fix" issue="LANG-460">StringUtils - correct JavaDocs for startsWith() and startsWithIgnoreCase().</action>
244 <action type="fix" issue="LANG-421">StringEscapeUtils - escapeJava() escapes '/' characters.</action>
245 <action type="fix" issue="LANG-450">StringEscapeUtils - change escapeJavaStyleString() to throw UnhandledException instead swallowing IOException and returning null.</action>
246 <action type="fix" issue="LANG-419">WordUtils - fix StringIndexOutOfBoundsException when lower is greater than the String length.</action>
247 <action type="fix" issue="LANG-523">StrBuilder - Performance improvement by doubling the size of the String in ensureCapacity.</action>
248 <action type="fix" issue="LANG-575">Compare, Equals and HashCode builders - use ArrayUtils to avoid creating a temporary List.</action>
249 <action type="fix" issue="LANG-467">EqualsBuilder - removing the special handling of BigDecimal (LANG-393) to use compareTo instead of equals because it creates an inequality with HashCodeBuilder.</action>
250 <action type="fix" issue="LANG-574">HashCodeBuilder - Performance improvement: check for isArray to short-circuit the 9 instanceof checks.</action>
251 <action type="fix" issue="LANG-520">HashCodeBuilder - Changing the hashCode() method to return toHashCode().</action>
252 <action type="fix" issue="LANG-459">HashCodeBuilder - reflectionHashCode() can generate incorrect hashcodes.</action>
253 <action type="fix" issue="LANG-586">HashCodeBuilder and ToStringStyle - use of ThreadLocal causes memory leaks in container environments.</action>
254 <action type="fix" issue="LANG-487">ToStringBuilder - make default style thread-safe.</action>
255 <action type="fix" issue="LANG-472">RandomUtils - nextLong() always produces even numbers.</action>
256 <action type="fix" issue="LANG-592">RandomUtils - RandomUtils tests are failing frequently.</action>
257 </release>
258
259 <release version="2.4" date="2008-03-18" description="">
260 <action type="add" issue="LANG-322">ClassUtils.getShortClassName(String) inefficient.</action>
261 <action type="add" issue="LANG-269">Shouldn't Commons Lang's StringUtils have a "common" string method?.</action>
262 <action type="fix" issue="LANG-368">FastDateFormat getDateInstance() and getDateTimeInstance() assume Locale.getDefault() won't change.</action>
263 <action type="add" issue="LANG-402">OSGi-ify Lang.</action>
264 <action type="fix" issue="LANG-412">StrBuilder appendFixedWidth does not handle nulls.</action>
265 <action type="fix" issue="LANG-380">infinite loop in Fraction.reduce when numerator == 0.</action>
266 <action type="fix" issue="LANG-367">FastDateFormat thread safety.</action>
267 <action type="add" issue="LANG-298">ClassUtils.getShortClassName and ClassUtils.getPackageName and class of array.</action>
268 <action type="fix" issue="LANG-328">LocaleUtils.toLocale() rejects strings with only language+variant.</action>
269 <action type="fix" issue="LANG-334">Enum is not thread-safe.</action>
270 <action type="fix" issue="LANG-365">BooleanUtils.toBoolean() - invalid drop-thru in case statement causes StringIndexOutOfBoundsException.</action>
271 <action type="add" issue="LANG-333">ArrayUtils.toClass.</action>
272 <action type="fix" issue="LANG-360">Why does appendIdentityToString return null?.</action>
273 <action type="fix" issue="LANG-381">NumberUtils.min(floatArray) returns wrong value if floatArray[0] happens to be Float.NaN.</action>
274 <action type="fix" issue="LANG-346">Dates.round() behaves incorrectly for minutes and seconds.</action>
275 <action type="add" issue="LANG-407">StringUtils.length(String) returns null-safe length.</action>
276 <action type="add" issue="LANG-180">adding a StringUtils.replace method that takes an array or List of replacement strings.</action>
277 <action type="add" issue="LANG-383">Adding functionality to DateUtils to allow direct setting of various fields.</action>
278 <action type="add" issue="LANG-374">Add escaping for CSV columns to StringEscapeUtils.</action>
279 <action type="add" issue="LANG-326">StringUtils: startsWith / endsWith / startsWithIgnoreCase / endsWithIgnoreCase / removeStartIgnoreCase / removeEndIgnoreCase methods.</action>
280 <action type="add" issue="LANG-351">Extension to ClassUtils: Obtain the primitive class from a wrapper.</action>
281 <action type="fix" issue="LANG-399">Javadoc bugs - cannot find object.</action>
282 <action type="add" issue="LANG-345">Optimize HashCodeBuilder.append(Object).</action>
283 <action type="fix" issue="LANG-385">http://commons.apache.org/lang/developerguide.html "Building" section is incorrect and incomplete.</action>
284 <action type="fix" issue="LANG-410">Ambiguous / confusing names in StringUtils replace* methods.</action>
285 <action type="add" issue="LANG-257">Add new splitByWholeSeparatorPreserveAllTokens() methods to StringUtils.</action>
286 <action type="add" issue="LANG-356">Add getStartTime to StopWatch.</action>
287 <action type="add" issue="LANG-377">Perhaps add containsAny() methods?.</action>
288 <action type="fix" issue="LANG-353">Javadoc Example for EqualsBuilder is questionable.</action>
289 <action type="fix" issue="LANG-393">EqualsBuilder don't compare BigDecimals correctly.</action>
290 <action type="add" issue="LANG-192">Split camel case strings.</action>
291 <action type="add" issue="LANG-404">Add Calendar flavour format methods to DateFormatUtils.</action>
292 <action type="add" issue="LANG-379">Calculating A date fragment in any time-unit.</action>
293 <action type="add" issue="LANG-413">Memory usage improvement for StringUtils#getLevenshteinDistance().</action>
294 <action type="add" issue="LANG-362">Add ExtendedMessageFormat to org.apache.commons.lang.text.</action>
295 <action type="fix" issue="LANG-363">StringEscapeUtils.escapeJavaScript() method did not escape '/' into '\/', it will make IE render page uncorrectly.</action>
296 <action type="add" issue="LANG-321">Add toArray() method to IntRange and LongRange classes.</action>
297 <action type="add" issue="LANG-375">add SystemUtils.IS_OS_WINDOWS_VISTA field.</action>
298 <action type="add" issue="LANG-329">Pointless synchronized in ThreadLocal.initialValue should be removed.</action>
299 <action type="add" issue="LANG-371">ToStringStyle javadoc should show examples of styles.</action>
300 <action type="fix" issue="LANG-364">Documentation bug for ignoreEmptyTokens accessors in StrTokenizer.</action>
301 <action type="fix" issue="LANG-361">BooleanUtils toBooleanObject javadoc does not match implementation.</action>
302 <action type="add" issue="LANG-338">truncateNicely method which avoids truncating in the middle of a word.</action>
303 </release>
304
305 <release version="2.3" date="2007-02-13" description="">
306 <action type="fix" issue="LANG-262">Use of enum prevents a classloader from being garbage collected resuling in out of memory exceptions.</action>
307 <action type="add" issue="LANG-289">NumberUtils.max(byte[]) and NumberUtils.min(byte[]) are missing.</action>
308 <action type="add" issue="LANG-291">Null-safe comparison methods for finding most recent / least recent dates.</action>
309 <action type="fix" issue="LANG-315">StopWatch: suspend() acts as split(), if followed by stop().</action>
310 <action type="fix" issue="LANG-294">StrBuilder.replaceAll and StrBuilder.deleteAll can throw ArrayIndexOutOfBoundsException.</action>
311 <action type="fix" issue="LANG-299">Bug in method appendFixedWidthPadRight of class StrBuilder causes an ArrayIndexOutOfBoundsException.</action>
312 <action type="fix" issue="LANG-69"> ToStringBuilder throws StackOverflowError when an Object cycle exists.</action>
313 <action type="add" issue="LANG-282">Create more tests to test out the +=31 replacement code in DurationFormatUtils.</action>
314 <action type="fix" issue="LANG-295">StrBuilder contains usages of thisBuf.length when they should use size.</action>
315 <action type="add" issue="LANG-258">Enum JavaDoc: 1) outline 5.0 native Enum migration 2) warn not to use the switch() , 3) point out approaches for persistence and gui.</action>
316 <action type="fix" issue="LANG-313">Wrong behavior of Entities.unescape.</action>
317 <action type="fix" issue="LANG-300">NumberUtils.createNumber throws NumberFormatException for one digit long.</action>
318 <action type="fix" issue="LANG-304">NullPointerException in isAvailableLocale(Locale).</action>
319 <action type="fix" issue="LANG-303">FastDateFormat.mRules is not transient or serializable.</action>
320 <action type="add" issue="LANG-268">StringUtils.join should allow you to pass a range for it (so it only joins a part of the array).</action>
321 <action type="fix" issue="LANG-102">Refactor Entities methods.</action>
322 <action type="fix" issue="LANG-314">Tests fail to pass when building with Maven 2.</action>
323 <action type="fix" issue="LANG-281">DurationFormatUtils returns wrong result.</action>
324 <action type="fix" issue="LANG-292">unescapeXml("&amp;12345678;") should be "&amp;12345678;".</action>
325 <action type="add" issue="LANG-287">Optimize StringEscapeUtils.unescapeXml(String).</action>
326 <action type="add" issue="LANG-310">BooleanUtils isNotTrue/isNotFalse.</action>
327 <action type="add" issue="LANG-306">Extra StrBuilder methods.</action>
328 <action type="add" issue="LANG-275">Add a pair of StringUtils.substringsBetween;String[] methods.</action>
329 <action type="fix" issue="LANG-279">HashCodeBuilder throws java.lang.StackOverflowError when an object contains a cycle.</action>
330 <action type="add" issue="LANG-266">Wish for StringUtils.join(Collection, *).</action>
331 </release>
332
333 <release version="2.2" date="2006-10-04" description="">
334 <action type="fix" issue="LANG-45">StrBuilderTest#testReplaceStringString fails.</action>
335 <action type="fix" issue="LANG-42">EqualsBuilder.append(Object[], Object[]) crashes with a NullPointerException if an element of the first array is null.</action>
336 <action type="fix" issue="LANG-286">Serialization - not backwards compatible.</action>
337 <action type="fix" issue="LANG-50"> Replace Clover with Cobertura.</action>
338 <action type="fix" issue="LANG-259">ValuedEnum.compareTo(Object other) not typesafe - it easily could be...</action>
339 <action type="fix" issue="LANG-271">LocaleUtils test fails under Mustang.</action>
340 <action type="fix" issue="LANG-2">javadoc example for StringUtils.splitByWholeSeparator incorrect.</action>
341 <action type="fix" issue="LANG-3">PADDING array in StringUtils overflows on '\uffff'.</action>
342 <action type="fix" issue="LANG-10">ClassUtils.primitiveToWrapper and Void.</action>
343 <action type="fix" issue="LANG-37">unit test for org.apache.commons.lang.text.StrBuilder.</action>
344 <action type="fix" issue="LANG-59">DateUtils.truncate method is buggy when dealing with DST switching hours.</action>
345 <action type="fix" issue="LANG-100">RandomStringUtils.random() family of methods create invalid Unicode sequences.</action>
346 <action type="fix" issue="LANG-106">StringUtils#getLevenshteinDistance() performance is sub-optimal.</action>
347 <action type="fix" issue="LANG-112">Wrong length check in StrTokenizer.StringMatcher.</action>
348 <action type="fix" issue="LANG-105">ExceptionUtils goes into infinite loop in getThrowables is throwable.getCause() == throwable.</action>
349 <action type="fix" issue="LANG-117">FastDateFormat: wrong format for date "01.01.1000".</action>
350 <action type="fix" issue="LANG-123">Unclear javadoc for DateUtils.iterator().</action>
351 <action type="fix" issue="LANG-130">Memory "leak" in StringUtils.</action>
352 <action type="add" issue="LANG-260">StringEscapeUtils should expose escape*() methods taking Writer argument.</action>
353 <action type="fix" issue="LANG-141">Fraction.toProperString() returns -1/1 for -1.</action>
354 <action type="fix" issue="LANG-152">DurationFormatUtils.formatDurationWords "11 &lt;unit&gt;s" gets converted to "11 &lt;unit&gt;".</action>
355 <action type="fix" issue="LANG-148">Performance modifications on StringUtils.replace.</action>
356 <action type="fix" issue="LANG-150">StringEscapeUtils.unescapeHtml skips first entity after standalone ampersand.</action>
357 <action type="fix" issue="LANG-140">DurationFormatUtils.formatPeriod() returns the wrong result.</action>
358 <action type="add" issue="LANG-186">Request for MutableBoolean implementation.</action>
359 <action type="add" issue="LANG-198">New method for EqualsBuilder.</action>
360 <action type="add" issue="LANG-212">New ExceptionUtils method setCause().</action>
361 <action type="add" issue="LANG-217">Add Mutable&lt;Type&gt; to&lt;Type&gt;() methods.</action>
362 <action type="add" issue="LANG-216">Provides a Class.getPublicMethod which returns public invocable Method.</action>
363 <action type="add" issue="LANG-226">Using ReflectionToStringBuilder and excluding secure fields.</action>
364 <action type="add" issue="LANG-194">add generic add method to DateUtils.</action>
365 <action type="add" issue="LANG-220">Tokenizer Enhancements: reset input string, static CSV/TSV factories.</action>
366 <action type="add" issue="LANG-242">Trivial cleanup of javadoc in various files.</action>
367 <action type="add" issue="LANG-246">CompositeFormat.</action>
368 <action type="add" issue="LANG-250">Performance boost for RandomStringUtils.</action>
369 <action type="add" issue="LANG-254">Enhanced Class.forName version.</action>
370 <action type="add" issue="LANG-263">Add StringUtils.containsIgnoreCase(...).</action>
371 <action type="add" issue="LANG-267">Support char array converters on ArrayUtils.</action>
372 <action type="fix" issue="LANG-25">DurationFormatUtils.formatDurationISO() javadoc is missing T in duration string between date and time part.</action>
373 <action type="fix" issue="LANG-272">Minor build and checkstyle changes.</action>
374 <action type="fix" issue="LANG-277">Javadoc errors on StringUtils.splitPreserveAllTokens(String, char).</action>
375 <action type="fix" issue="LANG-122">EscapeUtil.escapeHtml() should clarify that it does not escape ' chars to &amp;apos;.</action>
376 <action type="add" issue="LANG-161">Add methods and tests to StrBuilder.</action>
377 <action type="add" issue="LANG-162">replace() length calculation improvement.</action>
378 <action type="add" issue="LANG-166">New interpolation features.</action>
379 <action type="add" issue="LANG-169">Implementation of escape/unescapeHtml methods with Writer.</action>
380 <action type="add" issue="LANG-176">CompareToBuilder excludeFields for reflection method.</action>
381 <action type="add" issue="LANG-159">Add WordUtils.getInitials(String).</action>
382 <action type="fix" issue="LANG-261">Error in an example in the javadoc of the StringUtils.splitPreserveAllTokens() method.</action>
383 <action type="fix" issue="LANG-264">ToStringBuilder/HashCodeBuilder javadoc code examples.</action>
384 <action type="fix" issue="LANG-265">Cannot build tests from latest SVN.</action>
385 <action type="add" issue="LANG-270">minor javadoc improvements for StringUtils.stripXxx() methods.</action>
386 <action type="fix" issue="LANG-278">javadoc for StringUtils.removeEnd is incorrect.</action>
387 <action type="fix" issue="LANG-127">Minor tweak to fix of bug # 26616.</action>
388 </release>
389
390 <release version="2.1" date="2005-06-13" description="">
391 <action type="fix" issue="LANG-103">make optional parameters in FastDateFormat really optional.</action>
392 <action type="fix" issue="LANG-149">Nestable.indexOfThrowable(Class) uses Class.equals() to match.</action>
393 <action type="fix" issue="LANG-30">buffer under/overrun on Strings.strip, stripStart &amp; stripEnd.</action>
394 <action type="fix" issue="LANG-19">ToStringStyle.setArrayEnd(String) doesn't replace null with empty string.</action>
395 <action type="fix" issue="LANG-80">New class proposal: CharacterEncoding.</action>
396 <action type="fix" issue="LANG-43">SystemUtils fails init on HP-UX.</action>
397 <action type="fix" issue="LANG-134">javadoc - 'four basic XML entities' should be 5 (apos is missing).</action>
398 <action type="fix" issue="LANG-156">o.a.c.lang.enum.ValuedEnum: 'enum'is a keyword in JDK1.5.0.</action>
399 <action type="fix" issue="LANG-131">StringEscapeUtils.unescapeHtml() doesn't handle an empty entity.</action>
400 <action type="fix" issue="LANG-6">EqualsBuilder.append(Object[], Object[]) incorrectly checks that rhs[i] is instance of lhs[i]'s class.</action>
401 <action type="fix" issue="LANG-33">Method enums.Enum.equals(Object o) doesn't work correctly.</action>
402 <action type="fix" issue="LANG-31">ExceptionUtils.addCauseMethodName(String) does not check for duplicates.</action>
403 <action type="fix" issue="LANG-136">Make StopWatch validate state transitions.</action>
404 <action type="fix" issue="LANG-124">enum package is not compatible with 1.5 jdk.</action>
405 <action type="fix" issue="LANG-128">WordUtils capitalizeFully() throws a null pointer exception.</action>
406 <action type="fix" issue="LANG-138">ValuedEnum.</action>
407 <action type="fix" issue="LANG-133">parseDate class from HttpClient's DateParser class.</action>
408 <action type="fix" issue="LANG-62">ArrayUtils.isEquals() throws ClassCastException when array1 and array2 are different dimension.</action>
409 <action type="fix" issue="LANG-57">ClassCastException in Enum.equals(Object).</action>
410 <action type="fix" issue="LANG-107">FastDateFormat year bug.</action>
411 <action type="fix" issue="LANG-77">unbalanced ReflectionToStringBuilder.</action>
412 <action type="fix" issue="LANG-86">FastDateFormat.getDateInstance(int, Locale) always uses the pattern from the first invocation.</action>
413 <action type="fix" issue="LANG-79">ReflectionToStringBuilder.toString(null) throws exception by design.</action>
414 <action type="fix" issue="LANG-126">Make ClassUtils methods null-safe and not throw an IAE.</action>
415 <action type="fix" issue="LANG-5">StringUtils.split ignores empty items.</action>
416 <action type="fix" issue="LANG-144">EqualsBuilder.append(Object[], Object[]) throws NPE.</action>
417 <action type="fix" issue="LANG-74">ArrayUtils.addAll doesn't always return new array.</action>
418 <action type="fix" issue="LANG-81">Enum.equals does not handle different class loaders.</action>
419 <action type="fix" issue="LANG-27">Add SystemUtils.AWT_TOOLKIT and others.</action>
420 <action type="fix" issue="LANG-14">Throwable cause for NotImplementedException.</action>
421 <action type="fix" issue="LANG-28">ClassUtils.primitivesToWrappers method.</action>
422 <action type="fix" issue="LANG-120">public static boolean DateUtils.equals(Date dt1, Date dt2) ?.</action>
423 <action type="fix" issue="LANG-7">Documentation error in StringUtils.replace.</action>
424 <action type="fix" issue="LANG-125">DateUtils constants should be long.</action>
425 <action type="fix" issue="LANG-13">DateUtils.truncate() is off by one hour when using a date in DST switch 'zone'.</action>
426 <action type="fix" issue="LANG-118">StringEscapeUtils.unescapeHtml() doesn't handle hex entities.</action>
427 <action type="fix" issue="LANG-99">new StringUtils.replaceChars behaves differently from old CharSetUtils.translate.</action>
428 <action type="fix" issue="LANG-41">last substring returned by StringUtils.split( String, String, int ) is too long.</action>
429 <action type="fix" issue="LANG-119">Can't subclass EqualsBuilder because isEquals is private.</action>
430 <action type="fix" issue="LANG-158">new StringUtils.split methods that split on the whole separator string.</action>
431 <action type="add" issue="LANG-172">New method for converting a primitive Class to its corresponding wrapper Class.</action>
432 <action type="add" issue="LANG-222">Add convenience format(long) methods to FastDateFormat.</action>
433 <action type="fix" issue="LANG-116">Enum's outer class may not be loaded for EnumUtils.</action>
434 <action type="add" issue="LANG-219">WordUtils.capitalizeFully(String str) should take a delimiter.</action>
435 <action type="add" issue="LANG-183">Make javadoc crosslinking configurable.</action>
436 <action type="fix" issue="LANG-82">Minor javadoc fixes for StringUtils.contains(String, String).</action>
437 <action type="fix" issue="LANG-32">Error in JavaDoc for StringUtils.chomp(String, String).</action>
438 <action type="fix" issue="LANG-95">StringUtils.defaultString: Documentation error.</action>
439 <action type="add" issue="LANG-233">Add hashCode-support to class ObjectUtils.</action>
440 <action type="add" issue="LANG-202">add another "known method" to ExceptionUtils.</action>
441 <action type="add" issue="LANG-235">Enhancement of ExceptionUtils.CAUSE_METHOD_NAMES.</action>
442 <action type="fix" issue="LANG-24">DateUtils.truncate oddity at the far end of the Date spectrum.</action>
443 <action type="add" issue="LANG-232">add getLength() method to ArrayUtils.</action>
444 <action type="add" issue="LANG-171">Validate.java: fixes comment skew, removes unused loop counter.</action>
445 <action type="add" issue="LANG-179">StringUtils.isAsciiPrintable().</action>
446 <action type="add" issue="LANG-167">ExceptionUtils: new getCause() methodname (for tomcat-exception).</action>
447 <action type="fix" issue="LANG-85">fixes 75 typos.</action>
448 <action type="add" issue="LANG-230">mutable numbers.</action>
449 <action type="add" issue="LANG-191">Javadoc fixes for ClassUtils.</action>
450 <action type="add" issue="LANG-184">Add StringUtils.nIndexOf?.</action>
451 <action type="fix" issue="LANG-135">Javadoc fixes for CharSetUtils.</action>
452 <action type="fix" issue="LANG-154">Remove redundant check for null separator in StringUtils#join.</action>
453 <action type="add" issue="LANG-247">Class and Package Comparators for ClassUtils.</action>
454 <action type="add" issue="LANG-256">add remove methods to ArrayUtils.</action>
455 <action type="add" issue="LANG-185">WordUtils capitalize improvement.</action>
456 <action type="add" issue="LANG-173">add isEmpty method to ArrayUtils.</action>
457 <action type="add" issue="LANG-168">lang.math.Fraction class deficiencies.</action>
458 <action type="add" issue="LANG-207">Add methods to ArrayUtils: add at end and insert-like ops.</action>
459 <action type="add" issue="LANG-239">Add SystemUtils methods for directory properties.</action>
460 <action type="add" issue="LANG-189">Add method that validates Collection elements are a certain type.</action>
461 <action type="add" issue="LANG-224">elapsed time formatting utility method.</action>
462 </release>
463
464 <release version="2.0" date="2003-09-02" description="">
465 <action type="fix" issue="LANG-20">Infinite loop in ToStringBuilder.reflectionToString for inner classes.</action>
466 <action type="fix" issue="LANG-75">NumberUtils.createBigDecimal("") NPE in Sun 1.3.1_08.</action>
467 <action type="fix" issue="LANG-38">Rationalize StringUtils slice functions.</action>
468 <action type="fix" issue="LANG-53">SystemUtils.IS_OS_OS2 Javadoc is wrong.</action>
469 <action type="fix" issue="LANG-142">A small, but important javadoc fix for Fraction proper whole and numerator.</action>
470 <action type="fix" issue="LANG-70">Adding tolerance to double[] search methods in ArrayUtils.</action>
471 <action type="fix" issue="LANG-9">lang.builder classes javadoc edits (mostly typo fixes).</action>
472 <action type="fix" issue="LANG-63">StringUtils javadoc and test enhancements.</action>
473 <action type="fix" issue="LANG-132">SystemUtils.IS_OS_*, IS_JAVA_* are always false.</action>
474 <action type="fix" issue="LANG-143">Improve util.Validate tests.</action>
475 <action type="fix" issue="LANG-155">maven-beta10 checkstyle problem.</action>
476 <action type="fix" issue="LANG-147">StringUtils.chopNewLine - StringIndexOutOfBoundsException.</action>
477 <action type="fix" issue="LANG-73">ToStringBuilder doesn't work well in subclasses.</action>
478 <action type="fix" issue="LANG-48">static option for reversing the stacktrace.</action>
479 <action type="fix" issue="LANG-87">NullPointerException in CompareToBuilder.</action>
480 <action type="fix" issue="LANG-84">RandomStringUtils.randomAlpha methods omit 'z'.</action>
481 <action type="fix" issue="LANG-129">test.time fails in Japanese (non-us) locale.</action>
482 <action type="fix" issue="LANG-94">NumberUtils.isNumber allows illegal trailing characters.</action>
483 <action type="fix" issue="LANG-137">Improve javadoc and overflow behavior of Fraction.</action>
484 <action type="fix" issue="LANG-55">RandomStringUtils infloops with length &gt; 1.</action>
485 <action type="fix" issue="LANG-47">test.lang fails if compiled with non iso-8859-1 locales.</action>
486 <action type="fix" issue="LANG-113">SystemUtils does not play nice in an Applet.</action>
487 <action type="fix" issue="LANG-111">time unit tests fail on Sundays.</action>
488 <action type="fix" issue="LANG-90">java.lang.ExceptionInInitializerError thrown by JVMRandom constructor.</action>
489 <action type="fix" issue="LANG-78">StringUtils.chomp does not match Perl.</action>
490 <action type="fix" issue="LANG-36">patch and test case fixing problem with RandomStringUtils.random().</action>
491 <action type="fix" issue="LANG-151">General case: infinite loop: ToStringBuilder.reflectionToString.</action>
492 <action type="fix" issue="LANG-35">Should ToStringBuilder.reflectionToString handle arrays?.</action>
493 <action type="fix" issue="LANG-83">EnumUtils nit: The import java.io.Serializable is never used.</action>
494 <action type="fix" issue="LANG-12">Example in Javadoc for ToStringBuilder wrong for append.</action>
495 <action type="fix" issue="LANG-110">Added class hierachy support to HashCodeBuilder.reflectionHashCode().</action>
496 <action type="fix" issue="LANG-71">ExceptionUtils new methods.</action>
497 <action type="fix" issue="LANG-15">Infinite loop in StringUtils.replace(text, repl, with) + FIX.</action>
498 <action type="fix" issue="LANG-93">StackOverflow due to ToStringBuilder.</action>
499 <action type="fix" issue="LANG-39">No Javadoc for NestableDelegate.</action>
500 <action type="fix" issue="LANG-49">Specify initial size for Enum's HashMap.</action>
501 <action type="fix" issue="LANG-146">Enum does not support inner sub-classes.</action>
502 <action type="fix" issue="LANG-157">Removed compile warning in ObjectUtils.</action>
503 <action type="fix" issue="LANG-96">SystemUtils.IS_JAVA_1_5 Javadoc is wrong.</action>
504 <action type="fix" issue="LANG-16">NumberRange inaccurate for Long, etc.</action>
505 <action type="fix" issue="LANG-4">Hierarchy support in ToStringBuilder.reflectionToString().</action>
506 <action type="fix" issue="LANG-56">StringUtils.countMatches loops forever if substring empty.</action>
507 <action type="add" issue="LANG-209">javadoc fixes (remove @links to non-public identifiers).</action>
508 <action type="add" issue="LANG-210">Add javadoc examples and tests for StringUtils.</action>
509 <action type="add" issue="LANG-170">Make NumberUtils null handling consistent.</action>
510 <action type="fix" issue="LANG-145">Unused field 'startFinal' in DateIterator.</action>
511 <action type="add" issue="LANG-214">reduce object creation in ToStringBuilder.</action>
512 <action type="add" issue="LANG-228">Improved tests, javadoc for CharSetUtils, StringEscapeUtils.</action>
513 <action type="add" issue="LANG-252">NumberUtils min/max, BooleanUtils.xor, and ArrayUtils toPrimitive and toObject.</action>
514 <action type="add" issue="LANG-208">Javadoc, tests improvements for CharSet, CharSetUtils.</action>
515 <action type="add" issue="LANG-205">StringUtil enhancement.</action>
516 <action type="add" issue="LANG-164">Javadoc nit.</action>
517 <action type="add" issue="LANG-206">Additional Lang Method Suggestions.</action>
518 <action type="add" issue="LANG-178">Make NestableDelegate methods public instead of package private.</action>
519 <action type="add" issue="LANG-174">Missing @since tags.</action>
520 <action type="add" issue="LANG-245">Refactored reflection feature of ToStringBuilder into new ReflectionToStringBuilder.</action>
521 <action type="fix" issue="LANG-51">Typo in documentation.</action>
522 <action type="fix" issue="LANG-1">Patch for javadocs.</action>
523 <action type="add" issue="LANG-244">Add join(..., char c) to StringUtils (and some performance fixes). Even contains tests!.</action>
524 <action type="add" issue="LANG-231">Resurrect the WordWrapUtils from commons-sandbox/utils.</action>
525 <action type="fix" issue="LANG-139">EnumTest fails on Linux Sun JDK 1.3.0.</action>
526 <action type="add" issue="LANG-234">What to do with FastDateFormat unused private constructors.</action>
527 <action type="add" issue="LANG-240">Added class hierachy support to CompareToBuilder.reflectionCompare().</action>
528 <action type="add" issue="LANG-190">Removed compile warning in FastDateFormat.</action>
529 <action type="fix" issue="LANG-97">typo in the javadoc example code.</action>
530 <action type="add" issue="LANG-249">MethodUtils: Removed unused code/unused local vars.</action>
531 <action type="add" issue="LANG-237">Hierarchy support in EqualsBuilder.reflectionEquals().</action>
532 <action type="fix" issue="LANG-91">JavaDoc Errata.</action>
533 <action type="add" issue="LANG-215">ArrayUtils.contains().</action>
534 <action type="add" issue="LANG-221">More flexibility for getRootCause in ExceptionUtils.</action>
535 </release>
536
537 <release version="1.0.1" date="2002-11-25" description="Quick bugfix to 1.0">
538 <action type="fix">NumberRange.getMaximum returns minimum.</action>
539 <action type="fix">Enum constructor validations.</action>
540 <action type="fix">NestableException/Delegate is not serializable.</action>
541 <action type="fix">split using null and max less than actual token count adds "null".</action>
542 <action type="add">ExceptionUtils cannot handle J2EE-Exception in a default way.</action>
543 </release>
544
545 <release version="1.0" date="2002-10-04" description="First release of Commons Lang">
546 </release>
547
548 </body>
549 </document>
0 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <!-- Generated by Apache Maven Doxia at Jul 13, 2011 ( $Revision: 1080083 $ ) -->
18 <!-- $HeadURL: https://svn.apache.org/repos/asf/commons/proper/commons-skin/trunk/src/main/resources/META-INF/maven/site.vm $ -->
19 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
20 <head>
21 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
22 <title>Lang - Clirr Results</title>
23 <style type="text/css" media="all">
24 @import url("./css/maven-base.css");
25 @import url("./css/maven-theme.css");
26 @import url("./css/site.css");
27 </style>
28 <link rel="stylesheet" href="./css/print.css" type="text/css" media="print" />
29 <meta name="Date-Revision-yyyymmdd" content="20110713" />
30 <meta http-equiv="Content-Language" content="en" />
31
32 <link rel="stylesheet" type="text/css" href="./css/prettify.css" media="all"/>
33 <script src="./js/prettify.js" type="text/javascript"></script>
34 <script type="text/javascript">window.onload=function() {
35 prettyPrint();
36 }</script>
37 </head>
38 <body class="composite">
39 <div id="banner">
40 <div id="bannerLeft">
41 <a href="http://commons.apache.org/" title="Apache Commons logo">
42 <img src="./images/commons-logo.png" alt="Apache Commons logo"/>
43 </a>
44 </div><!-- id="bannerLeft" -->
45 <div id="bannerRight">
46 <a href="index.html">
47 <img src="images/logo.png" alt="Commons Lang"/>
48 </a>
49 </div><!-- id="bannerRight" -->
50 <div class="clear">
51 <hr/>
52 </div>
53 </div>
54 <div id="breadcrumbs">
55
56
57 <div class="xleft">
58 <span id="publishDate">Last Published: 13 July 2011</span>
59 &nbsp;| <span id="projectVersion">Version: 3.0</span>
60 </div>
61 <div class="xright"> <a href="http://www.apachecon.com/" class="externalLink" title="ApacheCon">ApacheCon</a>
62 |
63 <a href="http://www.apache.org" class="externalLink" title="Apache">Apache</a>
64 |
65 <a href="../" title="Commons">Commons</a>
66
67
68 </div>
69 <div class="clear">
70 <hr/>
71 </div>
72 </div>
73 <div id="leftColumn">
74 <div id="navcolumn">
75
76
77 <h5>Lang</h5>
78 <ul>
79 <li class="none">
80 <a href="index.html" title="Overview">Overview</a>
81 </li>
82 <li class="none">
83 <a href="download_lang.cgi" title="Download">Download</a>
84 </li>
85 <li class="none">
86 <a href="userguide.html" title="Users guide">Users guide</a>
87 </li>
88 <li class="none">
89 <a href="release-history.html" title="Release History">Release History</a>
90 </li>
91 <li class="none">
92 <a href="api-release/index.html" title="Javadoc (3.0 release)">Javadoc (3.0 release)</a>
93 </li>
94 </ul>
95 <h5>Development</h5>
96 <ul>
97 <li class="none">
98 <a href="building.html" title="Building">Building</a>
99 </li>
100 <li class="none">
101 <a href="mail-lists.html" title="Mailing Lists">Mailing Lists</a>
102 </li>
103 <li class="none">
104 <a href="issue-tracking.html" title="Issue Tracking">Issue Tracking</a>
105 </li>
106 <li class="none">
107 <a href="proposal.html" title="Proposal">Proposal</a>
108 </li>
109 <li class="none">
110 <a href="developerguide.html" title="Developer guide">Developer guide</a>
111 </li>
112 <li class="none">
113 <a href="source-repository.html" title="Source Repository">Source Repository</a>
114 </li>
115 <li class="none">
116 <a href="apidocs/index.html" title="Javadoc (SVN latest)">Javadoc (SVN latest)</a>
117 </li>
118 </ul>
119 <h5>Project Documentation</h5>
120 <ul>
121 <li class="collapsed">
122 <a href="project-info.html" title="Project Information">Project Information</a>
123 </li>
124 <li class="expanded">
125 <a href="project-reports.html" title="Project Reports">Project Reports</a>
126 <ul>
127 <li class="none">
128 <a href="changes-report.html" title="Changes Report">Changes Report</a>
129 </li>
130 <li class="none">
131 <a href="checkstyle.html" title="Checkstyle">Checkstyle</a>
132 </li>
133 <li class="none">
134 <strong>Clirr</strong>
135 </li>
136 <li class="none">
137 <a href="cobertura/index.html" title="Cobertura Test Coverage">Cobertura Test Coverage</a>
138 </li>
139 <li class="none">
140 <a href="cpd.html" title="CPD Report">CPD Report</a>
141 </li>
142 <li class="none">
143 <a href="findbugs.html" title="FindBugs Report">FindBugs Report</a>
144 </li>
145 <li class="none">
146 <a href="apidocs/index.html" title="JavaDocs">JavaDocs</a>
147 </li>
148 <li class="none">
149 <a href="javancss.html" title="JavaNCSS Report">JavaNCSS Report</a>
150 </li>
151 <li class="none">
152 <a href="jdepend-report.html" title="JDepend">JDepend</a>
153 </li>
154 <li class="none">
155 <a href="pmd.html" title="PMD Report">PMD Report</a>
156 </li>
157 <li class="none">
158 <a href="rat-report.html" title="RAT Report">RAT Report</a>
159 </li>
160 <li class="none">
161 <a href="xref/index.html" title="Source Xref">Source Xref</a>
162 </li>
163 <li class="none">
164 <a href="surefire-report.html" title="Surefire Report">Surefire Report</a>
165 </li>
166 <li class="none">
167 <a href="taglist.html" title="Tag List">Tag List</a>
168 </li>
169 <li class="none">
170 <a href="testapidocs/index.html" title="Test JavaDocs">Test JavaDocs</a>
171 </li>
172 <li class="none">
173 <a href="xref-test/index.html" title="Test Source Xref">Test Source Xref</a>
174 </li>
175 </ul>
176 </li>
177 </ul>
178 <h5>Commons</h5>
179 <ul>
180 <li class="none">
181 <a href="../" title="Home">Home</a>
182 </li>
183 <li class="none">
184 <a href="http://www.apache.org/licenses/" class="externalLink" title="License">License</a>
185 </li>
186 <li class="collapsed">
187 <a href="../components.html" title="Components">Components</a>
188 </li>
189 <li class="collapsed">
190 <a href="../sandbox/index.html" title="Sandbox">Sandbox</a>
191 </li>
192 <li class="collapsed">
193 <a href="../dormant/index.html" title="Dormant">Dormant</a>
194 </li>
195 </ul>
196 <h5>General Information</h5>
197 <ul>
198 <li class="none">
199 <a href="../volunteering.html" title="Volunteering">Volunteering</a>
200 </li>
201 <li class="none">
202 <a href="../patches.html" title="Contributing Patches">Contributing Patches</a>
203 </li>
204 <li class="none">
205 <a href="../building.html" title="Building Components">Building Components</a>
206 </li>
207 <li class="none">
208 <a href="../releases/index.html" title="Releasing Components">Releasing Components</a>
209 </li>
210 <li class="none">
211 <a href="http://wiki.apache.org/commons/FrontPage" class="externalLink" title="Wiki">Wiki</a>
212 </li>
213 </ul>
214 <h5>ASF</h5>
215 <ul>
216 <li class="none">
217 <a href="http://www.apache.org/foundation/how-it-works.html" class="externalLink" title="How the ASF works">How the ASF works</a>
218 </li>
219 <li class="none">
220 <a href="http://www.apache.org/foundation/getinvolved.html" class="externalLink" title="Get Involved">Get Involved</a>
221 </li>
222 <li class="none">
223 <a href="http://www.apache.org/dev/" class="externalLink" title="Developer Resources">Developer Resources</a>
224 </li>
225 <li class="none">
226 <a href="http://www.apache.org/foundation/sponsorship.html" class="externalLink" title="Sponsorship">Sponsorship</a>
227 </li>
228 <li class="none">
229 <a href="http://www.apache.org/foundation/thanks.html" class="externalLink" title="Thanks">Thanks</a>
230 </li>
231 </ul>
232 <a href="http://www.apache.org/events/current-event.html" title="ApacheCon" class="poweredBy">
233 <img class="poweredBy" alt="ApacheCon" src="http://www.apache.org/events/current-event-125x125.png" />
234 </a>
235 <a href="http://maven.apache.org/" title="Maven" class="poweredBy">
236 <img class="poweredBy" alt="Maven" src="http://maven.apache.org/images/logos/maven-feather.png" />
237 </a>
238
239
240 </div>
241 </div>
242 <div id="bodyColumn">
243 <div id="contentBox">
244 <div class="section"><h2>Clirr Results<a name="Clirr_Results"></a></h2><p>The following document contains the results of <a class="externalLink" href="http://clirr.sourceforge.net/">Clirr</a>.</p><ul><li>Current Version: 3.0</li><li>Comparison Version: (2.6,3.0)</li></ul><div class="section"><h2>Summary<a name="Summary"></a></h2><table border="0" class="bodyTable"><tr class="a"><th>Severity</th><th>Number</th></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" />&#160;Error</td><td>268</td></tr><tr class="a"><td><img alt="Warning" src="images/icon_warning_sml.gif" />&#160;Warning</td><td>0</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" />&#160;Info</td><td>146</td></tr></table></div><div class="section"><h2>Details<a name="Details"></a></h2><table border="0" class="bodyTable"><tr class="a"><th>Severity</th><th>Message</th><th>Class</th><th>Method / Field</th></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.Boolean toBooleanObject(boolean)' has been removed</td><td><a href="./xref/org/apache/commons/lang/BooleanUtils.html">org.apache.commons.lang.BooleanUtils</a></td><td>public java.lang.Boolean toBooleanObject(boolean)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Decreased visibility of class from public to package</td><td><a href="./xref/org/apache/commons/lang/CharRange.html">org.apache.commons.lang.CharRange</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'protected CharSet(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/CharSet.html">org.apache.commons.lang.CharSet</a></td><td>protected CharSet(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Accessibility of method 'public org.apache.commons.lang.CharRange[] getCharRanges()' has been decreased from public to package</td><td><a href="./xref/org/apache/commons/lang/CharSet.html">org.apache.commons.lang.CharSet</a></td><td>public org.apache.commons.lang.CharRange[] getCharRanges()</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public org.apache.commons.lang.CharSet getInstance(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/CharSet.html">org.apache.commons.lang.CharSet</a></td><td>public org.apache.commons.lang.CharSet getInstance(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public int count(java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/CharSetUtils.html">org.apache.commons.lang.CharSetUtils</a></td><td>public int count(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String delete(java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/CharSetUtils.html">org.apache.commons.lang.CharSetUtils</a></td><td>public java.lang.String delete(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public org.apache.commons.lang.CharSet evaluateSet(java.lang.String[])' has been removed</td><td><a href="./xref/org/apache/commons/lang/CharSetUtils.html">org.apache.commons.lang.CharSetUtils</a></td><td>public org.apache.commons.lang.CharSet evaluateSet(java.lang.String[])</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String keep(java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/CharSetUtils.html">org.apache.commons.lang.CharSetUtils</a></td><td>public java.lang.String keep(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String squeeze(java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/CharSetUtils.html">org.apache.commons.lang.CharSetUtils</a></td><td>public java.lang.String squeeze(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String translate(java.lang.String, java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/CharSetUtils.html">org.apache.commons.lang.CharSetUtils</a></td><td>public java.lang.String translate(java.lang.String, java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.IllegalClassException removed</td><td><a href="./xref/org/apache/commons/lang/IllegalClassException.html">org.apache.commons.lang.IllegalClassException</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.IncompleteArgumentException removed</td><td><a href="./xref/org/apache/commons/lang/IncompleteArgumentException.html">org.apache.commons.lang.IncompleteArgumentException</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.NotImplementedException removed</td><td><a href="./xref/org/apache/commons/lang/NotImplementedException.html">org.apache.commons.lang.NotImplementedException</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.NullArgumentException removed</td><td><a href="./xref/org/apache/commons/lang/NullArgumentException.html">org.apache.commons.lang.NullArgumentException</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.NumberRange removed</td><td><a href="./xref/org/apache/commons/lang/NumberRange.html">org.apache.commons.lang.NumberRange</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.NumberUtils removed</td><td><a href="./xref/org/apache/commons/lang/NumberUtils.html">org.apache.commons.lang.NumberUtils</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.StringBuffer appendIdentityToString(java.lang.StringBuffer, java.lang.Object)' has been removed</td><td><a href="./xref/org/apache/commons/lang/ObjectUtils.html">org.apache.commons.lang.ObjectUtils</a></td><td>public java.lang.StringBuffer appendIdentityToString(java.lang.StringBuffer, java.lang.Object)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>In method 'public java.lang.Object max(java.lang.Comparable, java.lang.Comparable)' the number of arguments has changed</td><td><a href="./xref/org/apache/commons/lang/ObjectUtils.html">org.apache.commons.lang.ObjectUtils</a></td><td>public java.lang.Object max(java.lang.Comparable, java.lang.Comparable)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object max(java.lang.Comparable, java.lang.Comparable)' has been changed to java.lang.Comparable</td><td><a href="./xref/org/apache/commons/lang/ObjectUtils.html">org.apache.commons.lang.ObjectUtils</a></td><td>public java.lang.Object max(java.lang.Comparable, java.lang.Comparable)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>In method 'public java.lang.Object min(java.lang.Comparable, java.lang.Comparable)' the number of arguments has changed</td><td><a href="./xref/org/apache/commons/lang/ObjectUtils.html">org.apache.commons.lang.ObjectUtils</a></td><td>public java.lang.Object min(java.lang.Comparable, java.lang.Comparable)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object min(java.lang.Comparable, java.lang.Comparable)' has been changed to java.lang.Comparable</td><td><a href="./xref/org/apache/commons/lang/ObjectUtils.html">org.apache.commons.lang.ObjectUtils</a></td><td>public java.lang.Object min(java.lang.Comparable, java.lang.Comparable)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Removed org.apache.commons.lang.exception.Nestable from the set of implemented interfaces</td><td><a href="./xref/org/apache/commons/lang/SerializationException.html">org.apache.commons.lang.SerializationException</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Removed org.apache.commons.lang.exception.NestableRuntimeException from the list of superclasses</td><td><a href="./xref/org/apache/commons/lang/SerializationException.html">org.apache.commons.lang.SerializationException</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object clone(java.io.Serializable)' has been changed to java.io.Serializable</td><td><a href="./xref/org/apache/commons/lang/SerializationUtils.html">org.apache.commons.lang.SerializationUtils</a></td><td>public java.lang.Object clone(java.io.Serializable)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String escapeCsv(java.lang.String)' is now final</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String escapeCsv(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void escapeCsv(java.io.Writer, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public void escapeCsv(java.io.Writer, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String escapeHtml(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String escapeHtml(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void escapeHtml(java.io.Writer, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public void escapeHtml(java.io.Writer, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String escapeJava(java.lang.String)' is now final</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String escapeJava(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void escapeJava(java.io.Writer, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public void escapeJava(java.io.Writer, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String escapeJavaScript(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String escapeJavaScript(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void escapeJavaScript(java.io.Writer, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public void escapeJavaScript(java.io.Writer, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String escapeSql(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String escapeSql(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String escapeXml(java.lang.String)' is now final</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String escapeXml(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void escapeXml(java.io.Writer, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public void escapeXml(java.io.Writer, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String unescapeCsv(java.lang.String)' is now final</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String unescapeCsv(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void unescapeCsv(java.io.Writer, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public void unescapeCsv(java.io.Writer, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String unescapeHtml(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String unescapeHtml(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void unescapeHtml(java.io.Writer, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public void unescapeHtml(java.io.Writer, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String unescapeJava(java.lang.String)' is now final</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String unescapeJava(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void unescapeJava(java.io.Writer, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public void unescapeJava(java.io.Writer, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String unescapeJavaScript(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String unescapeJavaScript(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void unescapeJavaScript(java.io.Writer, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public void unescapeJavaScript(java.io.Writer, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String unescapeXml(java.lang.String)' is now final</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String unescapeXml(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void unescapeXml(java.io.Writer, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public void unescapeXml(java.io.Writer, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String capitalise(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String capitalise(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String capitaliseAllWords(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String capitaliseAllWords(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String chompLast(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String chompLast(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String chompLast(java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String chompLast(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String chopNewline(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String chopNewline(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String clean(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String clean(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String concatenate(java.lang.Object[])' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String concatenate(java.lang.Object[])</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean contains(java.lang.String, char)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean contains(java.lang.String, char)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean contains(java.lang.String, char)' has changed its type to int</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean contains(java.lang.String, char)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean contains(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean contains(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean contains(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean contains(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean containsAny(java.lang.String, char[])' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean containsAny(java.lang.String, char[])</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean containsAny(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean containsAny(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean containsAny(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean containsAny(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean containsIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean containsIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean containsIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean containsIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean containsNone(java.lang.String, char[])' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean containsNone(java.lang.String, char[])</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean containsNone(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean containsNone(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean containsOnly(java.lang.String, char[])' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean containsOnly(java.lang.String, char[])</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean containsOnly(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean containsOnly(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int countMatches(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int countMatches(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int countMatches(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int countMatches(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public java.lang.String defaultIfBlank(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String defaultIfBlank(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public java.lang.String defaultIfBlank(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String defaultIfBlank(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.String defaultIfBlank(java.lang.String, java.lang.String)' has been changed to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String defaultIfBlank(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public java.lang.String defaultIfEmpty(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String defaultIfEmpty(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public java.lang.String defaultIfEmpty(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String defaultIfEmpty(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.String defaultIfEmpty(java.lang.String, java.lang.String)' has been changed to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String defaultIfEmpty(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String deleteSpaces(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String deleteSpaces(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean endsWith(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean endsWith(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean endsWith(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean endsWith(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean endsWithAny(java.lang.String, java.lang.String[])' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean endsWithAny(java.lang.String, java.lang.String[])</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean endsWithAny(java.lang.String, java.lang.String[])' has changed its type to java.lang.CharSequence[]</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean endsWithAny(java.lang.String, java.lang.String[])</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean endsWithIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean endsWithIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean endsWithIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean endsWithIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean equals(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean equals(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean equals(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean equals(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean equalsIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean equalsIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean equalsIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean equalsIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String escape(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String escape(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String getChomp(java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String getChomp(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int getLevenshteinDistance(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int getLevenshteinDistance(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int getLevenshteinDistance(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int getLevenshteinDistance(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String getNestedString(java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String getNestedString(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String getNestedString(java.lang.String, java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String getNestedString(java.lang.String, java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String getPrechomp(java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String getPrechomp(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOf(java.lang.String, char)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOf(java.lang.String, char)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int indexOf(java.lang.String, char)' has changed its type to int</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOf(java.lang.String, char)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOf(java.lang.String, char, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOf(java.lang.String, char, int)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int indexOf(java.lang.String, char, int)' has changed its type to int</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOf(java.lang.String, char, int)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOf(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOf(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int indexOf(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOf(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOf(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOf(java.lang.String, java.lang.String, int)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int indexOf(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOf(java.lang.String, java.lang.String, int)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOfAny(java.lang.String, char[])' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfAny(java.lang.String, char[])</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOfAny(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfAny(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOfAny(java.lang.String, java.lang.String[])' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfAny(java.lang.String, java.lang.String[])</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int indexOfAny(java.lang.String, java.lang.String[])' has changed its type to java.lang.CharSequence[]</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfAny(java.lang.String, java.lang.String[])</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOfAnyBut(java.lang.String, char[])' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfAnyBut(java.lang.String, char[])</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOfAnyBut(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfAnyBut(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int indexOfAnyBut(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfAnyBut(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOfDifference(java.lang.String[])' has changed its type to java.lang.CharSequence[]</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfDifference(java.lang.String[])</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOfDifference(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfDifference(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int indexOfDifference(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfDifference(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOfIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int indexOfIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int indexOfIgnoreCase(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfIgnoreCase(java.lang.String, java.lang.String, int)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int indexOfIgnoreCase(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int indexOfIgnoreCase(java.lang.String, java.lang.String, int)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isAllLowerCase(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isAllLowerCase(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isAllUpperCase(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isAllUpperCase(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isAlpha(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isAlpha(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isAlphaSpace(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isAlphaSpace(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isAlphanumeric(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isAlphanumeric(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isAlphanumericSpace(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isAlphanumericSpace(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isAsciiPrintable(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isAsciiPrintable(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isBlank(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isBlank(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isEmpty(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isEmpty(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isNotBlank(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isNotBlank(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isNotEmpty(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isNotEmpty(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isNumeric(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isNumeric(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isNumericSpace(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isNumericSpace(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isWhitespace(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean isWhitespace(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public java.lang.String join(java.util.Collection, char)' has changed its type to java.lang.Iterable</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String join(java.util.Collection, char)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public java.lang.String join(java.util.Collection, java.lang.String)' has changed its type to java.lang.Iterable</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String join(java.util.Collection, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int lastIndexOf(java.lang.String, char)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOf(java.lang.String, char)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int lastIndexOf(java.lang.String, char)' has changed its type to int</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOf(java.lang.String, char)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int lastIndexOf(java.lang.String, char, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOf(java.lang.String, char, int)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int lastIndexOf(java.lang.String, char, int)' has changed its type to int</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOf(java.lang.String, char, int)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int lastIndexOf(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOf(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int lastIndexOf(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOf(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int lastIndexOf(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOf(java.lang.String, java.lang.String, int)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int lastIndexOf(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOf(java.lang.String, java.lang.String, int)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int lastIndexOfAny(java.lang.String, java.lang.String[])' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOfAny(java.lang.String, java.lang.String[])</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int lastIndexOfAny(java.lang.String, java.lang.String[])' has changed its type to java.lang.CharSequence[]</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOfAny(java.lang.String, java.lang.String[])</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int lastIndexOfIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOfIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int lastIndexOfIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOfIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int lastIndexOfIgnoreCase(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOfIgnoreCase(java.lang.String, java.lang.String, int)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int lastIndexOfIgnoreCase(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastIndexOfIgnoreCase(java.lang.String, java.lang.String, int)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int lastOrdinalIndexOf(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastOrdinalIndexOf(java.lang.String, java.lang.String, int)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int lastOrdinalIndexOf(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int lastOrdinalIndexOf(java.lang.String, java.lang.String, int)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int length(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int length(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public int ordinalIndexOf(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int ordinalIndexOf(java.lang.String, java.lang.String, int)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public int ordinalIndexOf(java.lang.String, java.lang.String, int)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int ordinalIndexOf(java.lang.String, java.lang.String, int)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String overlayString(java.lang.String, java.lang.String, int, int)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String overlayString(java.lang.String, java.lang.String, int, int)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String prechomp(java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String prechomp(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String reverseDelimitedString(java.lang.String, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String reverseDelimitedString(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean startsWith(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean startsWith(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean startsWith(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean startsWith(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean startsWithAny(java.lang.String, java.lang.String[])' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean startsWithAny(java.lang.String, java.lang.String[])</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean startsWithAny(java.lang.String, java.lang.String[])' has changed its type to java.lang.CharSequence[]</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean startsWithAny(java.lang.String, java.lang.String[])</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean startsWithIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean startsWithIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 2 of 'public boolean startsWithIgnoreCase(java.lang.String, java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean startsWithIgnoreCase(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String uncapitalise(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String uncapitalise(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Removed field JAVA_VERSION_FLOAT</td><td><a href="./xref/org/apache/commons/lang/SystemUtils.html">org.apache.commons.lang.SystemUtils</a></td><td>JAVA_VERSION_FLOAT</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Removed field JAVA_VERSION_INT</td><td><a href="./xref/org/apache/commons/lang/SystemUtils.html">org.apache.commons.lang.SystemUtils</a></td><td>JAVA_VERSION_INT</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Removed field JAVA_VERSION_TRIMMED</td><td><a href="./xref/org/apache/commons/lang/SystemUtils.html">org.apache.commons.lang.SystemUtils</a></td><td>JAVA_VERSION_TRIMMED</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public float getJavaVersion()' has been removed</td><td><a href="./xref/org/apache/commons/lang/SystemUtils.html">org.apache.commons.lang.SystemUtils</a></td><td>public float getJavaVersion()</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public boolean isJavaVersionAtLeast(float)' has changed its type to org.apache.commons.lang.JavaVersion</td><td><a href="./xref/org/apache/commons/lang/SystemUtils.html">org.apache.commons.lang.SystemUtils</a></td><td>public boolean isJavaVersionAtLeast(float)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public boolean isJavaVersionAtLeast(int)' has been removed</td><td><a href="./xref/org/apache/commons/lang/SystemUtils.html">org.apache.commons.lang.SystemUtils</a></td><td>public boolean isJavaVersionAtLeast(int)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.UnhandledException removed</td><td><a href="./xref/org/apache/commons/lang/UnhandledException.html">org.apache.commons.lang.UnhandledException</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void allElementsOfType(java.util.Collection, java.lang.Class, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void allElementsOfType(java.util.Collection, java.lang.Class, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void allElementsOfType(java.util.Collection, java.lang.Class)' has been removed</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void allElementsOfType(java.util.Collection, java.lang.Class)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 3 of 'public void isTrue(boolean, java.lang.String, java.lang.Object)' has changed its type to java.lang.Object[]</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void isTrue(boolean, java.lang.String, java.lang.Object)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void isTrue(boolean, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void isTrue(boolean, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void noNullElements(java.lang.Object[])' has been changed to java.lang.Object[]</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void noNullElements(java.lang.Object[])</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public void noNullElements(java.util.Collection)' has changed its type to java.lang.Iterable</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void noNullElements(java.util.Collection)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void noNullElements(java.util.Collection)' has been changed to java.lang.Iterable</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void noNullElements(java.util.Collection)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>In method 'public void noNullElements(java.lang.Object[], java.lang.String)' the number of arguments has changed</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void noNullElements(java.lang.Object[], java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void noNullElements(java.lang.Object[], java.lang.String)' has been changed to java.lang.Object[]</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void noNullElements(java.lang.Object[], java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>In method 'public void noNullElements(java.util.Collection, java.lang.String)' the number of arguments has changed</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void noNullElements(java.util.Collection, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void noNullElements(java.util.Collection, java.lang.String)' has been changed to java.lang.Iterable</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void noNullElements(java.util.Collection, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void notEmpty(java.lang.Object[])' has been changed to java.lang.Object[]</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.lang.Object[])</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void notEmpty(java.util.Collection)' has been changed to java.util.Collection</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.util.Collection)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void notEmpty(java.util.Map)' has been changed to java.util.Map</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.util.Map)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public void notEmpty(java.lang.String)' has changed its type to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void notEmpty(java.lang.String)' has been changed to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>In method 'public void notEmpty(java.lang.Object[], java.lang.String)' the number of arguments has changed</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.lang.Object[], java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void notEmpty(java.lang.Object[], java.lang.String)' has been changed to java.lang.Object[]</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.lang.Object[], java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>In method 'public void notEmpty(java.util.Collection, java.lang.String)' the number of arguments has changed</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.util.Collection, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void notEmpty(java.util.Collection, java.lang.String)' has been changed to java.util.Collection</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.util.Collection, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>In method 'public void notEmpty(java.util.Map, java.lang.String)' the number of arguments has changed</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.util.Map, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void notEmpty(java.util.Map, java.lang.String)' has been changed to java.util.Map</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.util.Map, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>In method 'public void notEmpty(java.lang.String, java.lang.String)' the number of arguments has changed</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.lang.String, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void notEmpty(java.lang.String, java.lang.String)' has been changed to java.lang.CharSequence</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notEmpty(java.lang.String, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void notNull(java.lang.Object)' has been changed to java.lang.Object</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notNull(java.lang.Object)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>In method 'public void notNull(java.lang.Object, java.lang.String)' the number of arguments has changed</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notNull(java.lang.Object, java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public void notNull(java.lang.Object, java.lang.String)' has been changed to java.lang.Object</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void notNull(java.lang.Object, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.WordUtils removed</td><td><a href="./xref/org/apache/commons/lang/WordUtils.html">org.apache.commons.lang.WordUtils</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public int reflectionCompare(java.lang.Object, java.lang.Object, boolean, java.lang.Class)' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/CompareToBuilder.html">org.apache.commons.lang.builder.CompareToBuilder</a></td><td>public int reflectionCompare(java.lang.Object, java.lang.Object, boolean, java.lang.Class)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public boolean reflectionEquals(java.lang.Object, java.lang.Object)' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/EqualsBuilder.html">org.apache.commons.lang.builder.EqualsBuilder</a></td><td>public boolean reflectionEquals(java.lang.Object, java.lang.Object)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public boolean reflectionEquals(java.lang.Object, java.lang.Object, boolean, java.lang.Class)' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/EqualsBuilder.html">org.apache.commons.lang.builder.EqualsBuilder</a></td><td>public boolean reflectionEquals(java.lang.Object, java.lang.Object, boolean, java.lang.Class)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public int reflectionHashCode(int, int, java.lang.Object, boolean, java.lang.Class)' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/HashCodeBuilder.html">org.apache.commons.lang.builder.HashCodeBuilder</a></td><td>public int reflectionHashCode(int, int, java.lang.Object, boolean, java.lang.Class)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public int reflectionHashCode(java.lang.Object)' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/HashCodeBuilder.html">org.apache.commons.lang.builder.HashCodeBuilder</a></td><td>public int reflectionHashCode(java.lang.Object)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public ReflectionToStringBuilder(java.lang.Object, org.apache.commons.lang.builder.ToStringStyle, java.lang.StringBuffer, java.lang.Class, boolean)' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/ReflectionToStringBuilder.html">org.apache.commons.lang.builder.ReflectionToStringBuilder</a></td><td>public ReflectionToStringBuilder(java.lang.Object, org.apache.commons.lang.builder.ToStringStyle, java.lang.StringBuffer, java.lang.Class, boolean)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public org.apache.commons.lang.builder.ToStringBuilder reflectionAppendArray(java.lang.Object)' has been changed to org.apache.commons.lang.builder.ReflectionToStringBuilder</td><td><a href="./xref/org/apache/commons/lang/builder/ReflectionToStringBuilder.html">org.apache.commons.lang.builder.ReflectionToStringBuilder</a></td><td>public org.apache.commons.lang.builder.ToStringBuilder reflectionAppendArray(java.lang.Object)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String toString(java.lang.Object, org.apache.commons.lang.builder.ToStringStyle, boolean, java.lang.Class)' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/ReflectionToStringBuilder.html">org.apache.commons.lang.builder.ReflectionToStringBuilder</a></td><td>public java.lang.String toString(java.lang.Object, org.apache.commons.lang.builder.ToStringStyle, boolean, java.lang.Class)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String toStringExclude(java.lang.Object, java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/ReflectionToStringBuilder.html">org.apache.commons.lang.builder.ReflectionToStringBuilder</a></td><td>public java.lang.String toStringExclude(java.lang.Object, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public boolean isShortClassName()' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/StandardToStringStyle.html">org.apache.commons.lang.builder.StandardToStringStyle</a></td><td>public boolean isShortClassName()</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void setShortClassName(boolean)' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/StandardToStringStyle.html">org.apache.commons.lang.builder.StandardToStringStyle</a></td><td>public void setShortClassName(boolean)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'protected boolean isShortClassName()' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/ToStringStyle.html">org.apache.commons.lang.builder.ToStringStyle</a></td><td>protected boolean isShortClassName()</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'protected void setShortClassName(boolean)' has been removed</td><td><a href="./xref/org/apache/commons/lang/builder/ToStringStyle.html">org.apache.commons.lang.builder.ToStringStyle</a></td><td>protected void setShortClassName(boolean)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.enum.Enum removed</td><td><a href="./xref/org/apache/commons/lang/enum/Enum.html">org.apache.commons.lang.enum.Enum</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.enum.EnumUtils removed</td><td><a href="./xref/org/apache/commons/lang/enum/EnumUtils.html">org.apache.commons.lang.enum.EnumUtils</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.enum.ValuedEnum removed</td><td><a href="./xref/org/apache/commons/lang/enum/ValuedEnum.html">org.apache.commons.lang.enum.ValuedEnum</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.enums.Enum removed</td><td><a href="./xref/org/apache/commons/lang/enums/Enum.html">org.apache.commons.lang.enums.Enum</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.enums.EnumUtils removed</td><td><a href="./xref/org/apache/commons/lang/enums/EnumUtils.html">org.apache.commons.lang.enums.EnumUtils</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.enums.ValuedEnum removed</td><td><a href="./xref/org/apache/commons/lang/enums/ValuedEnum.html">org.apache.commons.lang.enums.ValuedEnum</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Removed org.apache.commons.lang.exception.Nestable from the set of implemented interfaces</td><td><a href="./xref/org/apache/commons/lang/exception/CloneFailedException.html">org.apache.commons.lang.exception.CloneFailedException</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Removed org.apache.commons.lang.exception.NestableRuntimeException from the list of superclasses</td><td><a href="./xref/org/apache/commons/lang/exception/CloneFailedException.html">org.apache.commons.lang.exception.CloneFailedException</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void addCauseMethodName(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionUtils.html">org.apache.commons.lang.exception.ExceptionUtils</a></td><td>public void addCauseMethodName(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.String getFullStackTrace(java.lang.Throwable)' has been removed</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionUtils.html">org.apache.commons.lang.exception.ExceptionUtils</a></td><td>public java.lang.String getFullStackTrace(java.lang.Throwable)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public boolean isCauseMethodName(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionUtils.html">org.apache.commons.lang.exception.ExceptionUtils</a></td><td>public boolean isCauseMethodName(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public boolean isNestedThrowable(java.lang.Throwable)' has been removed</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionUtils.html">org.apache.commons.lang.exception.ExceptionUtils</a></td><td>public boolean isNestedThrowable(java.lang.Throwable)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public boolean isThrowableNested()' has been removed</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionUtils.html">org.apache.commons.lang.exception.ExceptionUtils</a></td><td>public boolean isThrowableNested()</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public void removeCauseMethodName(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionUtils.html">org.apache.commons.lang.exception.ExceptionUtils</a></td><td>public void removeCauseMethodName(java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public boolean setCause(java.lang.Throwable, java.lang.Throwable)' has been removed</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionUtils.html">org.apache.commons.lang.exception.ExceptionUtils</a></td><td>public boolean setCause(java.lang.Throwable, java.lang.Throwable)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.exception.Nestable removed</td><td><a href="./xref/org/apache/commons/lang/exception/Nestable.html">org.apache.commons.lang.exception.Nestable</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.exception.NestableDelegate removed</td><td><a href="./xref/org/apache/commons/lang/exception/NestableDelegate.html">org.apache.commons.lang.exception.NestableDelegate</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.exception.NestableError removed</td><td><a href="./xref/org/apache/commons/lang/exception/NestableError.html">org.apache.commons.lang.exception.NestableError</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.exception.NestableException removed</td><td><a href="./xref/org/apache/commons/lang/exception/NestableException.html">org.apache.commons.lang.exception.NestableException</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.exception.NestableRuntimeException removed</td><td><a href="./xref/org/apache/commons/lang/exception/NestableRuntimeException.html">org.apache.commons.lang.exception.NestableRuntimeException</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.math.DoubleRange removed</td><td><a href="./xref/org/apache/commons/lang/math/DoubleRange.html">org.apache.commons.lang.math.DoubleRange</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.math.FloatRange removed</td><td><a href="./xref/org/apache/commons/lang/math/FloatRange.html">org.apache.commons.lang.math.FloatRange</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.math.IntRange removed</td><td><a href="./xref/org/apache/commons/lang/math/IntRange.html">org.apache.commons.lang.math.IntRange</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.math.JVMRandom removed</td><td><a href="./xref/org/apache/commons/lang/math/JVMRandom.html">org.apache.commons.lang.math.JVMRandom</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.math.LongRange removed</td><td><a href="./xref/org/apache/commons/lang/math/LongRange.html">org.apache.commons.lang.math.LongRange</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.math.NumberRange removed</td><td><a href="./xref/org/apache/commons/lang/math/NumberRange.html">org.apache.commons.lang.math.NumberRange</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public int compare(double, double)' has been removed</td><td><a href="./xref/org/apache/commons/lang/math/NumberUtils.html">org.apache.commons.lang.math.NumberUtils</a></td><td>public int compare(double, double)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public int compare(float, float)' has been removed</td><td><a href="./xref/org/apache/commons/lang/math/NumberUtils.html">org.apache.commons.lang.math.NumberUtils</a></td><td>public int compare(float, float)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public int stringToInt(java.lang.String)' has been removed</td><td><a href="./xref/org/apache/commons/lang/math/NumberUtils.html">org.apache.commons.lang.math.NumberUtils</a></td><td>public int stringToInt(java.lang.String)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public int stringToInt(java.lang.String, int)' has been removed</td><td><a href="./xref/org/apache/commons/lang/math/NumberUtils.html">org.apache.commons.lang.math.NumberUtils</a></td><td>public int stringToInt(java.lang.String, int)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.math.RandomUtils removed</td><td><a href="./xref/org/apache/commons/lang/math/RandomUtils.html">org.apache.commons.lang.math.RandomUtils</a></td><td></td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Class org.apache.commons.lang.math.Range removed</td><td><a href="./xref/org/apache/commons/lang/math/Range.html">org.apache.commons.lang.math.Range</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object getValue()' has been changed to java.lang.Boolean</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableBoolean.html">org.apache.commons.lang.mutable.MutableBoolean</a></td><td>public java.lang.Object getValue()</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object getValue()' has been changed to java.lang.Byte</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableByte.html">org.apache.commons.lang.mutable.MutableByte</a></td><td>public java.lang.Object getValue()</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object getValue()' has been changed to java.lang.Double</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableDouble.html">org.apache.commons.lang.mutable.MutableDouble</a></td><td>public java.lang.Object getValue()</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object getValue()' has been changed to java.lang.Float</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableFloat.html">org.apache.commons.lang.mutable.MutableFloat</a></td><td>public java.lang.Object getValue()</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object getValue()' has been changed to java.lang.Integer</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableInt.html">org.apache.commons.lang.mutable.MutableInt</a></td><td>public java.lang.Object getValue()</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object getValue()' has been changed to java.lang.Long</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableLong.html">org.apache.commons.lang.mutable.MutableLong</a></td><td>public java.lang.Object getValue()</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object getValue()' has been changed to java.lang.Short</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableShort.html">org.apache.commons.lang.mutable.MutableShort</a></td><td>public java.lang.Object getValue()</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.reflect.Constructor getAccessibleConstructor(java.lang.Class, java.lang.Class)' has been removed</td><td><a href="./xref/org/apache/commons/lang/reflect/ConstructorUtils.html">org.apache.commons.lang.reflect.ConstructorUtils</a></td><td>public java.lang.reflect.Constructor getAccessibleConstructor(java.lang.Class, java.lang.Class)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.Object invokeConstructor(java.lang.Class, java.lang.Object)' has been removed</td><td><a href="./xref/org/apache/commons/lang/reflect/ConstructorUtils.html">org.apache.commons.lang.reflect.ConstructorUtils</a></td><td>public java.lang.Object invokeConstructor(java.lang.Class, java.lang.Object)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.Object invokeExactConstructor(java.lang.Class, java.lang.Object)' has been removed</td><td><a href="./xref/org/apache/commons/lang/reflect/ConstructorUtils.html">org.apache.commons.lang.reflect.ConstructorUtils</a></td><td>public java.lang.Object invokeExactConstructor(java.lang.Class, java.lang.Object)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.reflect.Method getAccessibleMethod(java.lang.Class, java.lang.String, java.lang.Class)' has been removed</td><td><a href="./xref/org/apache/commons/lang/reflect/MethodUtils.html">org.apache.commons.lang.reflect.MethodUtils</a></td><td>public java.lang.reflect.Method getAccessibleMethod(java.lang.Class, java.lang.String, java.lang.Class)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.Object invokeExactMethod(java.lang.Object, java.lang.String, java.lang.Object)' has been removed</td><td><a href="./xref/org/apache/commons/lang/reflect/MethodUtils.html">org.apache.commons.lang.reflect.MethodUtils</a></td><td>public java.lang.Object invokeExactMethod(java.lang.Object, java.lang.String, java.lang.Object)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.Object invokeExactStaticMethod(java.lang.Class, java.lang.String, java.lang.Object)' has been removed</td><td><a href="./xref/org/apache/commons/lang/reflect/MethodUtils.html">org.apache.commons.lang.reflect.MethodUtils</a></td><td>public java.lang.Object invokeExactStaticMethod(java.lang.Class, java.lang.String, java.lang.Object)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.Object invokeMethod(java.lang.Object, java.lang.String, java.lang.Object)' has been removed</td><td><a href="./xref/org/apache/commons/lang/reflect/MethodUtils.html">org.apache.commons.lang.reflect.MethodUtils</a></td><td>public java.lang.Object invokeMethod(java.lang.Object, java.lang.String, java.lang.Object)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.Object invokeStaticMethod(java.lang.Class, java.lang.String, java.lang.Object)' has been removed</td><td><a href="./xref/org/apache/commons/lang/reflect/MethodUtils.html">org.apache.commons.lang.reflect.MethodUtils</a></td><td>public java.lang.Object invokeStaticMethod(java.lang.Class, java.lang.String, java.lang.Object)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Removed java.lang.Cloneable from the set of implemented interfaces</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td></td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public org.apache.commons.lang.text.StrBuilder appendAll(java.util.Collection)' has changed its type to java.lang.Iterable</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td>public org.apache.commons.lang.text.StrBuilder appendAll(java.util.Collection)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Parameter 1 of 'public org.apache.commons.lang.text.StrBuilder appendWithSeparators(java.util.Collection, java.lang.String)' has changed its type to java.lang.Iterable</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td>public org.apache.commons.lang.text.StrBuilder appendWithSeparators(java.util.Collection, java.lang.String)</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public java.lang.Object clone()' has been removed</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td>public java.lang.Object clone()</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object next()' has been changed to java.lang.String</td><td><a href="./xref/org/apache/commons/lang/text/StrTokenizer.html">org.apache.commons.lang.text.StrTokenizer</a></td><td>public java.lang.Object next()</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Return type of method 'public java.lang.Object previous()' has been changed to java.lang.String</td><td><a href="./xref/org/apache/commons/lang/text/StrTokenizer.html">org.apache.commons.lang.text.StrTokenizer</a></td><td>public java.lang.Object previous()</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Field MILLIS_IN_DAY has been removed, but it was previously a constant</td><td><a href="./xref/org/apache/commons/lang/time/DateUtils.html">org.apache.commons.lang.time.DateUtils</a></td><td>MILLIS_IN_DAY</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Field MILLIS_IN_HOUR has been removed, but it was previously a constant</td><td><a href="./xref/org/apache/commons/lang/time/DateUtils.html">org.apache.commons.lang.time.DateUtils</a></td><td>MILLIS_IN_HOUR</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Field MILLIS_IN_MINUTE has been removed, but it was previously a constant</td><td><a href="./xref/org/apache/commons/lang/time/DateUtils.html">org.apache.commons.lang.time.DateUtils</a></td><td>MILLIS_IN_MINUTE</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Field MILLIS_IN_SECOND has been removed, but it was previously a constant</td><td><a href="./xref/org/apache/commons/lang/time/DateUtils.html">org.apache.commons.lang.time.DateUtils</a></td><td>MILLIS_IN_SECOND</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Removed field UTC_TIME_ZONE</td><td><a href="./xref/org/apache/commons/lang/time/DateUtils.html">org.apache.commons.lang.time.DateUtils</a></td><td>UTC_TIME_ZONE</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Accessibility of method 'public java.util.Date add(java.util.Date, int, int)' has been decreased from public to private</td><td><a href="./xref/org/apache/commons/lang/time/DateUtils.html">org.apache.commons.lang.time.DateUtils</a></td><td>public java.util.Date add(java.util.Date, int, int)</td></tr><tr class="b"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Method 'public boolean getTimeZoneOverridesCalendar()' has been removed</td><td><a href="./xref/org/apache/commons/lang/time/FastDateFormat.html">org.apache.commons.lang.time.FastDateFormat</a></td><td>public boolean getTimeZoneOverridesCalendar()</td></tr><tr class="a"><td><img alt="Error" src="images/icon_error_sml.gif" /></td><td>Accessibility of method 'protected void init()' has been decreased from protected to private</td><td><a href="./xref/org/apache/commons/lang/time/FastDateFormat.html">org.apache.commons.lang.time.FastDateFormat</a></td><td>protected void init()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.AnnotationUtils added</td><td><a href="./xref/org/apache/commons/lang/AnnotationUtils.html">org.apache.commons.lang.AnnotationUtils</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object[] toArray(java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/ArrayUtils.html">org.apache.commons.lang.ArrayUtils</a></td><td>public java.lang.Object[] toArray(java.lang.Object[])</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.CharSequenceUtils added</td><td><a href="./xref/org/apache/commons/lang/CharSequenceUtils.html">org.apache.commons.lang.CharSequenceUtils</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String getSimpleName(java.lang.Class)' has been added</td><td><a href="./xref/org/apache/commons/lang/ClassUtils.html">org.apache.commons.lang.ClassUtils</a></td><td>public java.lang.String getSimpleName(java.lang.Class)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String getSimpleName(java.lang.Object, java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/ClassUtils.html">org.apache.commons.lang.ClassUtils</a></td><td>public java.lang.String getSimpleName(java.lang.Object, java.lang.String)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.EnumUtils added</td><td><a href="./xref/org/apache/commons/lang/EnumUtils.html">org.apache.commons.lang.EnumUtils</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.JavaVersion added</td><td><a href="./xref/org/apache/commons/lang/JavaVersion.html">org.apache.commons.lang.JavaVersion</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object firstNonNull(java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/ObjectUtils.html">org.apache.commons.lang.ObjectUtils</a></td><td>public java.lang.Object firstNonNull(java.lang.Object[])</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public int hashCodeMulti(java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/ObjectUtils.html">org.apache.commons.lang.ObjectUtils</a></td><td>public int hashCodeMulti(java.lang.Object[])</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.Range added</td><td><a href="./xref/org/apache/commons/lang/Range.html">org.apache.commons.lang.Range</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field ESCAPE_CSV</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>ESCAPE_CSV</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field ESCAPE_ECMASCRIPT</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>ESCAPE_ECMASCRIPT</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field ESCAPE_HTML3</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>ESCAPE_HTML3</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field ESCAPE_HTML4</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>ESCAPE_HTML4</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field ESCAPE_JAVA</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>ESCAPE_JAVA</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field ESCAPE_XML</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>ESCAPE_XML</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field UNESCAPE_CSV</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>UNESCAPE_CSV</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field UNESCAPE_ECMASCRIPT</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>UNESCAPE_ECMASCRIPT</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field UNESCAPE_HTML3</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>UNESCAPE_HTML3</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field UNESCAPE_HTML4</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>UNESCAPE_HTML4</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field UNESCAPE_JAVA</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>UNESCAPE_JAVA</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added public field UNESCAPE_XML</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>UNESCAPE_XML</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String escapeEcmaScript(java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String escapeEcmaScript(java.lang.String)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String escapeHtml3(java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String escapeHtml3(java.lang.String)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String escapeHtml4(java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String escapeHtml4(java.lang.String)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String unescapeEcmaScript(java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String unescapeEcmaScript(java.lang.String)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String unescapeHtml3(java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String unescapeHtml3(java.lang.String)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String unescapeHtml4(java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/StringEscapeUtils.html">org.apache.commons.lang.StringEscapeUtils</a></td><td>public java.lang.String unescapeHtml4(java.lang.String)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public boolean containsWhitespace(java.lang.CharSequence)' has been added</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public boolean containsWhitespace(java.lang.CharSequence)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public int getLevenshteinDistance(java.lang.CharSequence, java.lang.CharSequence, int)' has been added</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public int getLevenshteinDistance(java.lang.CharSequence, java.lang.CharSequence, int)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String repeat(char, int)' has been added</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String repeat(char, int)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String stripAccents(java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/StringUtils.html">org.apache.commons.lang.StringUtils</a></td><td>public java.lang.String stripAccents(java.lang.String)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void exclusiveBetween(java.lang.Object, java.lang.Object, java.lang.Comparable)' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void exclusiveBetween(java.lang.Object, java.lang.Object, java.lang.Comparable)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void exclusiveBetween(java.lang.Object, java.lang.Object, java.lang.Comparable, java.lang.String, java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void exclusiveBetween(java.lang.Object, java.lang.Object, java.lang.Comparable, java.lang.String, java.lang.Object[])</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void inclusiveBetween(java.lang.Object, java.lang.Object, java.lang.Comparable)' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void inclusiveBetween(java.lang.Object, java.lang.Object, java.lang.Comparable)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void inclusiveBetween(java.lang.Object, java.lang.Object, java.lang.Comparable, java.lang.String, java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void inclusiveBetween(java.lang.Object, java.lang.Object, java.lang.Comparable, java.lang.String, java.lang.Object[])</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void isAssignableFrom(java.lang.Class, java.lang.Class)' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void isAssignableFrom(java.lang.Class, java.lang.Class)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void isAssignableFrom(java.lang.Class, java.lang.Class, java.lang.String, java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void isAssignableFrom(java.lang.Class, java.lang.Class, java.lang.String, java.lang.Object[])</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void isInstanceOf(java.lang.Class, java.lang.Object)' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void isInstanceOf(java.lang.Class, java.lang.Object)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void isInstanceOf(java.lang.Class, java.lang.Object, java.lang.String, java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void isInstanceOf(java.lang.Class, java.lang.Object, java.lang.String, java.lang.Object[])</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void matchesPattern(java.lang.CharSequence, java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void matchesPattern(java.lang.CharSequence, java.lang.String)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void matchesPattern(java.lang.CharSequence, java.lang.String, java.lang.String, java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void matchesPattern(java.lang.CharSequence, java.lang.String, java.lang.String, java.lang.Object[])</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.CharSequence notBlank(java.lang.CharSequence, java.lang.String, java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public java.lang.CharSequence notBlank(java.lang.CharSequence, java.lang.String, java.lang.Object[])</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.CharSequence notBlank(java.lang.CharSequence)' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public java.lang.CharSequence notBlank(java.lang.CharSequence)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object[] validIndex(java.lang.Object[], int, java.lang.String, java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public java.lang.Object[] validIndex(java.lang.Object[], int, java.lang.String, java.lang.Object[])</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object[] validIndex(java.lang.Object[], int)' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public java.lang.Object[] validIndex(java.lang.Object[], int)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.util.Collection validIndex(java.util.Collection, int, java.lang.String, java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public java.util.Collection validIndex(java.util.Collection, int, java.lang.String, java.lang.Object[])</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.util.Collection validIndex(java.util.Collection, int)' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public java.util.Collection validIndex(java.util.Collection, int)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.CharSequence validIndex(java.lang.CharSequence, int, java.lang.String, java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public java.lang.CharSequence validIndex(java.lang.CharSequence, int, java.lang.String, java.lang.Object[])</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.CharSequence validIndex(java.lang.CharSequence, int)' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public java.lang.CharSequence validIndex(java.lang.CharSequence, int)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void validState(boolean)' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void validState(boolean)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void validState(boolean, java.lang.String, java.lang.Object[])' has been added</td><td><a href="./xref/org/apache/commons/lang/Validate.html">org.apache.commons.lang.Validate</a></td><td>public void validState(boolean, java.lang.String, java.lang.Object[])</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.builder.Builder added</td><td><a href="./xref/org/apache/commons/lang/builder/Builder.html">org.apache.commons.lang.builder.Builder</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added org.apache.commons.lang.builder.Builder to the set of implemented interfaces</td><td><a href="./xref/org/apache/commons/lang/builder/CompareToBuilder.html">org.apache.commons.lang.builder.CompareToBuilder</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Integer build()' has been added</td><td><a href="./xref/org/apache/commons/lang/builder/CompareToBuilder.html">org.apache.commons.lang.builder.CompareToBuilder</a></td><td>public java.lang.Integer build()</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object build()' has been added</td><td><a href="./xref/org/apache/commons/lang/builder/CompareToBuilder.html">org.apache.commons.lang.builder.CompareToBuilder</a></td><td>public java.lang.Object build()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added org.apache.commons.lang.builder.Builder to the set of implemented interfaces</td><td><a href="./xref/org/apache/commons/lang/builder/EqualsBuilder.html">org.apache.commons.lang.builder.EqualsBuilder</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Boolean build()' has been added</td><td><a href="./xref/org/apache/commons/lang/builder/EqualsBuilder.html">org.apache.commons.lang.builder.EqualsBuilder</a></td><td>public java.lang.Boolean build()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object build()' has been added</td><td><a href="./xref/org/apache/commons/lang/builder/EqualsBuilder.html">org.apache.commons.lang.builder.EqualsBuilder</a></td><td>public java.lang.Object build()</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added org.apache.commons.lang.builder.Builder to the set of implemented interfaces</td><td><a href="./xref/org/apache/commons/lang/builder/HashCodeBuilder.html">org.apache.commons.lang.builder.HashCodeBuilder</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Integer build()' has been added</td><td><a href="./xref/org/apache/commons/lang/builder/HashCodeBuilder.html">org.apache.commons.lang.builder.HashCodeBuilder</a></td><td>public java.lang.Integer build()</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object build()' has been added</td><td><a href="./xref/org/apache/commons/lang/builder/HashCodeBuilder.html">org.apache.commons.lang.builder.HashCodeBuilder</a></td><td>public java.lang.Object build()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added org.apache.commons.lang.builder.Builder to the set of implemented interfaces</td><td><a href="./xref/org/apache/commons/lang/builder/ReflectionToStringBuilder.html">org.apache.commons.lang.builder.ReflectionToStringBuilder</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Accessibility of field excludeFieldNames has been increased from private to protected</td><td><a href="./xref/org/apache/commons/lang/builder/ReflectionToStringBuilder.html">org.apache.commons.lang.builder.ReflectionToStringBuilder</a></td><td>excludeFieldNames</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added org.apache.commons.lang.builder.Builder to the set of implemented interfaces</td><td><a href="./xref/org/apache/commons/lang/builder/ToStringBuilder.html">org.apache.commons.lang.builder.ToStringBuilder</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String build()' has been added</td><td><a href="./xref/org/apache/commons/lang/builder/ToStringBuilder.html">org.apache.commons.lang.builder.ToStringBuilder</a></td><td>public java.lang.String build()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object build()' has been added</td><td><a href="./xref/org/apache/commons/lang/builder/ToStringBuilder.html">org.apache.commons.lang.builder.ToStringBuilder</a></td><td>public java.lang.Object build()</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.AtomicInitializer added</td><td><a href="./xref/org/apache/commons/lang/concurrent/AtomicInitializer.html">org.apache.commons.lang.concurrent.AtomicInitializer</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.AtomicSafeInitializer added</td><td><a href="./xref/org/apache/commons/lang/concurrent/AtomicSafeInitializer.html">org.apache.commons.lang.concurrent.AtomicSafeInitializer</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.BackgroundInitializer added</td><td><a href="./xref/org/apache/commons/lang/concurrent/BackgroundInitializer.html">org.apache.commons.lang.concurrent.BackgroundInitializer</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.BasicThreadFactory added</td><td><a href="./xref/org/apache/commons/lang/concurrent/BasicThreadFactory.html">org.apache.commons.lang.concurrent.BasicThreadFactory</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.BasicThreadFactory$Builder added</td><td><a href="./xref/org/apache/commons/lang/concurrent/BasicThreadFactory$Builder.html">org.apache.commons.lang.concurrent.BasicThreadFactory$Builder</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.CallableBackgroundInitializer added</td><td><a href="./xref/org/apache/commons/lang/concurrent/CallableBackgroundInitializer.html">org.apache.commons.lang.concurrent.CallableBackgroundInitializer</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.ConcurrentException added</td><td><a href="./xref/org/apache/commons/lang/concurrent/ConcurrentException.html">org.apache.commons.lang.concurrent.ConcurrentException</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.ConcurrentInitializer added</td><td><a href="./xref/org/apache/commons/lang/concurrent/ConcurrentInitializer.html">org.apache.commons.lang.concurrent.ConcurrentInitializer</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.ConcurrentRuntimeException added</td><td><a href="./xref/org/apache/commons/lang/concurrent/ConcurrentRuntimeException.html">org.apache.commons.lang.concurrent.ConcurrentRuntimeException</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.ConcurrentUtils added</td><td><a href="./xref/org/apache/commons/lang/concurrent/ConcurrentUtils.html">org.apache.commons.lang.concurrent.ConcurrentUtils</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.ConstantInitializer added</td><td><a href="./xref/org/apache/commons/lang/concurrent/ConstantInitializer.html">org.apache.commons.lang.concurrent.ConstantInitializer</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.LazyInitializer added</td><td><a href="./xref/org/apache/commons/lang/concurrent/LazyInitializer.html">org.apache.commons.lang.concurrent.LazyInitializer</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.MultiBackgroundInitializer added</td><td><a href="./xref/org/apache/commons/lang/concurrent/MultiBackgroundInitializer.html">org.apache.commons.lang.concurrent.MultiBackgroundInitializer</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.MultiBackgroundInitializer$MultiBackgroundInitializerResults added</td><td><a href="./xref/org/apache/commons/lang/concurrent/MultiBackgroundInitializer$MultiBackgroundInitializerResults.html">org.apache.commons.lang.concurrent.MultiBackgroundInitializer$MultiBackgroundInitializerResults</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.concurrent.TimedSemaphore added</td><td><a href="./xref/org/apache/commons/lang/concurrent/TimedSemaphore.html">org.apache.commons.lang.concurrent.TimedSemaphore</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.event.EventListenerSupport added</td><td><a href="./xref/org/apache/commons/lang/event/EventListenerSupport.html">org.apache.commons.lang.event.EventListenerSupport</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.event.EventListenerSupport$ProxyInvocationHandler added</td><td><a href="./xref/org/apache/commons/lang/event/EventListenerSupport$ProxyInvocationHandler.html">org.apache.commons.lang.event.EventListenerSupport$ProxyInvocationHandler</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.event.EventUtils added</td><td><a href="./xref/org/apache/commons/lang/event/EventUtils.html">org.apache.commons.lang.event.EventUtils</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.exception.ContextedException added</td><td><a href="./xref/org/apache/commons/lang/exception/ContextedException.html">org.apache.commons.lang.exception.ContextedException</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.exception.ContextedRuntimeException added</td><td><a href="./xref/org/apache/commons/lang/exception/ContextedRuntimeException.html">org.apache.commons.lang.exception.ContextedRuntimeException</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.exception.DefaultExceptionContext added</td><td><a href="./xref/org/apache/commons/lang/exception/DefaultExceptionContext.html">org.apache.commons.lang.exception.DefaultExceptionContext</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.exception.ExceptionContext added</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionContext.html">org.apache.commons.lang.exception.ExceptionContext</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Throwable getCause(java.lang.Throwable)' has been deprecated</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionUtils.html">org.apache.commons.lang.exception.ExceptionUtils</a></td><td>public java.lang.Throwable getCause(java.lang.Throwable)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Throwable getCause(java.lang.Throwable, java.lang.String[])' has been deprecated</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionUtils.html">org.apache.commons.lang.exception.ExceptionUtils</a></td><td>public java.lang.Throwable getCause(java.lang.Throwable, java.lang.String[])</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.String[] getDefaultCauseMethodNames()' has been added</td><td><a href="./xref/org/apache/commons/lang/exception/ExceptionUtils.html">org.apache.commons.lang.exception.ExceptionUtils</a></td><td>public java.lang.String[] getDefaultCauseMethodNames()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public int compareTo(org.apache.commons.lang.math.Fraction)' has been added</td><td><a href="./xref/org/apache/commons/lang/math/Fraction.html">org.apache.commons.lang.math.Fraction</a></td><td>public int compareTo(org.apache.commons.lang.math.Fraction)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public int compareTo(org.apache.commons.lang.mutable.MutableBoolean)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableBoolean.html">org.apache.commons.lang.mutable.MutableBoolean</a></td><td>public int compareTo(org.apache.commons.lang.mutable.MutableBoolean)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object getValue()' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableBoolean.html">org.apache.commons.lang.mutable.MutableBoolean</a></td><td>public java.lang.Object getValue()</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void setValue(java.lang.Boolean)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableBoolean.html">org.apache.commons.lang.mutable.MutableBoolean</a></td><td>public void setValue(java.lang.Boolean)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public int compareTo(org.apache.commons.lang.mutable.MutableByte)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableByte.html">org.apache.commons.lang.mutable.MutableByte</a></td><td>public int compareTo(org.apache.commons.lang.mutable.MutableByte)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object getValue()' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableByte.html">org.apache.commons.lang.mutable.MutableByte</a></td><td>public java.lang.Object getValue()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void setValue(java.lang.Number)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableByte.html">org.apache.commons.lang.mutable.MutableByte</a></td><td>public void setValue(java.lang.Number)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public int compareTo(org.apache.commons.lang.mutable.MutableDouble)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableDouble.html">org.apache.commons.lang.mutable.MutableDouble</a></td><td>public int compareTo(org.apache.commons.lang.mutable.MutableDouble)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object getValue()' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableDouble.html">org.apache.commons.lang.mutable.MutableDouble</a></td><td>public java.lang.Object getValue()</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void setValue(java.lang.Number)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableDouble.html">org.apache.commons.lang.mutable.MutableDouble</a></td><td>public void setValue(java.lang.Number)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public int compareTo(org.apache.commons.lang.mutable.MutableFloat)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableFloat.html">org.apache.commons.lang.mutable.MutableFloat</a></td><td>public int compareTo(org.apache.commons.lang.mutable.MutableFloat)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object getValue()' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableFloat.html">org.apache.commons.lang.mutable.MutableFloat</a></td><td>public java.lang.Object getValue()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void setValue(java.lang.Number)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableFloat.html">org.apache.commons.lang.mutable.MutableFloat</a></td><td>public void setValue(java.lang.Number)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public int compareTo(org.apache.commons.lang.mutable.MutableInt)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableInt.html">org.apache.commons.lang.mutable.MutableInt</a></td><td>public int compareTo(org.apache.commons.lang.mutable.MutableInt)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object getValue()' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableInt.html">org.apache.commons.lang.mutable.MutableInt</a></td><td>public java.lang.Object getValue()</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void setValue(java.lang.Number)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableInt.html">org.apache.commons.lang.mutable.MutableInt</a></td><td>public void setValue(java.lang.Number)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public int compareTo(org.apache.commons.lang.mutable.MutableLong)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableLong.html">org.apache.commons.lang.mutable.MutableLong</a></td><td>public int compareTo(org.apache.commons.lang.mutable.MutableLong)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object getValue()' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableLong.html">org.apache.commons.lang.mutable.MutableLong</a></td><td>public java.lang.Object getValue()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void setValue(java.lang.Number)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableLong.html">org.apache.commons.lang.mutable.MutableLong</a></td><td>public void setValue(java.lang.Number)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public int compareTo(org.apache.commons.lang.mutable.MutableShort)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableShort.html">org.apache.commons.lang.mutable.MutableShort</a></td><td>public int compareTo(org.apache.commons.lang.mutable.MutableShort)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object getValue()' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableShort.html">org.apache.commons.lang.mutable.MutableShort</a></td><td>public java.lang.Object getValue()</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void setValue(java.lang.Number)' has been added</td><td><a href="./xref/org/apache/commons/lang/mutable/MutableShort.html">org.apache.commons.lang.mutable.MutableShort</a></td><td>public void setValue(java.lang.Number)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.reflect.TypeUtils added</td><td><a href="./xref/org/apache/commons/lang/reflect/TypeUtils.html">org.apache.commons.lang.reflect.TypeUtils</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.FormattableUtils added</td><td><a href="./xref/org/apache/commons/lang/text/FormattableUtils.html">org.apache.commons.lang.text.FormattableUtils</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added java.lang.Appendable to the set of implemented interfaces</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Added java.lang.CharSequence to the set of implemented interfaces</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public org.apache.commons.lang.text.StrBuilder append(java.lang.CharSequence)' has been added</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td>public org.apache.commons.lang.text.StrBuilder append(java.lang.CharSequence)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public org.apache.commons.lang.text.StrBuilder append(java.lang.CharSequence, int, int)' has been added</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td>public org.apache.commons.lang.text.StrBuilder append(java.lang.CharSequence, int, int)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Appendable append(char)' has been added</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td>public java.lang.Appendable append(char)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Appendable append(java.lang.CharSequence, int, int)' has been added</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td>public java.lang.Appendable append(java.lang.CharSequence, int, int)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Appendable append(java.lang.CharSequence)' has been added</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td>public java.lang.Appendable append(java.lang.CharSequence)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.CharSequence subSequence(int, int)' has been added</td><td><a href="./xref/org/apache/commons/lang/text/StrBuilder.html">org.apache.commons.lang.text.StrBuilder</a></td><td>public java.lang.CharSequence subSequence(int, int)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void add(java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/text/StrTokenizer.html">org.apache.commons.lang.text.StrTokenizer</a></td><td>public void add(java.lang.String)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object next()' has been added</td><td><a href="./xref/org/apache/commons/lang/text/StrTokenizer.html">org.apache.commons.lang.text.StrTokenizer</a></td><td>public java.lang.Object next()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.lang.Object previous()' has been added</td><td><a href="./xref/org/apache/commons/lang/text/StrTokenizer.html">org.apache.commons.lang.text.StrTokenizer</a></td><td>public java.lang.Object previous()</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public void set(java.lang.String)' has been added</td><td><a href="./xref/org/apache/commons/lang/text/StrTokenizer.html">org.apache.commons.lang.text.StrTokenizer</a></td><td>public void set(java.lang.String)</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.WordUtils added</td><td><a href="./xref/org/apache/commons/lang/text/WordUtils.html">org.apache.commons.lang.text.WordUtils</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.AggregateTranslator added</td><td><a href="./xref/org/apache/commons/lang/text/translate/AggregateTranslator.html">org.apache.commons.lang.text.translate.AggregateTranslator</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.CharSequenceTranslator added</td><td><a href="./xref/org/apache/commons/lang/text/translate/CharSequenceTranslator.html">org.apache.commons.lang.text.translate.CharSequenceTranslator</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.CodePointTranslator added</td><td><a href="./xref/org/apache/commons/lang/text/translate/CodePointTranslator.html">org.apache.commons.lang.text.translate.CodePointTranslator</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.EntityArrays added</td><td><a href="./xref/org/apache/commons/lang/text/translate/EntityArrays.html">org.apache.commons.lang.text.translate.EntityArrays</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.LookupTranslator added</td><td><a href="./xref/org/apache/commons/lang/text/translate/LookupTranslator.html">org.apache.commons.lang.text.translate.LookupTranslator</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.NumericEntityEscaper added</td><td><a href="./xref/org/apache/commons/lang/text/translate/NumericEntityEscaper.html">org.apache.commons.lang.text.translate.NumericEntityEscaper</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.NumericEntityUnescaper added</td><td><a href="./xref/org/apache/commons/lang/text/translate/NumericEntityUnescaper.html">org.apache.commons.lang.text.translate.NumericEntityUnescaper</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.NumericEntityUnescaper$OPTION added</td><td><a href="./xref/org/apache/commons/lang/text/translate/NumericEntityUnescaper$OPTION.html">org.apache.commons.lang.text.translate.NumericEntityUnescaper$OPTION</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.OctalUnescaper added</td><td><a href="./xref/org/apache/commons/lang/text/translate/OctalUnescaper.html">org.apache.commons.lang.text.translate.OctalUnescaper</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.UnicodeEscaper added</td><td><a href="./xref/org/apache/commons/lang/text/translate/UnicodeEscaper.html">org.apache.commons.lang.text.translate.UnicodeEscaper</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.text.translate.UnicodeUnescaper added</td><td><a href="./xref/org/apache/commons/lang/text/translate/UnicodeUnescaper.html">org.apache.commons.lang.text.translate.UnicodeUnescaper</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public java.util.Date add(java.util.Date, int, int)' is no longer deprecated</td><td><a href="./xref/org/apache/commons/lang/time/DateUtils.html">org.apache.commons.lang.time.DateUtils</a></td><td>public java.util.Date add(java.util.Date, int, int)</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public long getNanoTime()' has been added</td><td><a href="./xref/org/apache/commons/lang/time/StopWatch.html">org.apache.commons.lang.time.StopWatch</a></td><td>public long getNanoTime()</td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Method 'public long getSplitNanoTime()' has been added</td><td><a href="./xref/org/apache/commons/lang/time/StopWatch.html">org.apache.commons.lang.time.StopWatch</a></td><td>public long getSplitNanoTime()</td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.tuple.ImmutablePair added</td><td><a href="./xref/org/apache/commons/lang/tuple/ImmutablePair.html">org.apache.commons.lang.tuple.ImmutablePair</a></td><td></td></tr><tr class="b"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.tuple.MutablePair added</td><td><a href="./xref/org/apache/commons/lang/tuple/MutablePair.html">org.apache.commons.lang.tuple.MutablePair</a></td><td></td></tr><tr class="a"><td><img alt="Info" src="images/icon_info_sml.gif" /></td><td>Class org.apache.commons.lang.tuple.Pair added</td><td><a href="./xref/org/apache/commons/lang/tuple/Pair.html">org.apache.commons.lang.tuple.Pair</a></td><td></td></tr></table></div>
245 </div>
246 </div>
247 <div class="clear">
248 <hr/>
249 </div>
250 <div id="footer">
251 <div class="center">Copyright &#169; 2001-2011
252 <a href="http://www.apache.org/">The Apache Software Foundation</a>.
253 All Rights Reserved.
254
255 </div>
256
257 <div class="center">Apache Commons, Apache Commons Lang, Apache, the Apache feather logo, and the Apache Commons project logos are trademarks of The Apache Software Foundation.
258 All other marks mentioned may be trademarks or registered trademarks of their respective owners.</div>
259 <div class="clear">
260 <hr/>
261 </div>
262 </div>
263 </body>
264 </html>
0 <?xml version="1.0" encoding="ISO-8859-1"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <project name="Lang">
18 <bannerRight>
19 <name>Commons Lang</name>
20 <src>/images/logo.png</src>
21 <href>/index.html</href>
22 </bannerRight>
23
24 <body>
25 <menu name="Lang">
26 <item name="Overview" href="/index.html"/>
27 <item name="Download" href="/download_lang.cgi"/>
28 <item name="Users guide" href="/userguide.html"/>
29 <item name="Release History" href="/release-history.html"/>
30 <item name="Javadoc (3.0 release)" href="api-release/index.html"/>
31 </menu>
32
33 <menu name="Development">
34 <item name="Building" href="/building.html"/>
35 <item name="Mailing Lists" href="/mail-lists.html"/>
36 <item name="Issue Tracking" href="/issue-tracking.html"/>
37 <item name="Proposal" href="/proposal.html"/>
38 <item name="Developer guide" href="/developerguide.html"/>
39 <item name="Source Repository" href="/source-repository.html"/>
40 <item name="Javadoc (SVN latest)" href="apidocs/index.html"/>
41 </menu>
42
43 </body>
44
45 </project>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>What's new in Commons Lang 2.4?</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="What's new in Commons Lang 2.4?">
25 <p>Commons Lang 2.4 is out, and the obvious question is: <i>"So what? What's changed?"</i>.</p>
26 <p>This article aims to briefly cover the changes and save you from having to dig through each JIRA
27 issue to see what went on in the year of development between Lang 2.3 and 2.4.</p>
28 <section name="Deprecations">
29 <p>First, let us start with a couple of deprecations. As you can see in the release notes, we chose
30 to deprecate the <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/ObjectUtils.html#appendIdentityToString(java.lang.StringBuffer,%20java.lang.Object)"><code>ObjectUtils.appendIdentityToString(StringBuffer, Object)</code></a> method as its
31 null handling did not match its design (see <a href="http://issues.apache.org/jira/browse/LANG-360">LANG-360</a>
32 for more details. Instead users should use <code>ObjectUtils.identityToString(StringBuffer, Object)</code>.</p>
33
34 <p>We also deprecated <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/time/DateUtils.html#add(java.util.Date,%20int,%20int)"><code>DateUtils.add(java.util.Date, int, int)</code></a>. It should have been <code>private</code>
35 from the beginning; please let us know if you actually use it.</p>
36 </section>
37 <section name="The build">
38 <p>Before we move on, a quick note on the build: we built 2.4 using Maven 2 and Java 1.4. We also tested that the Ant build passed the tests
39 successfully under Java 1.3, and that the classes compiled under Java 1.2. As it's been so long, we stopped building a Java 1.1-compatible jar. <strong>Most importantly</strong>, it <em>should</em> be a drop in replacement for Lang 2.3, but we recommend testing first, of course. Also, for those of you who work within an OSGi framework, the jar should be ready for OSGi. Now... time to move on.
40 </p>
41 </section>
42 <section name="New classes">
43 <p>Three new classes were added, so let's cover those next.</p>
44 <p>Firstly, we added an <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/math/IEEE754rUtils.html"><code>IEEE754rUtils</code></a>
45 class to the <code>org.apache.commons.lang.math</code> package.
46 This candidate for ugly name of the month was needed to add <a href="http://en.wikipedia.org/wiki/IEEE_754r#min_and_max">IEEE-754r</a>
47 semantics for some of the <code>NumberUtils</code> methods. The relevant part of that
48 IEEE specification in this case is the NaN handling for <code>min</code> and <code>max</code> methods, and
49 you can read more about it in <a href="http://issues.apache.org/jira/browse/LANG-381">LANG-381</a>.
50 </p>
51 <p>Second and third on our newcomers list are the <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/text/ExtendedMessageFormat.html"><code>ExtendedMessageFormat</code></a> class and its peer
52 <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/text/FormatFactory.html"><code>FormatFactory</code></a>
53 interface, both found in the <code>org.apache.commons.lang.text</code> package.</p>
54 <p>Together they allow you to take the <code>java.text.MessageFormat</code> class further and insert your own formatting elements.</p>
55 <p>
56 By way of an example, imagine that we have a need for custom formatting of a employee identification
57 number or EIN. Perhaps, simplistically, our EIN is composed of a two-character department code
58 followed by a four-digit number, and that it is customary within our organization to render the EIN
59 with a hyphen following the department identifier. Here we'll represent the EIN as a simple
60 String (of course in real life we would likely create a class composed of department and number).
61 We can create a custom <code>Format</code> class:
62 <pre><code>
63 public class EINFormat extends Format {
64 private char[] idMask;
65
66 public EINFormat() {
67 }
68 public EINFormat(char maskChar) {
69 idMask = new char[4];
70 Arrays.fill(idMask, maskChar);
71 }
72 public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
73 String ein = (String) obj; //assume or assert length &gt;= 2
74 if (idMask == null) {
75 return new StringBuffer(ein).insert(2, '-').toString();
76 }
77 return new StringBuffer(ein.substring(0, 2)).append('-').append(idMask).toString();
78 }
79 public Object parseObject(String source, ParsePosition pos) {
80 int idx = pos.getIndex();
81 int endIdx = idx + 7;
82 if (source == null || source.length() &lt; endIdx) {
83 pos.setErrorIndex(idx);
84 return null;
85 }
86 if (source.charAt(idx + 2) != '-') {
87 pos.setErrorIndex(idx);
88 return null;
89 }
90 pos.setIndex(endIdx);
91 return source.substring(idx, endIdx).deleteCharAt(2);
92 }
93 }
94 </code></pre>
95 Our custom EIN format is made available for <code>MessageFormat</code>-style processing by a
96 <code>FormatFactory</code> implementation:
97 <pre><code>
98 public class EINFormatFactory implements FormatFactory {
99 public static final String EIN_FORMAT = "ein";
100 public Format getFormat(String name, String arguments, Locale locale) {
101 if (EIN_FORMAT.equals(name)) {
102 if (arguments == null || "".equals(arguments)) {
103 return new EINFormat();
104 }
105 return new EINFormat(arguments.charAt(0));
106 }
107 return null;
108 }
109 }
110 </code></pre>
111
112 Now you simply provide a <code>java.util.Map&lt;String, FormatFactory&gt;</code> registry (keyed
113 by format type) to <code>ExtendedMessageFormat</code>:
114 <pre><code>
115 new ExtendedMessageFormat("EIN: {0,ein}", Collections.singletonMap(EINFormatFactory.EIN_FORMAT, new EINFormatFactory()));
116 </code></pre>
117 As expected, this will render a String EIN "AA9999" as: <code>"EIN: AA-9999"</code>.
118 <br /> <br />
119 If we wanted to trigger the EIN masking code, we could trigger that in the format pattern:
120 <pre><code>
121 new ExtendedMessageFormat("EIN: {0,ein,#}", Collections.singletonMap(EINFormatFactory.EIN_FORMAT, new EINFormatFactory()));
122 </code></pre>
123 This should render "AA9999" as: <code>"EIN: AA-####"</code>.
124 <br /> <br />
125 You can also use <code>ExtendedMessageFormat</code> to override any or all of the built-in
126 formats supported by <code>java.text.MessageFormat</code>. Finally, note that because
127 <code>ExtendedMessageFormat</code> extends <code>MessageFormat</code> it should work in most
128 cases as a <em>true</em> drop-in replacement.
129 </p>
130 </section>
131 <section name="New methods">
132 <p>There were 58 new methods added to existing Commons Lang classes. Going through each one, one at a time would be dull,
133 and fortunately there are some nice groupings that we can discuss instead:</p>
134 <p>CharSet <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/CharSet.html#getInstance(java.lang.String[])">getInstance(String[])</a> adds an additional builder method by which you can build a CharSet from multiple sets of characters at the same time. If you weren't aware of the CharSet class, it holds a set of characters created by a simple pattern language allowing constructs such as <code>"a-z"</code> and <code>"^a"</code> (everything but 'a'). It's most used by the CharSetUtils class, and came out of CharSetUtils.translate, a simple variant of the UNIX tr command.</p>
135 <p>ClassUtils <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/ClassUtils.html">canonical name</a> methods are akin to the non '<code>Canonical</code>' methods, except they work with the more human readable <code>int[]</code> type names rather than the JVM versions of <code>[I</code>. This makes them useful for parsing input from developer's configuration files. </p>
136 <p>ClassUtils <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/ClassUtils.html#toClass(java.lang.Object[])">toClass(String[])</a> is very easy to explain - it calls <code>toClass</code> on each <code>Object</code> in the array and returns an array of <code>Class</code> objects.</p>
137 <p>ClassUtils <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/ClassUtils.html#wrappersToPrimitives(java.lang.Class[])">wrapper-&gt;primitive</a> conversions are the reflection of the pre-existing <code>primitiveToWrapper</code> methods. Again easy to explain, they turn an array of <code>Integer</code> into an array of <code>int[]</code>.</p>
138 <p>ObjectUtils <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/ObjectUtils.html#identityToString(java.lang.StringBuffer,%20java.lang.Object)">identityToString(StringBuffer, Object)</a> is the StringBuffer variant of the pre-existing <code>identityToString</code> method. In case you've not met that before, it produces the toString that would have been produced by an Object if it hadn't been overridden.</p>
139 <p>StringEscapeUtils <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringEscapeUtils.html#escapeCsv(java.lang.String)">CSV methods</a> are a new addition to our range of simple parser/printers. These, quite as expected, parse and unparse CSV text as per <a href="http://tools.ietf.org/html/rfc4180">RFC-4180</a>.</p>
140 <p>StringUtils has a host of new methods, as always, and we'll leave these for later.</p>
141 <p>WordUtils <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/WordUtils.html#abbreviate(java.lang.String,%20int,%20int,%20java.lang.String)">abbreviate</a> finds the first space after the lower limit and abbreviates the text.</p>
142 <p>math.<a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/math/IntRange.html#toArray()">IntRange</a>/<a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/math/LongRange.html#toArray()">LongRange.toArray</a> turn the range into an array of primitive <code>int</code>/<code>long</code>s contained in the range.</p>
143 <p>text.StrMatch.<a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/text/StrMatcher.html#isMatch(char[],%20int)">isMatch(char[], int)</a> is a helper method for checking whether there was a match with the StrMatcher objects.</p>
144 <p>time.DateFormatUtils <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/time/DateFormatUtils.html">format(Calendar, ...)</a> provide Calendar variants for the pre-existing format methods. If these are new to you, they are helper methods to formatting a date.</p>
145 <p>time.DateUtils <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/time/DateUtils.html">getFragment*</a> methods are used to splice the time element out of Date. If you have <code>2008/12/13 14:57</code>, then these could, for example, pull out the 13.</p>
146 <p>time.DateUtils <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/time/DateUtils.html">setXxx methods</a> round off our walk through the methods - the setXxx variant of the existing addXxx helper methods.</p>
147 </section>
148
149 <section name="StringUtils methods">
150 <p>The <code>StringUtils</code> class is a little large, isn't it? Sorry, but it's gotten bigger.
151 </p>
152 <ul>
153 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#containsOnly(java.lang.String,%20char[])">boolean containsAny(String, char[])</a></li>
154 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#containsOnly(java.lang.String,%20java.lang.String)">boolean containsAny(String, String)</a></li>
155 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#endsWith(java.lang.String,%20java.lang.String)">boolean endsWith(String, String)</a></li>
156 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#endsWithIgnoreCase(java.lang.String,%20java.lang.String)">boolean endsWithIgnoreCase(String, String)</a></li>
157 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#getCommonPrefix(java.lang.String[])">String getCommonPrefix(String[])</a></li>
158 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#indexOfDifference(java.lang.String[])">int indexOfDifference(String[])</a></li>
159 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#length(java.lang.String)">int length(String)</a></li>
160 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#removeEndIgnoreCase(java.lang.String,%20java.lang.String)">String removeEndIgnoreCase(String, String)</a></li>
161 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#removeStartIgnoreCase(java.lang.String,%20java.lang.String)">String removeStartIgnoreCase(String, String)</a></li>
162 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#replaceEach(java.lang.String,%20java.lang.String[],%20java.lang.String[])">String replaceEach(String, String[], String[])</a></li>
163 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#replaceEachRepeatedly(java.lang.String,%20java.lang.String[],%20java.lang.String[])">String replaceEachRepeatedly(String, String[], String[])</a></li>
164 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#splitByCharacterType(java.lang.String)">String[] splitByCharacterType(String)</a></li>
165 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#splitByCharacterTypeCamelCase(java.lang.String)">String[] splitByCharacterTypeCamelCase(String)</a></li>
166 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#splitByWholeSeparatorPreserveAllTokens(java.lang.String,%20java.lang.String)">String[] splitByWholeSeparatorPreserveAllTokens(String, String)</a></li>
167 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#splitByWholeSeparatorPreserveAllTokens(java.lang.String,%20java.lang.String,%20int)">String[] splitByWholeSeparatorPreserveAllTokens(String, String, int)</a></li>
168 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#startsWith(java.lang.String,%20java.lang.String)">boolean startsWith(String, String)</a></li>
169 <li><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html#startsWithIgnoreCase(java.lang.String,%20java.lang.String)">boolean startsWithIgnoreCase(String, String)</a></li>
170 </ul>
171
172 <p>Hopefully they are in many cases self-describing. Rather than spend a lot of time describing them, we'll let you read the Javadoc of the ones that interest you.</p>
173
174 </section>
175
176 <section name="What's fixed in Lang 2.4?">
177 <p>In addition to new things, there are the bugfixes. As you can tell from the release notes, there are a good few - 24 in fact according to JIRA. Here are some of the interesting ones: </p>
178 <ul>
179 <li><a href="http://issues.apache.org/jira/browse/LANG-393">LANG-393</a> - We fixed EqualsBuilder so that it understands that BigDecimals are equal even when they think they're not. It seems very likely that usually you will want "29.0" and "29.00" to be equal, even if BigDecimal disagrees. </li>
180 <li><a href="http://issues.apache.org/jira/browse/LANG-380">LANG-380</a> - Chances are you'll know if you met this one. Fraction.reduce has an infinite loop if the numerator is 0. </li>
181 <li><a href="http://issues.apache.org/jira/browse/LANG-369">LANG-369</a>, <a href="http://issues.apache.org/jira/browse/LANG-367">LANG-367</a>, <a href="http://issues.apache.org/jira/browse/LANG-334">LANG-334</a> - Threading bugs - we improved how things work in concurrency situations for ExceptionUtils, FastDateFormat and Enum. </li>
182 <li><a href="http://issues.apache.org/jira/browse/LANG-346">LANG-346</a> - DateUtils.round was getting things wrong for minutes and seconds. </li>
183 <li><a href="http://issues.apache.org/jira/browse/LANG-328">LANG-328</a> - LocaleUtils.toLocale was broken if there was no country code defined. </li>
184 </ul>
185 </section>
186
187 <section name="So long, farewell...">
188 <p>Hopefully that was all of interest. Don't forget to download <a href="http://commons.apache.org/lang/download_lang.cgi">Lang 2.4</a>, or, for the Maven repository users, upgrade your &lt;version&gt; tag to 2.4. Please feel free to raise any questions you might have on the <a href="mail-lists.html">mailing lists</a>, and report bugs or enhancements in the <a href="issue-tracking.html">issue tracker</a>.</p>
189 </section>
190
191 </section>
192
193 </body>
194 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>What's new in Commons Lang 2.5?</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="What's new in Commons Lang 2.5?">
25 <p>Commons Lang 2.5 is out, and the obvious question is: <i>"So what? What's changed?"</i>.</p>
26 <p>This article aims to briefly cover the changes and save you from having to dig through each JIRA
27 issue to see what went on in the two years of development between Lang 2.4 and 2.5.</p>
28 <p>Two years?!? Yes, it's true. The reason is that 2.5 represents the backwards compatible changes in the
29 nearly complete Java-5 focused Lang 3.0. </p>
30 <section name="Deprecations">
31 <p>There were no new deprecations in 2.5. </p>
32 </section>
33 <section name="The build">
34 <p>2.5 was built using Sun's 1.6.0_17 JVM, but targets Java 1.3. </p>
35 </section>
36 <section name="New classes">
37 <p>A new org.apache.commons.lang.reflect package was added, accumulating common high-level uses of the java.lang.reflect APIs. The
38 classes, hopefully self-evident in nature, were pulled together from the existing BeanUtils and the unreleased Reflect components.
39 The classes are: </p>
40 <ul>
41 <li>ConstructorUtils - primarily creating new instances of classes</li>
42 <li>FieldUtils - primarily reading and writing to Object/Class fields</li>
43 <li>MethodUtils - primarily methods to make invoking methods simpler</li>
44 </ul>
45 <p>You can read more about the classes in their
46 <a href="LANG_2_5/src/main/java/org/apache/commons/lang/reflect//MemberUtils.java">javadoc</a>. </p>
47 </section>
48 <section name="New fields">
49 <p>With both Java 7 and Windows 7 becoming a reality,
50 <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/SystemUtils.html">SystemUtils</a> was updated to
51 provide boolean fields for both versions. </p>
52 </section>
53 <section name="New methods">
54 <p>There were 66 new methods added to existing Commons Lang classes. </p>
55 <p>The <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/ArrayUtils.html">ArrayUtils</a> class
56 received two new types of methods. Firstly, a boolean isNotEmpty(array) set of methods, identifying whether the particular
57 array is null or an empty sized array. This makes it the inverse of the existing isEmpty(array) methods. Secondly, an array
58 nullToEmpty(array) set of methods that converts null or empty arrays to a singleton empty array already available from the
59 ArrayUtils class. Non null/empty arrays are left untouched. </p>
60
61 <p>The constructor for the
62 <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/CharRange.html">CharRange</a> class is somewhat
63 confusing. It takes a boolean parameter that when set to true means the CharRange is negated. To make code easier to read, the
64 following static helper methods were added: </p>
65 <ul>
66 <li>public org.apache.commons.lang.CharRange is(char)</li>
67 <li>public org.apache.commons.lang.CharRange isIn(char, char)</li>
68 <li>public org.apache.commons.lang.CharRange isNot(char)</li>
69 <li>public org.apache.commons.lang.CharRange isNotIn(char, char)</li>
70 </ul>
71 <p>An iterator() method was also added to provide another way of walking the range. </p>
72
73 <p>The <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/builder/EqualsBuilder.html">EqualsBuilder</a>
74 obtained a new reset() method to allow for reuse, while the
75 <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/builder/HashCodeBuilder.html">HashCodeBuilder</a>
76 received a hashCode() method that returns the built hash code instead of the natural hash code of the builder object itself. It
77 doesn't really matter what the builder chooses to use as a hash code and this stops accidental use of the hashCode() instead of
78 toHashCode() method from causing lots of pain. </p>
79
80 <p>Helper isFalse(), isTrue() and toBoolean() methods were added to
81 <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/mutable/MutableBoolean.html">MutableBoolean</a>,
82 while the other mutable classes received String argument constructors. </p>
83
84 <p>Lastly, the <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/time/DateUtils.html">DateUtils</a>
85 class received a new ceiling set of methods to truncate upwards, and a parseDateStrictly method to parse a Date with the
86 supplied DateFormat classes leniency set to false. </p>
87
88 </section>
89
90 <section name="StringUtils methods">
91 <p>As with 2.4, the
92 <a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html">StringUtils</a> class has
93 grown and we cover its new methods in its own section. </p>
94 <ul>
95 <li>abbreviateMiddle(String, String, int);String - This method turns aRatherLongNameSuchAsAFileName into 'aRatherLo...AFileName'.
96 This is often desirable when you want to restrict the length of a name, but you can afford to have quite long names. </li>
97 <li>indexOfIgnoreCase(String, String);int - An indexOf method that ignores the case of what it's matching. Matching lastIndexOfIgnoreCase and 'start at index' variants were also added. </li>
98 <li>lastOrdinalIndexOf(String, String, int);int - A matching variant for the already exisitng ordinalIndexOf method - they
99 support finding the Nth indexOf instead of the first time the search term is found. </li>
100 <li>isAllLowerCase(String);boolean - Is the String all lower case. </li>
101 <li>isAllUpperCase(String);boolean - Is the String all upper case. </li>
102 <li>lowerCase(String, Locale);String - Null protected toLowerCase methods for the platform independent inclined. </li>
103 <li>upperCase(String, Locale);String - Null protected toUpperCase methods for the platform independent inclined. </li>
104 <li>repeat(String, String, int);String - Repeat option that includes an optional separator. </li>
105 <li>startsWithAny(String, String[]);boolean - Does the specified String start with any of the supplied values. </li>
106 </ul>
107 </section>
108
109 <section name="What's fixed in Lang 2.5?">
110 <p>Per the <a href="upgradeto2_5.html">release notes</a> there are 32 bugs fixed in Lang 2.5. Some highlights are: </p>
111 <ul>
112 <li><a href="http://issues.apache.org/jira/browse/LANG-477">LANG-477</a> - fixing an OutOfMemoryError in ExtendedMessageFormat. </li>
113 <li><a href="http://issues.apache.org/jira/browse/LANG-76">LANG-76</a> - EnumUtils.getEnum() doesn't work well in 1.5. </li>
114 <li><a href="http://issues.apache.org/jira/browse/LANG-204">LANG-204</a> and
115 <a href="http://issues.apache.org/jira/browse/LANG-506">LANG-506</a> - Multithread improvements to the package private Entities
116 class, used behind the scenes by StringEscapeUtils. </li>
117 <li><a href="http://issues.apache.org/jira/browse/LANG-511">LANG-511</a> - Improve performance by deferring LocaleUtils initialization. </li>
118 <li><a href="http://issues.apache.org/jira/browse/LANG-523">LANG-523</a> - Two orders of magnitude performance improvement in StrBuilder. </li>
119 <li><a href="http://issues.apache.org/jira/browse/LANG-467">LANG-467</a> - Reverted the change to EqualsBuilder in Lang 2.4 to
120 specially handle BigDecimal. While useful, it put things out of sync with HashCodeBuilder. </li>
121 <li><a href="http://issues.apache.org/jira/browse/LANG-586">LANG-586</a> - Use of a ThreadLocal in HashCodeBuilder and
122 ToStringStyle meant that containers could end up with memory leaks. This was rewritten to avoid this. </li>
123 <li><a href="http://issues.apache.org/jira/browse/LANG-472">LANG-472</a> - RandomUtils.nextLong() was returning only even numbers. Fans of Java-based roulette wheels can breathe a sigh of relief. </li>
124 </ul>
125 </section>
126
127 <section name="So long, farewell...">
128 <p>Hopefully that was all of interest. Don't forget to download <a href="http://commons.apache.org/lang/download_lang.cgi">Lang 2.5</a>, or, for the Maven repository users, upgrade your &lt;version&gt; tag to 2.5. Please feel free to raise any questions you might have on the <a href="mail-lists.html">mailing lists</a>, and report bugs or enhancements in the <a href="issue-tracking.html">issue tracker</a>.</p>
129 </section>
130
131 </section>
132
133 </body>
134 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>What's new in Commons Lang 3.0?</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="What's new in Commons Lang 3.0?">
25 <p>Commons Lang 3.0 is out, and the obvious question is: <i>"So what? What's changed?"</i>.</p>
26 <section name="The big story">
27 <p>Lang is now Java 5 based. We've generified the API, moved certain APIs to support <code>varargs</code> and thrown out any features
28 that are now supported by Java itself. We've removed the deprecated parts of the API and have also removed some features that
29 were deemed weak or unnecessary. All of this means that Lang 3.0 is not backwards compatible. </p>
30 <p>To that end we have changed the package name, allowing Lang 3.0 to sit side-by-side with your previous version of Lang without any bad side effects. The new package name is the exciting and original <code>org.apache.commons.lang3</code>. This also forces you to recompile your code, making sure the compiler can let you know if a backwards incompatibility affects you. </p>
31 <p>As you'd expect, there are also new features, enhancements and bugs fixed. </p>
32 </section>
33 <!--
34 <section name="The build">
35 <p>We built 3.0 using Maven 2.2.1 and Java 1.5. <strong>Needs confirmation before release of actual build details</strong></p>
36 </section>
37 -->
38 <section name="Migrating from 2.x">
39 <h3>Java code</h3>
40 <p>Despite the label of backwards incompatibility, in the vast majority of cases the simple addition of a <code>'3'</code> to an import statement will suffice for your migration. </p><br/>
41 <p>Change: <code>import org.apache.commons.lang</code> -&gt; <code>import org.apache.commons.lang3</code></p>
42 <h3>Maven</h3>
43 <p><code>groupId</code>: <code>commons-lang</code> -&gt; <code>org.apache.commons</code></p>
44 <p><code>artifactId</code>: <code>commons-lang</code> -&gt; <code>commons-lang3</code></p>
45 </section>
46
47 <section name="What's gone?">
48 <h3>Enum package</h3>
49 <p>Java 5 provided enums out of the box, therefore we dispensed with both the deprecated enum package,
50 and the enums package. Instead you should migrate over to the standard Java enum. An EnumUtils class has been born
51 from the ashes of the old code, focused on providing additional functionality to the standard Java enum API. </p>
52 <h3>NestedExceptions</h3>
53 <p>In Java 1.4, the notion that all Throwables could be linked to a cause was introduced. In Lang we
54 had provided a NestedException framework to support the same feature, and now that we're jumping from Java 1.3 to
55 Java 5 we are remove this feature. The deprecation section below covers one part of ExceptionUtils that remains until
56 we are on Java 6, where the last remaining parts of the JDK appear to have embraced the new cause API. </p>
57 <h3>JVMRandom</h3>
58 <p>This class was introduced in Lang 2.0 to support a Random object built around the system seed. This
59 proved to be both an uncommon use case and one with bugs and so was dropped. </p>
60 <h3>StringEscapeUtils.escapeSql</h3>
61 <p>This was a misleading method, only handling the simplest of possible SQL cases. As SQL is not Lang's focus, it didn't make sense to maintain this method. </p>
62 <h3>*Exceptions removed</h3>
63 <p>Various Exception classes were removed - the lesson in defining more semantically relevant exception classes is that you can keep on coming up with more and more new classes. Simpler to focus on using the main JDK classes. </p>
64 <h3>math.*Range</h3>
65 <p>The various Range classes in the <code>math</code> package were removed in favour of a new generic Range class. </p>
66 <h3>Previous Deprecations</h3>
67 <p>All deprecated fields/methods/classes - with a new major version, all of the previously deprecated parts of the API could finally go away. </p>
68 <p>If you feel that something was unfairly taken away, please feel free to contact the list. In many cases the possibility exists to reintroduce code. </p>
69 </section>
70 <section name="Deprecations">
71 <p>The lone deprecation in 3.0 is that of the notion of 'cause method names' in ExceptionUtils. In Java 5.0 it is still just about
72 needed to handle some JDK classes that have not been migrated to the getCause API. In Java 6.0 things appear to be resolved and
73 we will remove the related methods in Lang 4.0. </p>
74 </section>
75 <section name="New packages">
76 <p>Two new packages have shown up. org.apache.commons.lang3.concurrent, which unsurprisingly provides support classes for
77 multi-threaded programming, and org.apache.commons.lang3.text.translate, which provides a pluggable API for text transformation. </p>
78
79 <h3>concurrent.*</h3>
80 <p>Java 1.5 adds a great bunch of functionality related to multi-threaded programming
81 below the <code>java.util.concurrent</code> package. Commons Lang 3.0 provides
82 some additional classes in this area which are intended to further simplify the
83 development of concurrent applications.</p>
84 <p>The classes located in the <code>concurrent</code> package can be roughly
85 divided into the following categories:
86 <ul>
87 <li>Utility classes</li>
88 <li>Initializer classes</li>
89 </ul>
90 </p>
91 <p>Classes of the former category provide some basic functionality a developer
92 typically has to implement manually again and again. Examples are a configurable
93 <code>ThreadFactory</code> implementation or utility methods for the handling of
94 <code>ExecutionException</code>s thrown by Java's executor service framework.</p>
95 <p>Initializer classes deal with the creation of objects in a multi-threaded
96 environment. There are several variants of initializer implementations serving
97 different purposes. For instance, there are a couple of concrete initializers
98 supporting lazy initialization of objects in a safe way. Another example is
99 <code>BackgroundInitializer</code> which allows pushing the creation of an
100 expensive object to a background thread while the application can continue with
101 the execution of other tasks. Here is an example of the usage of <code>BackgroundInitializer</code>
102 which creates an <code>EntityManagerFactory</code> object:</p>
103 <pre>
104 public class DBInitializer extends BackgroundInitialize&lt;EntityManagerFactory&gt; {
105 protected EntityManagerFactory initialize() {
106 return Persistence.createEntityManagerFactory(&quot;mypersistenceunit&quot;);
107 }
108 }
109 </pre>
110 <p>An application creates an instance of the <code>DBInitializer</code> class
111 and calls its <code>start()</code> method. When it later needs access to the
112 <code>EntityManagerFactory</code> created by the initializer it calls the
113 <code>get()</code> method; <code>get()</code> returns the object produced by the
114 initializer if it is already available or blocks if necessary until initialization
115 is complete. Alternatively a convenience method of the <code>ConcurrentUtils</code>
116 class can be used to obtain the object from the initializer which hides the
117 checked exception declared by <code>get()</code>:</p>
118 <pre>
119 DBInitializer init = new DBInitializer();
120 init.start();
121
122 // now do some other stuff
123
124 EntityManagerFactory factory = ConcurrentUtils.initializeUnchecked(init);
125 </pre>
126 <p>Comprehensive documentation about the <code>concurrent</code> package is
127 available in the <a href="userguide.html#lang.concurrent.">user guide</a>.</p>
128 <h3>text.translate.*</h3>
129 <p>A common complaint with StringEscapeUtils was that its escapeXml and escapeHtml methods should not be escaping non-ASCII characters. We agreed and made the change while creating a modular approach to let users define their own escaping constructs. </p>
130 <p>The simplest way to show this is to look at the code that implements escapeXml:</p>
131 <pre>
132 return ESCAPE_XML.translate(input);
133 </pre>
134 <p>Very simple. Maybe a bit too very simple, let's look a bit deeper. </p>
135 <pre>
136 public static final CharSequenceTranslator ESCAPE_XML =
137 new AggregateTranslator(
138 new LookupTranslator(EntityArrays.BASIC_ESCAPE()),
139 new LookupTranslator(EntityArrays.APOS_ESCAPE())
140 );
141 </pre>
142 <p>Here we see that <code>ESCAPE_XML</code> is a '<code>CharSequenceTranslator</code>', which in turn is made up of two lookup translators based on the basic XML escapes and another to escape apostrophes. This shows one way to combine translators. Another can be shown by looking at the example to achieve the old XML escaping functionality (escaping non-ASCII): </p>
143 <pre>
144 StringEscapeUtils.ESCAPE_XML.with( NumericEntityEscaper.between(0x7f, Integer.MAX_VALUE) );
145 </pre>
146 <p>That takes the standard Commons Lang provided escape functionality, and adds on another translation layer. Another JIRA requested option was to also escape non-printable ASCII, this is now achievable with a modification of the above: </p>
147 <pre>
148 StringEscapeUtils.ESCAPE_XML.with(
149 new AggregateTranslator(
150 NumericEntityEscaper.between(0, 31),
151 NumericEntityEscaper.between(0x80, Integer.MAX_VALUE)
152 )
153 )
154 </pre>
155 <p>You can also implement your own translators (be they for escaping, unescaping or some aspect of your own). See the <code>CharSequenceTranslator</code> and its <code>CodePointTranslator</code> helper subclass for details - primarily a case of implementing the translate(CharSequence, int, Writer);int method. </p>
156 </section>
157 <section name="New classes + methods">
158 <p>There are many new classes and methods in Lang 3.0 - the most complete way to see the changes is via this <a href="lang2-lang3-clirr-report.html">Lang2 to Lang3 Clirr report</a>. </p>
159 <p>Here is a summary of the new classes: </p>
160 <ul>
161 <li><code>AnnotationUtils</code></li>
162 <li><code>CharSequenceUtils</code></li>
163 <li><code>EnumUtils</code></li>
164 <li><code>JavaVersion</code> - used in SystemUtils</li>
165 <li><code>Pair, ImmutablePair and MutablePair</code></li>
166 <li><code>Range</code> - replaces the old math.*Range classes</li>
167 <li><code>builder.Builder</code></li>
168 <li><code>exception.ContextedException</code></li>
169 <li><code>exception.CloneFailedException</code></li>
170 <li><code>reflect.ConstructorUtils</code></li>
171 <li><code>reflect.FieldUtils</code></li>
172 <li><code>reflect.MethodUtils</code></li>
173 <li><code>reflect.TypeUtils</code></li>
174 <li><code>text.WordUtils</code></li>
175 </ul>
176 </section>
177
178 <section name="Bugfixes?">
179 <p>See the <a href="changes-report.html#3.0">3.0 changes report</a> for the list of fixed bugs and other enhancements. </p>
180 </section>
181
182 <section name="Other Notable Changes">
183 <ul>
184 <li>StringUtils.isAlpha, isNumeric and isAlphanumeric now all return false when passed an empty String. Previously they returned true. </li>
185 <li>SystemUtils.isJavaVersionAtLeast now relies on the <code>java.specification.version</code> and not the <code>java.version</code> System property. </li>
186 <li>StringEscapeUtils.escapeXml and escapeHtml no longer escape high value Unicode characters by default. The text.translate package is available to recreate the old behaviour. </li>
187 </ul>
188 </section>
189
190 <!--
191 <section name="What next???"> TODO: Add Beta info.
192 <p>Hopefully that was all of interest. Don't forget to download <a href="http://commons.apache.org/lang/download_lang.cgi">Lang 3.0</a>, or, for the Maven repository users, upgrade your &lt;version&gt; tag to 3.0 and your groupId to org.apache.commons. Please feel free to raise any questions you might have on the <a href="mail-lists.html">mailing lists</a>, and report bugs or enhancements in the <a href="issue-tracking.html">issue tracker</a>.</p>
193 </section>
194 -->
195
196 </section>
197
198 </body>
199 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>Building</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23 <!-- ================================================== -->
24 <section name="Overview">
25 <p>
26 Commons Lang uses <a href="http://maven.apache.org">Maven</a> or
27 <a href="http://ant.apache.org">Ant</a> as a build system.
28 </p>
29 <p>
30 You may also be interested in the upgrade notes:
31 </p>
32 <ul>
33 <li>Upgrade from 2.6 to 3.0 - <a href="upgradeto3_0.html">Lang 3.0 Release Notes</a></li>
34 <li>Upgrade from 2.5 to 2.6 - <a href="upgradeto2_6.html">Lang 2.6 Release Notes</a></li>
35 <li>Upgrade from 2.4 to 2.5 - <a href="upgradeto2_5.html">Lang 2.5 Release Notes</a></li>
36 <li>Upgrade from 2.3 to 2.4 - <a href="upgradeto2_4.html">Lang 2.4 Release Notes</a></li>
37 <li>Upgrade from 2.2 to 2.3 - <a href="upgradeto2_3.html">Lang 2.3 Release Notes</a></li>
38 <li>Upgrade from 2.1 to 2.2 - <a href="upgradeto2_2.html">Lang 2.2 Release Notes</a></li>
39 <li>Upgrade from 2.0 to 2.1 - <a href="upgradeto2_1.html">Lang 2.1 Release Notes</a></li>
40 <li>Upgrade from 1.0 to 2.0 - <a href="upgradeto2_0.html">Lang 2.0 Release Notes</a></li>
41 </ul>
42 </section>
43 <!-- ================================================== -->
44 <section name="Maven Goals">
45 <p>
46 To build a jar file, change into the root directory of Lang and run "mvn package".
47 The result will be in the "target" subdirectory.
48 </p>
49 <p>
50 To build the full website, run "mvn site".
51 The result will be in "target/site".
52 You must be online to successfully complete this target.
53 </p>
54 <p>
55 Further details can be found in the
56 <a href="http://commons.apache.org/building.html">commons build instructions</a>.
57 </p>
58 </section>
59 <!-- ================================================== -->
60 <section name="Ant Goals">
61 <p>
62 To build a jar file, change into the root directory of Lang and run "ant jar".
63 The result will be in the "target" subdirectory.
64 </p>
65 <p>
66 To build the Javadocs, run "ant javadoc".
67 The result will be in "target/docs/api".
68 </p>
69 </section>
70 <!-- ================================================== -->
71 </body>
72 </document>
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <document>
17 <properties>
18 <title>Developer guide for Commons "Lang"</title>
19 </properties>
20 <body>
21
22 <!-- $Id: developerguide.xml 930469 2010-04-03 04:37:26Z bayard $ -->
23
24 <section name='Developer guide for Commons "Lang"'>
25
26
27 <div align="center">
28 <h1>The Commons <em>Lang</em> Package</h1>
29 <h2>Developers Guide</h2>
30 <br />
31 <a href="#Introduction">[Introduction]</a>
32 <a href="#PackageStructure">[Package Structure]</a>
33 <a href="#UtilityClasses">[Utility Classes]</a>
34 <a href="#Javadoc">[Javadoc]</a>
35 <a href="#Building">[Building]</a>
36 <br /><br />
37 </div>
38
39
40 <a name="Introduction"></a>
41 <h3>1. INTRODUCTION</h3>
42
43 <p>The <em>Lang</em> package contains a set of Java classes that extend
44 the basic JDK classes. This developer guide seeks to set
45 out rules for the naming of classes and methods within the package. The purpose
46 of this, as with all naming standards, is to improve the coherency and
47 consistency of the whole API.</p>
48
49 <p>The philosophy of the naming standards is to follow those of the JDK
50 if possible.</p>
51
52
53
54 <a name="PackageStructure"></a>
55 <h3>2. PACKAGE STRUCTURE</h3>
56
57 <p>The main package for Lang is <code>org.apache.commons.lang3</code>. Subpackages should
58 be created for each group of related items. </p>
59
60 <p>Each package should have a <code>package.html</code> file for javadoc. This should
61 describe the use of the package and its scope.</p>
62
63
64
65 <a name="UtilityClasses"></a>
66 <h3>3. UTILITY CLASSES</h3>
67
68 <p>Utility classes provide additional functionality around a class or interface.
69 Examples include StringUtils and SerializationUtils.</p>
70
71 <p>Each class shall follow the naming pattern XxxUtils where Xxx relates to the
72 class or interface that the utility services. Variations on a theme (<code>Integer</code>
73 as opposed to <code>Number</code>) should be dealt with in one Utils class where possible.
74 Each Utils class shall:</p>
75
76 <ul>
77 <li>be a single, static method based, class</li>
78 <li>have a name consisting of the interface name plus 'Utils'</li>
79 <li>deal with one class or interface and its variations (subclasses)</li>
80 <li>provide methods that perform useful utility functions</li>
81 <li>the class will not be final</li>
82 <li>for null parameters, rather than throwing an Exception, consider performing a Null patterned concept, such as returning 0 or ""</li>
83 </ul>
84
85 <p>A utility class can act as a factory for specific implementations of a class or
86 interface. In such cases the implementations should be non-public, static, inner classes
87 of the utility class. However, if warranted due to maintenance or other reasons, these
88 decorator classes may be moved to top-level classes in a subpackage. The
89 naming of such a subpackage should be discussed and agreed upon on the
90 developers mailing list.</p>
91
92 <p>If different overloaded variants of a method are desired, with the same method signature, it should not be indicated via a boolean argument, but via a more focused method name. Rather than replace(boolean repeat), replace and replaceAll, or replaceOnce and replace. </p>
93
94
95 <a name="Javadoc"></a>
96 <h3>4. JAVADOC</h3>
97
98 <p>The Sun javadoc guidelines are the starting point for Lang. These points are
99 an extension to make it easier for users reading the generated
100 docs and developers with javadoc-popup capabilities from within their IDE.</p>
101
102 <h4>General</h4>
103 <p>References to other objects, interfaces or methods use the @link-tag the
104 first time it is referenced in a class or interface. On the following
105 references always enclose it inside &lt;code&gt;&lt;/code&gt;.</p>
106
107 <p>References to <code>null</code>, <code>this</code>, <code>long</code>,
108 <code>int</code>, <code>short</code>, <code>char</code>, <code>byte</code>,
109 <code>double</code>, <code>float</code> and <code>boolean</code> should be enclosed
110 in &lt;code&gt;&lt;/code&gt;.</p>
111
112 <h4>Classes/Interfaces/Methods</h4>
113 <p>Use a short description of what the class/interface/method is used for,
114 enclose with &lt;p&gt;&lt;/p&gt;.</p>
115
116 <p>A longer description about what the class/interface/method is used for
117 and if it is needed how it is done. If it is necessary include
118 description of the parameters, what they are used for and how. Enclose
119 with &lt;p&gt;&lt;/p&gt; where it is needed, try to divide into smaller parts (not
120 to small!) to enhance readability of the generated Javadoc.</p>
121
122 <p>If an example is needed enclose it with &lt;pre&gt;&lt;/pre&gt;.
123 It should be supported with an explanation within a normal paragraph.</p>
124
125 <h4>Exception throwing</h4>
126 <p>When throwing an exception to indicate a bad argument, always try to throw
127 IllegalArgumentException, even if the argument was null. Do not throw
128 NullPointerException. (Obviously, you should document what the code actually does!)</p>
129
130 <h4>Deprecations</h4>
131 <p>When deprecating a method or class include a clear reference to when the method will be deleted.
132 This should be of the form 'Method will be removed in Commons Lang 3.0.'. </p>
133
134 <h4>Language used in code/comments</h4>
135 <p>It has been decided to casually standardize on US-English.
136 To avoid misplaced jeers of 'americanisation', the people making this decision largely write in non-US-English.
137 However, it's not something to get worked up about. Lots of spelling differences will creep in all over.</p>
138
139 <a name="Building"></a>
140 <h3>5.BUILDING</h3>
141 <h4>Building a Release</h4>
142 <p>
143 The currently targetted version of Java is 1.5.
144 </p>
145 <p>
146 To build Lang:
147 <table>
148 <tr><th></th><th>Tested JAR</th><th>Distribution</th><th>Site</th></tr>
149 <tr><td>Maven 2.x</td><td><code>mvn package</code></td><td>mvn assembly:assembly</td><td>mvn site</td></tr>
150 </table>
151 </p>
152 </section>
153 </body>
154 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <!--
18 +======================================================================+
19 |**** ****|
20 |**** THIS FILE IS GENERATED BY THE COMMONS BUILD PLUGIN ****|
21 |**** DO NOT EDIT DIRECTLY ****|
22 |**** ****|
23 +======================================================================+
24 | TEMPLATE FILE: download-page-template.xml |
25 | commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
26 +======================================================================+
27 | |
28 | 1) Re-generate using: mvn commons:download-page |
29 | |
30 | 2) Set the following properties in the component's pom: |
31 | - commons.componentid (required, alphabetic, lower case) |
32 | - commons.release.version (required) |
33 | - commons.binary.suffix (optional) |
34 | (defaults to "-bin", set to "" for pre-maven2 releases) |
35 | |
36 | 3) Example Properties |
37 | |
38 | <properties> |
39 | <commons.componentid>math</commons.componentid> |
40 | <commons.release.version>1.2</commons.release.version> |
41 | </properties> |
42 | |
43 +======================================================================+
44 -->
45 <document>
46 <properties>
47 <title>Download Commons Lang</title>
48 <author email="dev@commons.apache.org">Commons Documentation Team</author>
49 </properties>
50 <body>
51 <section name="Download Commons Lang">
52 <subsection name="Using a Mirror">
53 <p>
54 We recommend you use a mirror to download our release
55 builds, but you <strong>must</strong> verify the integrity of
56 the downloaded files using signatures downloaded from our main
57 distribution directories. Recent releases (48 hours) may not yet
58 be available from the mirrors.
59 </p>
60
61 <p>
62 You are currently using <b>[preferred]</b>. If you
63 encounter a problem with this mirror, please select another
64 mirror. If all mirrors are failing, there are <i>backup</i>
65 mirrors (at the end of the mirrors list) that should be
66 available.
67 <br></br>
68 [if-any logo]<a href="[link]"><img align="right" src="[logo]" border="0"></img></a>[end]
69 </p>
70
71 <form action="[location]" method="get" id="SelectMirror">
72 <p>
73 Other mirrors:
74 <select name="Preferred">
75 [if-any http]
76 [for http]<option value="[http]">[http]</option>[end]
77 [end]
78 [if-any ftp]
79 [for ftp]<option value="[ftp]">[ftp]</option>[end]
80 [end]
81 [if-any backup]
82 [for backup]<option value="[backup]">[backup] (backup)</option>[end]
83 [end]
84 </select>
85 <input type="submit" value="Change"></input>
86 </p>
87 </form>
88
89 <p>
90 The <a href="http://www.apache.org/dist/commons/KEYS">KEYS</a>
91 link links to the code signing keys used to sign the product.
92 The <code>PGP</code> link downloads the OpenPGP compatible signature from our main site.
93 The <code>MD5</code> link downloads the checksum from the main site.
94 </p>
95 </subsection>
96 </section>
97 <section name="Commons Lang 3.0 (Java 5.0+)">
98 <subsection name="Binaries">
99 <table>
100 <tr>
101 <td><a href="[preferred]/commons/lang/binaries/commons-lang3-3.0-bin.tar.gz">commons-lang3-3.0-bin.tar.gz</a></td>
102 <td><a href="http://www.apache.org/dist/commons/lang/binaries/commons-lang3-3.0-bin.tar.gz.md5">md5</a></td>
103 <td><a href="http://www.apache.org/dist/commons/lang/binaries/commons-lang3-3.0-bin.tar.gz.asc">pgp</a></td>
104 </tr>
105 <tr>
106 <td><a href="[preferred]/commons/lang/binaries/commons-lang3-3.0-bin.zip">commons-lang3-3.0-bin.zip</a></td>
107 <td><a href="http://www.apache.org/dist/commons/lang/binaries/commons-lang3-3.0-bin.zip.md5">md5</a></td>
108 <td><a href="http://www.apache.org/dist/commons/lang/binaries/commons-lang3-3.0-bin.zip.asc">pgp</a></td>
109 </tr>
110 </table>
111 </subsection>
112 <subsection name="Source">
113 <table>
114 <tr>
115 <td><a href="[preferred]/commons/lang/source/commons-lang3-3.0-src.tar.gz">commons-lang3-3.0-src.tar.gz</a></td>
116 <td><a href="http://www.apache.org/dist/commons/lang/source/commons-lang3-3.0-src.tar.gz.md5">md5</a></td>
117 <td><a href="http://www.apache.org/dist/commons/lang/source/commons-lang3-3.0-src.tar.gz.asc">pgp</a></td>
118 </tr>
119 <tr>
120 <td><a href="[preferred]/commons/lang/source/commons-lang3-3.0-src.zip">commons-lang3-3.0-src.zip</a></td>
121 <td><a href="http://www.apache.org/dist/commons/lang/source/commons-lang3-3.0-src.zip.md5">md5</a></td>
122 <td><a href="http://www.apache.org/dist/commons/lang/source/commons-lang3-3.0-src.zip.asc">pgp</a></td>
123 </tr>
124 </table>
125 </subsection>
126 </section>
127 <section name="Commons Lang 2.6 (Java 1.3+)">
128 <subsection name="Binaries">
129 <table>
130 <tr>
131 <td><a href="[preferred]/commons/lang/binaries/commons-lang3-2.6-bin.tar.gz">commons-lang3-2.6-bin.tar.gz</a></td>
132 <td><a href="http://www.apache.org/dist/commons/lang/binaries/commons-lang3-2.6-bin.tar.gz.md5">md5</a></td>
133 <td><a href="http://www.apache.org/dist/commons/lang/binaries/commons-lang3-2.6-bin.tar.gz.asc">pgp</a></td>
134 </tr>
135 <tr>
136 <td><a href="[preferred]/commons/lang/binaries/commons-lang3-2.6-bin.zip">commons-lang3-2.6-bin.zip</a></td>
137 <td><a href="http://www.apache.org/dist/commons/lang/binaries/commons-lang3-2.6-bin.zip.md5">md5</a></td>
138 <td><a href="http://www.apache.org/dist/commons/lang/binaries/commons-lang3-2.6-bin.zip.asc">pgp</a></td>
139 </tr>
140 </table>
141 </subsection>
142 <subsection name="Source">
143 <table>
144 <tr>
145 <td><a href="[preferred]/commons/lang/source/commons-lang3-2.6-src.tar.gz">commons-lang3-2.6-src.tar.gz</a></td>
146 <td><a href="http://www.apache.org/dist/commons/lang/source/commons-lang3-2.6-src.tar.gz.md5">md5</a></td>
147 <td><a href="http://www.apache.org/dist/commons/lang/source/commons-lang3-2.6-src.tar.gz.asc">pgp</a></td>
148 </tr>
149 <tr>
150 <td><a href="[preferred]/commons/lang/source/commons-lang3-2.6-src.zip">commons-lang3-2.6-src.zip</a></td>
151 <td><a href="http://www.apache.org/dist/commons/lang/source/commons-lang3-2.6-src.zip.md5">md5</a></td>
152 <td><a href="http://www.apache.org/dist/commons/lang/source/commons-lang3-2.6-src.zip.asc">pgp</a></td>
153 </tr>
154 </table>
155 </subsection>
156 </section>
157 <section name="Archives">
158 <p>
159 Older releases can be obtained from the archives.
160 </p>
161 <ul>
162 <li class="download"><a href="[preferred]/commons/lang/">browse download area</a></li>
163 <li><a href="http://archive.apache.org/dist/commons/lang/">archives...</a></li>
164 </ul>
165 </section>
166 </body>
167 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>Home</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23 <!-- ================================================== -->
24 <section name="Commons Lang">
25
26 <p>
27 The standard Java libraries fail to provide enough methods for
28 manipulation of its core classes. Apache Commons Lang provides
29 these extra methods.
30 </p>
31
32 <p>
33 Lang provides a host of helper utilities for the java.lang API, notably
34 String manipulation methods, basic numerical methods, object reflection, concurrency, creation and serialization
35 and System properties. Additionally it contains basic enhancements to java.util.Date and a series of utilities dedicated to help with
36 building methods, such as hashCode, toString and equals.
37 </p>
38 <p>
39 Note that Lang 3.0 uses a different package (<i>org.apache.commons.lang3</i>) than its predecessors (<i>org.apache.commons.lang</i>), allowing it to be used at the same time as an earlier version.
40 </p>
41 </section>
42 <!-- ================================================== -->
43 <section name="Documentation">
44 <p>
45 A getting started <a href="userguide.html">user guide</a> is available
46 together with various <a href="project-reports.html">project reports</a>.
47 </p>
48 <p>
49 The JavaDoc API documents are available online:
50 </p>
51 <ul>
52 <li>The <a href="api-3.0/index.html">current stable release 3.0</a></li>
53 <li>The <a href="api-2.6/index.html">legacy release 2.6</a></li>
54 <li>The <a href="api-2.5/index.html">previous version 2.5</a></li>
55 <li>Older releases - see the <a href="release-history.html">Release History</a> page</li>
56 </ul>
57 <p>
58 The <a href="source-repository.html">subversion repository</a> can be
59 <a href="http://svn.apache.org/viewvc/commons/proper/lang/trunk/">browsed</a>.
60 </p>
61 </section>
62 <!-- ================================================== -->
63 <section name="Releases">
64 <p>
65 A latest stable and Java 5.0 dependent version is available:
66 (<a href="http://commons.apache.org/lang/download_lang.cgi">download 3.0</a>)
67 (<a href="upgradeto3_0.html">changelog</a>) (<a href="article3_0.html">upgrade notes</a>)
68 (<a href="lang2-lang3-clirr-report.html">Lang2 to Lang3 Clirr report</a>). </p>
69
70 <p>
71 The legacy JDK 1.3 compatible version is also available:
72 (<a href="http://commons.apache.org/lang/download_lang.cgi">download 2.6</a>)
73 (<a href="upgradeto2_6.html">release notes</a>). </p>
74
75 <p>
76 For information on previous releases, see the <a href="release-history.html">Release History</a> and to download previous releases, see the <a href="http://archive.apache.org/dist/commons/lang/">Apache Archive</a>.
77 </p>
78 </section>
79 <!-- ================================================== -->
80 <section name="Support">
81 <p>
82 The <a href="mail-lists.html">commons mailing lists</a> act as the main support forum.
83 The user list is suitable for most library usage queries.
84 The dev list is intended for the development discussion.
85 Please remember that the lists are shared between all commons components,
86 so prefix your email by [lang].
87 </p>
88 <p>
89 Issues may be reported via <a href="issue-tracking.html">ASF JIRA</a>.
90 Please read the instructions carefully to submit a useful bug report or enhancement request.
91 </p>
92 </section>
93 <!-- ================================================== -->
94 </body>
95 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <!--
18 +======================================================================+
19 |**** ****|
20 |**** THIS FILE IS GENERATED BY THE COMMONS BUILD PLUGIN ****|
21 |**** DO NOT EDIT DIRECTLY ****|
22 |**** ****|
23 +======================================================================+
24 | TEMPLATE FILE: issue-tracking-template.xml |
25 | commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
26 +======================================================================+
27 | |
28 | 1) Re-generate using: mvn commons:jira-page |
29 | |
30 | 2) Set the following properties in the component's pom: |
31 | - commons.jira.id (required, alphabetic, upper case) |
32 | - commons.jira.pid (required, numeric) |
33 | |
34 | 3) Example Properties |
35 | |
36 | <properties> |
37 | <commons.jira.id>MATH</commons.jira.id> |
38 | <commons.jira.pid>12310485</commons.jira.pid> |
39 | </properties> |
40 | |
41 +======================================================================+
42 -->
43 <document>
44 <properties>
45 <title>Commons Lang Issue tracking</title>
46 <author email="dev@commons.apache.org">Commons Documentation Team</author>
47 </properties>
48 <body>
49
50 <section name="Commons Lang Issue tracking">
51 <p>
52 Commons Lang uses <a href="http://issues.apache.org/jira/">ASF JIRA</a> for tracking issues.
53 See the <a href="http://issues.apache.org/jira/browse/LANG">Commons Lang JIRA project page</a>.
54 </p>
55
56 <p>
57 To use JIRA you may need to <a href="http://issues.apache.org/jira/secure/Signup!default.jspa">create an account</a>
58 (if you have previously created/updated Commons issues using Bugzilla an account will have been automatically
59 created and you can use the <a href="http://issues.apache.org/jira/secure/ForgotPassword!default.jspa">Forgot Password</a>
60 page to get a new password).
61 </p>
62
63 <p>
64 If you would like to report a bug, or raise an enhancement request with
65 Commons Lang please do the following:
66 <ol>
67 <li><a href="http://issues.apache.org/jira/secure/IssueNavigator.jspa?reset=true&amp;pid=12310481&amp;sorter/field=issuekey&amp;sorter/order=DESC&amp;status=1&amp;status=3&amp;status=4">Search existing open bugs</a>.
68 If you find your issue listed then please add a comment with your details.</li>
69 <li><a href="mail-lists.html">Search the mailing list archive(s)</a>.
70 You may find your issue or idea has already been discussed.</li>
71 <li>Decide if your issue is a bug or an enhancement.</li>
72 <li>Submit either a <a href="http://issues.apache.org/jira/secure/CreateIssueDetails!init.jspa?pid=12310481&amp;issuetype=1&amp;priority=4&amp;assignee=-1">bug report</a>
73 or <a href="http://issues.apache.org/jira/secure/CreateIssueDetails!init.jspa?pid=12310481&amp;issuetype=4&amp;priority=4&amp;assignee=-1">enhancement request</a>.</li>
74 </ol>
75 </p>
76
77 <p>
78 Please also remember these points:
79 <ul>
80 <li>the more information you provide, the better we can help you</li>
81 <li>test cases are vital, particularly for any proposed enhancements</li>
82 <li>the developers of Commons Lang are all unpaid volunteers</li>
83 </ul>
84 </p>
85
86 <p>
87 For more information on subversion and creating patches see the
88 <a href="http://www.apache.org/dev/contributors.html">Apache Contributors Guide</a>.
89 </p>
90
91 <p>
92 You may also find these links useful:
93 <ul>
94 <li><a href="http://issues.apache.org/jira/secure/IssueNavigator.jspa?reset=true&amp;pid=12310481&amp;sorter/field=issuekey&amp;sorter/order=DESC&amp;status=1&amp;status=3&amp;status=4">All Open Commons Lang bugs</a></li>
95 <li><a href="http://issues.apache.org/jira/secure/IssueNavigator.jspa?reset=true&amp;pid=12310481&amp;sorter/field=issuekey&amp;sorter/order=DESC&amp;status=5&amp;status=6">All Resolved Commons Lang bugs</a></li>
96 <li><a href="http://issues.apache.org/jira/secure/IssueNavigator.jspa?reset=true&amp;pid=12310481&amp;sorter/field=issuekey&amp;sorter/order=DESC">All Commons Lang bugs</a></li>
97 </ul>
98 </p>
99 </section>
100 </body>
101 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <!--
18 +======================================================================+
19 |**** ****|
20 |**** THIS FILE IS GENERATED BY THE COMMONS BUILD PLUGIN ****|
21 |**** DO NOT EDIT DIRECTLY ****|
22 |**** ****|
23 +======================================================================+
24 | TEMPLATE FILE: mail-lists-template.xml |
25 | commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
26 +======================================================================+
27 | |
28 | 1) Re-generate using: mvn commons:mail-page |
29 | |
30 | 2) Set the following properties in the component's pom: |
31 | - commons.componentid (required, alphabetic, lower case) |
32 | |
33 | 3) Example Properties |
34 | |
35 | <properties> |
36 | <commons.componentid>math</commons.componentid> |
37 | </properties> |
38 | |
39 +======================================================================+
40 -->
41 <document>
42 <properties>
43 <title>Commons Lang Mailing Lists</title>
44 <author email="dev@commons.apache.org">Commons Documentation Team</author>
45 </properties>
46 <body>
47
48 <section name="Overview">
49 <p>
50 <a href="index.html">Commons Lang</a> shares mailing lists with all the other
51 <a href="http://commons.apache.org/components.html">Commons Components</a>.
52 To make it easier for people to only read messages related to components they are interested in,
53 the convention in Commons is to prefix the subject line of messages with the component's name,
54 for example:
55 <ul>
56 <li>[lang] Problem with the ...</li>
57 </ul>
58 </p>
59 <p>
60 Questions related to the usage of Commons Lang should be posted to the
61 <a href="http://mail-archives.apache.org/mod_mbox/commons-user/">User List</a>.
62 <br />
63 The <a href="http://mail-archives.apache.org/mod_mbox/commons-dev/">Developer List</a>
64 is for questions and discussion related to the development of Commons Lang.
65 <br />
66 Please do not cross-post; developers are also subscribed to the user list.
67 </p>
68 <p>
69 <strong>Note:</strong> please don't send patches or attachments to any of the mailing lists.
70 Patches are best handled via the <a href="issue-tracking.html">Issue Tracking</a> system.
71 Otherwise, please upload the file to a public server and include the URL in the mail.
72 </p>
73 </section>
74
75 <section name="Commons Lang Mailing Lists">
76 <p>
77 <strong>Please prefix the subject line of any messages for <a href="index.html">Commons Lang</a>
78 with <i>[lang]</i></strong> - <i>thanks!</i>
79 <br />
80 <br />
81 </p>
82
83 <table>
84 <tr>
85 <th>Name</th>
86 <th>Subscribe</th>
87 <th>Unsubscribe</th>
88 <th>Post</th>
89 <th>Archive</th>
90 <th>Other Archives</th>
91 </tr>
92
93
94 <tr>
95 <td>
96 <strong>Commons User List</strong>
97 <br /><br />
98 Questions on using Commons Lang.
99 <br /><br />
100 </td>
101 <td><a href="mailto:user-subscribe@commons.apache.org">Subscribe</a></td>
102 <td><a href="mailto:user-unsubscribe@commons.apache.org">Unsubscribe</a></td>
103 <td><a href="mailto:user@commons.apache.org?subject=[lang]">Post</a></td>
104 <td><a href="http://mail-archives.apache.org/mod_mbox/commons-user/">mail-archives.apache.org</a></td>
105 <td><a href="http://markmail.org/list/org.apache.commons.users/">markmail.org</a><br />
106 <a href="http://www.mail-archive.com/user@commons.apache.org/">www.mail-archive.com</a><br />
107 <a href="http://news.gmane.org/gmane.comp.jakarta.commons.devel">news.gmane.org</a>
108 </td>
109 </tr>
110
111
112 <tr>
113 <td>
114 <strong>Commons Developer List</strong>
115 <br /><br />
116 Discussion of development of Commons Lang.
117 <br /><br />
118 </td>
119 <td><a href="mailto:dev-subscribe@commons.apache.org">Subscribe</a></td>
120 <td><a href="mailto:dev-unsubscribe@commons.apache.org">Unsubscribe</a></td>
121 <td><a href="mailto:dev@commons.apache.org?subject=[lang]">Post</a></td>
122 <td><a href="http://mail-archives.apache.org/mod_mbox/commons-dev/">mail-archives.apache.org</a></td>
123 <td><a href="http://markmail.org/list/org.apache.commons.dev/">markmail.org</a><br />
124 <a href="http://www.mail-archive.com/dev@commons.apache.org/">www.mail-archive.com</a><br />
125 <a href="http://news.gmane.org/gmane.comp.jakarta.commons.devel">news.gmane.org</a>
126 </td>
127 </tr>
128
129
130 <tr>
131 <td>
132 <strong>Commons Issues List</strong>
133 <br /><br />
134 Only for e-mails automatically generated by the <a href="issue-tracking.html">issue tracking</a> system.
135 <br /><br />
136 </td>
137 <td><a href="mailto:issues-subscribe@commons.apache.org">Subscribe</a></td>
138 <td><a href="mailto:issues-unsubscribe@commons.apache.org">Unsubscribe</a></td>
139 <td><i>read only</i></td>
140 <td><a href="http://mail-archives.apache.org/mod_mbox/commons-issues/">mail-archives.apache.org</a></td>
141 <td><a href="http://markmail.org/list/org.apache.commons.issues/">markmail.org</a><br />
142 <a href="http://www.mail-archive.com/issues@commons.apache.org/">www.mail-archive.com</a>
143 </td>
144 </tr>
145
146
147 <tr>
148 <td>
149 <strong>Commons Commits List</strong>
150 <br /><br />
151 Only for e-mails automatically generated by the <a href="source-repository.html">source control</a> sytem.
152 <br /><br />
153 </td>
154 <td><a href="mailto:commits-subscribe@commons.apache.org">Subscribe</a></td>
155 <td><a href="mailto:commits-unsubscribe@commons.apache.org">Unsubscribe</a></td>
156 <td><i>read only</i></td>
157 <td><a href="http://mail-archives.apache.org/mod_mbox/commons-commits/">mail-archives.apache.org</a></td>
158 <td><a href="http://markmail.org/list/org.apache.commons.commits/">markmail.org</a><br />
159 <a href="http://www.mail-archive.com/commits@commons.apache.org/">www.mail-archive.com</a>
160 </td>
161 </tr>
162
163 </table>
164
165 </section>
166 <section name="Apache Mailing Lists">
167 <p>
168 Other mailing lists which you may find useful include:
169 </p>
170
171 <table>
172 <tr>
173 <th>Name</th>
174 <th>Subscribe</th>
175 <th>Unsubscribe</th>
176 <th>Post</th>
177 <th>Archive</th>
178 <th>Other Archives</th>
179 </tr>
180 <tr>
181 <td>
182 <strong>Apache Announce List</strong>
183 <br /><br />
184 General announcements of Apache project releases.
185 <br /><br />
186 </td>
187 <td><a class="externalLink" href="mailto:announce-subscribe@apache.org">Subscribe</a></td>
188 <td><a class="externalLink" href="mailto:announce-unsubscribe@apache.org">Unsubscribe</a></td>
189 <td><i>read only</i></td>
190 <td><a class="externalLink" href="http://mail-archives.apache.org/mod_mbox/www-announce/">mail-archives.apache.org</a></td>
191 <td><a class="externalLink" href="http://markmail.org/list/org.apache.announce/">markmail.org</a><br />
192 <a class="externalLink" href="http://old.nabble.com/Apache-News-and-Announce-f109.html">old.nabble.com</a><br />
193 <a class="externalLink" href="http://www.mail-archive.com/announce@apache.org/">www.mail-archive.com</a><br />
194 <a class="externalLink" href="http://news.gmane.org/gmane.comp.apache.announce">news.gmane.org</a>
195 </td>
196 </tr>
197 </table>
198
199 </section>
200 </body>
201 </document>
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 -->
16 <document>
17 <properties>
18 <title>Proposal for Lang Package</title>
19 </properties>
20 <body>
21
22
23 <section name="Proposal for Lang Package">
24
25
26
27 <subsection name="(0) Rationale">
28
29 <p>The standard Java libraries fail to provide enough methods for
30 manipulation of its main components. The <em>Lang</em> Package provides
31 these extra methods. There are other classes which might justifiably
32 be included in java.lang someday, this package also provides for them.</p>
33
34
35 </subsection>
36 <subsection name="(1) Scope of the Package">
37
38 <p>This proposal is to create a package of Java utility classes for the
39 classes that are in java.lang's hierarchy, or are considered to be so
40 standard as to justify existence in java.lang. The <em>Lang</em> Package
41 also applies to primitives and arrays.</p>
42
43
44 </subsection>
45 <subsection name="(1.5) Interaction With Other Packages">
46
47 <p><em>Lang</em> relies only on standard JDK 1.2 (or later) APIs for
48 production deployment. It utilizes the JUnit unit testing framework for
49 developing and executing unit tests, but this is of interest only to
50 developers of the component. Lang will be a dependency for
51 several existing components in the open source world.</p>
52
53 <p>No external configuration files are utilized.</p>
54
55
56 </subsection>
57 <subsection name="(2) Initial Source of the Package">
58
59 <p>The initial classes came from the Commons.Util subproject.</p>
60
61 <p>The proposed package name for the new component is
62 <code>org.apache.commons.lang</code>.</p>
63
64
65 </subsection>
66 <subsection name="(3) Required Jakarta-Commons Resources">
67
68 <ul>
69 <li>CVS Repository - New directory <code>lang</code> in the
70 <code>jakarta-commons</code> CVS repository.</li>
71 <li>Mailing List - Discussions will take place on the general
72 <em>dev@commons.apache.org</em> mailing list. To help
73 list subscribers identify messages of interest, it is suggested that
74 the message subject of messages about this component be prefixed with
75 [lang].</li>
76 <li>Bugzilla - New component "Lang" under the "Commons" product
77 category, with appropriate version identifiers as needed.</li>
78 <li>Jyve FAQ - New category "commons-lang" (when available).</li>
79 </ul>
80
81
82 </subsection>
83 <subsection name="(4) Initial Committers">
84
85 <p>The initial committers on the Lang component shall be as follows:
86 <ul>
87 <li>Henri Yandell (bayard)</li>
88 <li>Daniel Rall (dlr)</li>
89 <li>Stephen Colebourne (scolebourne)</li>
90 </ul>
91 </p>
92
93 </subsection>
94 </section>
95 </body>
96 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>Home</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23 <!-- ================================================== -->
24 <section name="Commons Lang Release History">
25
26 <!-- TODO: Add the Java version for each release -->
27
28 <table>
29 <tr><th>Version</th><th>Release date</th><th>Javadoc</th><th>Release notes</th></tr>
30 <tr><td>3.0</td><td>18/Jul/11</td><td><a href="api-3.0/">api-3.0</a></td><td><a href="upgradeto3_0.html">release notes for 3.0</a></td></tr>
31 <tr><td>2.6</td><td>16/Jan/11</td><td><a href="api-2.6/">api-2.6</a></td><td><a href="upgradeto2_6.html">release notes for 2.6</a></td></tr>
32 <tr><td>2.5</td><td>23/Feb/10</td><td><a href="api-2.5/">api-2.5</a></td><td><a href="upgradeto2_5.html">release notes for 2.5</a></td></tr>
33 <tr><td>2.4</td><td>18/Mar/08</td><td><a href="api-2.4/">api-2.4</a></td><td><a href="upgradeto2_4.html">release notes for 2.4</a></td></tr>
34 <tr><td>2.3</td><td>13/Feb/07</td><td><a href="api-2.3/">api-2.3</a></td><td><a href="upgradeto2_3.html">release notes for 2.3</a></td></tr>
35 <tr><td>2.2</td><td>04/Oct/06</td><td><a href="api-2.2/">api-2.2</a></td><td><a href="upgradeto2_2.html">release notes for 2.2</a></td></tr>
36 <tr><td>2.1</td><td>13/Jun/06</td><td><a href="api-2.1/">api-2.1</a></td><td><a href="upgradeto2_1.html">release notes for 2.1</a></td></tr>
37 <tr><td>2.0</td><td>02/Sep/03</td><td><a href="api-2.0/">api-2.0</a></td><td><a href="upgradeto2_0.html">release notes for 2.0</a></td></tr>
38 <tr><td>1.0.1</td><td>25/Nov/02</td><td><a href="api-1.0.1/">api-1.0.1</a></td><td><a href="http://archive.apache.org/dist/commons/lang/old/v1.0.1/RELEASE-NOTES.txt">release notes for 1.0.1</a></td></tr>
39 <tr><td>1.0</td><td>04/Oct/02</td><td><a href="api-1.0/">api-1.0</a></td><td><a href="http://archive.apache.org/dist/commons/lang/old/v1.0/RELEASE-NOTES.txt">release notes for 1.0</a></td></tr>
40 </table>
41
42 </section>
43 <!-- ================================================== -->
44 </body>
45 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>2.0 Release Notes</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="Lang 2.0 Release Notes">
25 <p>
26 These are the release notes and advice for upgrading Commons-Lang from
27 version 1.0 to version 2.0.
28 <source>
29 INTRODUCTION:
30
31 This document contains the release notes for this version of the Commons
32 Lang package. Commons Lang is a set of utility functions and reusable
33 components that should be a help in any Java environment.
34
35 This release has involved a major clean and tidy exercise.
36 Javadoc and Tests are now much more thorough.
37 All methods should now be much clearer in what they do in unusual cases.
38
39
40 INCOMPATIBLE CHANGES:
41 Some StringUtils methods have changed functionality from 1.0:
42 isEmpty()
43 chomp(String)
44 chomp(String,String)
45 swapCase(String)
46 Numerous other methods have changed null handling to accept nulls gracefully.
47 As with all major version releases, check your code for incompatibilities.
48
49
50 NEW FEATURES:
51
52 Since the release of the 1.0 package the following classes have been added:
53
54 lang package:
55 ArrayUtils
56 BitField
57 BooleanUtils
58 CharRange (previously package scoped)
59 ClassUtils
60 StringEscapeUtils
61 WordUtils
62 IllegalClassException
63 IncompleteArgumentException
64 NotImplementedException
65 NullArgumentException
66 SerializationException
67 UnhandledException
68 Validate
69
70
71 math sub-package:
72 IntRange
73 LongRange
74 Range
75 DoubleRange
76 JVMRandom
77 NumberRange
78 FloatRange
79 NumberUtils
80 Fraction
81 RandomUtils
82
83 time sub-package:
84 DateFormatUtils
85 FastDateFormat
86 DateUtils
87 StopWatch
88
89 Since the release of the 1.0 package the following classes have been changed:
90
91 lang:
92 CharSet:
93 Added factory method, equals and hashCode().
94 Better defined and tested the set syntax.
95 CharSetUtils:
96 added keep method: keep any characters specified in the CharSet string
97 RandomStringUtils:
98 random method: overloaded to allow passing in of a Random class
99 SerializationUtils:
100 added empty constructor
101 StringUtils:
102 isEmpty() changed to not trim
103 chomp() changed to be more like Perl.
104 swapCase() no longer word based, but no difference if you pass in ASCII
105 Various methods changed in the handling of null (less exceptions).
106 Many new methods.
107 Various methods deprecated.
108 SystemUtils:
109 isJavaVersionAtLeast(int) added. getJavaVersion() deprecated.
110 host of new constants.
111
112 enum:
113 Enum:
114 getEnumClass(Class) added
115 EnumUtils:
116 Removed irrelevant Comparable/Serializable interfaces.
117
118 exception:
119 NestableDelegate:
120 Gained many new methods for dissecting an Exception.
121 ExceptionUtils:
122 Gained many new methods to improve handling of nested stack traces.
123
124 builder:
125 ReflectionToStringBuilder:
126 Handy class added for creating default toStrings.
127 All other builder classes received a set of new methods.
128
129
130 BUG FIXES:
131
132 ID Sev Pri Plt Owner State Result Summary
133 13367 [PATCH] StringUtil enhancement
134 13391 Javadoc nit
135 13771 Additional Lang Method Suggestions
136 14306 NullPointerException in CompareToBuilder
137 14357 static option for reversing the stacktrace
138 14447 ToStringBuilder doesn't work well in subclasses
139 14883 StringUtils.countMatches loops forever if substring empty
140 14884 NumberRange inaccurate for Long, etc.
141 14985 More flexibility for getRootCause in ExceptionUtils
142 15154 SystemUtils.IS_JAVA_1_5 Javadoc is wrong
143 15257 Hierarchy support in ToStringBuilder.reflectionToString()
144 15438 ArrayUtils.contains()
145 15439 Enum does not support inner sub-classes
146 15986 Infinite loop in ToStringBuilder.reflectionToString for inne
147 16076 Example in Javadoc for ToStringBuilder wrong for append.
148 16193 Hierarchy support in EqualsBuilder.reflectionEquals()
149 16202 typo in the javadoc example code
150 16204 Infinite loop in StringUtils.replace(text, repl, with) + FIX
151 16227 Added class hierachy support to CompareToBuilder.reflectionC
152 16228 Added class hierachy support to HashCodeBuilder.reflectionHa
153 16284 MethodUtils: Removed unused code/unused local vars.
154 16341 No Javadoc for NestableDelegate
155 16622 Removed compile warning in FastDateFormat
156 16669 JavaDoc Errata
157 16676 StackOverflow due to ToStringBuilder
158 16689 ExceptionUtils new methods.
159 16690 Specify initial size for Enum's HashMap.
160 16787 Removed compile warning in ObjectUtils
161 17250 [Lang] Should ToStringBuilder.reflectionToString handle arra
162 17654 EnumUtils nit: The import java.io.Serializable is never used
163 17882 Add join(..., char c) to StringUtils (and some performance f
164 18077 StringUtils.chomp does not match Perl
165 18723 RandomStringUtils infloops with length &lt; 1
166 18836 test.lang fails if compiled with non iso-8859-1 locales
167 18948 Resurrect the WordWrapUtils from commons-sandbox/utils
168 19296 [Lang] What to do with FastDateFormat unused private constru
169 19364 [Lang] time unit tests fail on Sundays
170 19756 [lang] java.lang.ExceptionInInitializerError thrown by JVMRa
171 19880 [lang] patch and test case fixing problem with RandomStringU
172 20165 [LANG] SystemUtils does not play nice in an Applet
173 20538 [lang] NumberUtils.isNumber allows illegal trailing characte
174 20592 [lang] RandomStringUtils.randomAlpha methods omit 'z'
175 20603 [lang] Make NestableDelegate methods public instead of packa
176 20632 Refactored reflection feature of ToStringBuilder into new Re
177 20652 StringUtils.chopNewLine - StringIndexOutOfBoundsException
178 21021 [PATCH] reduce object creation in ToStringBuilder
179 21068 [lang] [PATCH] NumberUtils min/max, BooleanUtils.xor, and Ar
180 21099 [lang][PATCH] Unused field 'startFinal' in DateIterator
181 21715 The javadoc says "Mac" instead of "OS/2"
182 21734 [PATCH] all NumberUtils.createXXX(String) methods handle null
183 21750 [lang] StringUtils javadoc and test enhancements
184 21758 [lang] lang.builder classes javadoc edits (mostly typo fixes)
185 21797 [lang] Add javadoc examples and tests for StringUtils
186 21809 [lang] maven-beta10 checkstyle problem
187 21904 NumberUtils.createBigDecimal("") NPE in Sun 1.3.1_08
188 21952 [lang] Improved tests, javadoc for CharSetUtils, StringEscapeUtils
189 22091 Adding tolerance to double[] search methods in ArrayUtils
190 22094 A small, but important javadoc fix for Fraction proper whole/numerator
191 22095 [lang] Javadoc, tests improvements for CharSet, CharSetUtils
192 22098 [lang] Improve util.Validate tests
193 22245 [lang] test.time fails in Japanese (non-us) locale.
194 22286 [lang] Missing @since tags
195 22367 Typo in documentation
196 22386 [lang] Improve javadoc and overflow behavior of Fraction
197
198
199 DEPRECATIONS:
200
201 lang:
202 NumberRange:
203 now deprecated, see math subpackage
204 NumberUtils:
205 now deprecated, see math subpackage
206
207
208 CHANGES: [In 'diff' format]
209
210 Jar changes
211 ===========
212 &gt; org.apache.commons.lang.math.Range
213 &gt; org.apache.commons.lang.math.FloatRange
214 &gt; org.apache.commons.lang.math.NumberUtils
215 &gt; org.apache.commons.lang.math.JVMRandom
216 &gt; org.apache.commons.lang.math.IntRange
217 &gt; org.apache.commons.lang.math.LongRange
218 &gt; org.apache.commons.lang.math.DoubleRange
219 &gt; org.apache.commons.lang.math.NumberRange
220 &gt; org.apache.commons.lang.math.Fraction
221 &gt; org.apache.commons.lang.math.RandomUtils
222 &gt; org.apache.commons.lang.time.FastDateFormat
223 &gt; org.apache.commons.lang.time.DateUtils$DateIterator
224 &gt; org.apache.commons.lang.time.DateUtils
225 &gt; org.apache.commons.lang.time.FastDateFormat$UnpaddedMonthField
226 &gt; org.apache.commons.lang.time.FastDateFormat$StringLiteral
227 &gt; org.apache.commons.lang.time.FastDateFormat$TwelveHourField
228 &gt; org.apache.commons.lang.time.FastDateFormat$NumberRule
229 &gt; org.apache.commons.lang.time.FastDateFormat$CharacterLiteral
230 &gt; org.apache.commons.lang.time.FastDateFormat$TimeZoneNumberRule
231 &gt; org.apache.commons.lang.time.FastDateFormat$TimeZoneNameRule
232 &gt; org.apache.commons.lang.time.DateFormatUtils
233 &gt; org.apache.commons.lang.time.FastDateFormat$TwoDigitMonthField
234 &gt; org.apache.commons.lang.time.DurationFormatUtils
235 &gt; org.apache.commons.lang.time.FastDateFormat$TimeZoneDisplayKey
236 &gt; org.apache.commons.lang.time.FastDateFormat$UnpaddedNumberField
237 &gt; org.apache.commons.lang.time.FastDateFormat$PaddedNumberField
238 &gt; org.apache.commons.lang.time.StopWatch
239 &gt; org.apache.commons.lang.time.FastDateFormat$TwentyFourHourField
240 &gt; org.apache.commons.lang.time.FastDateFormat$Rule
241 &gt; org.apache.commons.lang.time.FastDateFormat$TwoDigitNumberField
242 &gt; org.apache.commons.lang.time.FastDateFormat$TextField
243 &gt; org.apache.commons.lang.time.FastDateFormat$Pair
244 &gt; org.apache.commons.lang.time.FastDateFormat$TwoDigitYearField
245 &gt; org.apache.commons.lang.util.IdentifierUtils$StringNumericIdentifierFactory
246 &gt; org.apache.commons.lang.util.IdentifierUtils$StringSessionIdentifierFactory
247 &gt; org.apache.commons.lang.util.IdentifierUtils$LongNumericIdentifierFactory
248 &gt; org.apache.commons.lang.util.IdentifierUtils$StringAlphanumericIdentifierFactory
249 &gt; org.apache.commons.lang.util.Validate
250 &gt; org.apache.commons.lang.util.LongIdentifierFactory
251 &gt; org.apache.commons.lang.util.IdentifierUtils$1
252 &gt; org.apache.commons.lang.util.StringIdentifierFactory
253 &gt; org.apache.commons.lang.util.IdentifierUtils
254 &gt; org.apache.commons.lang.util.IdentifierFactory
255 &gt; org.apache.commons.lang.util.BitField
256 &gt; org.apache.commons.lang.Entities
257 &gt; org.apache.commons.lang.Entities$LookupEntityMap
258 &gt; org.apache.commons.lang.NotImplementedException
259 &gt; org.apache.commons.lang.NullArgumentException
260 &lt; org.apache.commons.lang.ObjectUtils$1
261 ---
262 &gt; org.apache.commons.lang.StringPrintWriter
263 &gt; org.apache.commons.lang.UnhandledException
264 &gt; org.apache.commons.lang.Entities$HashEntityMap
265 &gt; org.apache.commons.lang.Entities$ArrayEntityMap
266 &gt; org.apache.commons.lang.Entities$EntityMap
267 &gt; org.apache.commons.lang.IntHashMap
268 &gt; org.apache.commons.lang.BooleanUtils
269 &gt; org.apache.commons.lang.IncompleteArgumentException
270 &gt; org.apache.commons.lang.Entities$PrimitiveEntityMap
271 &gt; org.apache.commons.lang.Entities$TreeEntityMap
272 &gt; org.apache.commons.lang.WordUtils
273 &gt; org.apache.commons.lang.StringEscapeUtils
274 &gt; org.apache.commons.lang.ArrayUtils
275 &gt; org.apache.commons.lang.Entities$BinaryEntityMap
276 &gt; org.apache.commons.lang.ClassUtils
277 &gt; org.apache.commons.lang.IntHashMap$Entry
278 &gt; org.apache.commons.lang.IllegalClassException
279 &gt; org.apache.commons.lang.builder.ReflectionToStringBuilder$1
280 &gt; org.apache.commons.lang.builder.ReflectionToStringBuilder
281 &gt; org.apache.commons.lang.Entities$MapIntMap
282
283
284 Class changes
285 =============
286 org.apache.commons.lang.enum.EnumUtils
287 --------------------
288 &lt; public abstract class org.apache.commons.lang.enum.EnumUtils extends java.lang.Object implements java.lang.Comparable, java.io.Serializable {
289 ---
290 &gt; public class org.apache.commons.lang.enum.EnumUtils extends java.lang.Object {
291 &gt; public org.apache.commons.lang.enum.EnumUtils();
292
293 org.apache.commons.lang.enum.Enum$Entry
294 --------------------
295 &gt; final java.util.Map unmodifiableMap;
296 &gt; final java.util.List unmodifiableList;
297
298 org.apache.commons.lang.enum.Enum
299 --------------------
300 &gt; protected transient java.lang.String iToString;
301 &gt; static java.lang.Class class$org$apache$commons$lang$enum$ValuedEnum;
302 &gt; public java.lang.Class getEnumClass();
303
304 org.apache.commons.lang.enum.ValuedEnum
305 --------------------
306 &gt; static {};
307
308 org.apache.commons.lang.StringUtils
309 --------------------
310 &gt; public static final java.lang.String EMPTY;
311 &gt; public static boolean isEmpty(java.lang.String);
312 &gt; public static boolean isNotEmpty(java.lang.String);
313 &gt; public static boolean isBlank(java.lang.String);
314 &gt; public static boolean isNotBlank(java.lang.String);
315 &lt; public static java.lang.String deleteSpaces(java.lang.String);
316 &lt; public static java.lang.String deleteWhitespace(java.lang.String);
317 &lt; public static boolean isNotEmpty(java.lang.String);
318 &lt; public static boolean isEmpty(java.lang.String);
319 ---
320 &gt; public static java.lang.String trimToNull(java.lang.String);
321 &gt; public static java.lang.String trimToEmpty(java.lang.String);
322 &gt; public static java.lang.String strip(java.lang.String);
323 &gt; public static java.lang.String stripToNull(java.lang.String);
324 &gt; public static java.lang.String stripToEmpty(java.lang.String);
325 &gt; public static java.lang.String strip(java.lang.String, java.lang.String);
326 &gt; public static java.lang.String stripStart(java.lang.String, java.lang.String);
327 &gt; public static java.lang.String stripEnd(java.lang.String, java.lang.String);
328 &gt; public static java.lang.String stripAll(java.lang.String[])[];
329 &gt; public static java.lang.String stripAll(java.lang.String[], java.lang.String)[];
330 &gt; public static int indexOf(java.lang.String, char);
331 &gt; public static int indexOf(java.lang.String, char, int);
332 &gt; public static int indexOf(java.lang.String, java.lang.String);
333 &gt; public static int indexOf(java.lang.String, java.lang.String, int);
334 &gt; public static int lastIndexOf(java.lang.String, char);
335 &gt; public static int lastIndexOf(java.lang.String, char, int);
336 &gt; public static int lastIndexOf(java.lang.String, java.lang.String);
337 &gt; public static int lastIndexOf(java.lang.String, java.lang.String, int);
338 &gt; public static boolean contains(java.lang.String, char);
339 &gt; public static boolean contains(java.lang.String, java.lang.String);
340 &gt; public static int indexOfAny(java.lang.String, char[]);
341 &gt; public static int indexOfAny(java.lang.String, java.lang.String);
342 &gt; public static int indexOfAnyBut(java.lang.String, char[]);
343 &gt; public static int indexOfAnyBut(java.lang.String, java.lang.String);
344 &gt; public static boolean containsOnly(java.lang.String, char[]);
345 &gt; public static boolean containsOnly(java.lang.String, java.lang.String);
346 &gt; public static boolean containsNone(java.lang.String, char[]);
347 &gt; public static boolean containsNone(java.lang.String, java.lang.String);
348 &gt; public static java.lang.String substringBefore(java.lang.String, java.lang.String);
349 &gt; public static java.lang.String substringAfter(java.lang.String, java.lang.String);
350 &gt; public static java.lang.String substringBeforeLast(java.lang.String, java.lang.String);
351 &gt; public static java.lang.String substringAfterLast(java.lang.String, java.lang.String);
352 &gt; public static java.lang.String substringBetween(java.lang.String, java.lang.String);
353 &gt; public static java.lang.String substringBetween(java.lang.String, java.lang.String, java.lang.String);
354 &gt; public static java.lang.String getNestedString(java.lang.String, java.lang.String);
355 &gt; public static java.lang.String getNestedString(java.lang.String, java.lang.String, java.lang.String);
356 &gt; public static java.lang.String split(java.lang.String, char)[];
357 &gt; public static java.lang.String join(java.lang.Object[]);
358 &gt; public static java.lang.String join(java.lang.Object[], char);
359 &gt; public static java.lang.String join(java.util.Iterator, char);
360 &gt; public static java.lang.String deleteSpaces(java.lang.String);
361 &gt; public static java.lang.String deleteWhitespace(java.lang.String);
362 &gt; public static java.lang.String replaceChars(java.lang.String, char, char);
363 &gt; public static java.lang.String replaceChars(java.lang.String, java.lang.String, java.lang.String);
364 &lt; public static java.lang.String center(java.lang.String, int);
365 &lt; public static java.lang.String center(java.lang.String, int, java.lang.String);
366 ---
367 &gt; public static java.lang.String overlay(java.lang.String, java.lang.String, int, int);
368 &gt; public static java.lang.String rightPad(java.lang.String, int, char);
369 &gt; public static java.lang.String leftPad(java.lang.String, int, char);
370 &lt; public static java.lang.String strip(java.lang.String);
371 &lt; public static java.lang.String strip(java.lang.String, java.lang.String);
372 &lt; public static java.lang.String stripAll(java.lang.String[])[];
373 &lt; public static java.lang.String stripAll(java.lang.String[], java.lang.String)[];
374 &lt; public static java.lang.String stripEnd(java.lang.String, java.lang.String);
375 &lt; public static java.lang.String stripStart(java.lang.String, java.lang.String);
376 ---
377 &gt; public static java.lang.String center(java.lang.String, int);
378 &gt; public static java.lang.String center(java.lang.String, int, char);
379 &gt; public static java.lang.String center(java.lang.String, int, java.lang.String);
380 &lt; public static java.lang.String uncapitalise(java.lang.String);
381 ---
382 &gt; public static java.lang.String capitalize(java.lang.String);
383 &gt; public static java.lang.String uncapitalize(java.lang.String);
384 &gt; public static java.lang.String uncapitalise(java.lang.String);
385 &lt; public static java.lang.String getNestedString(java.lang.String, java.lang.String);
386 &lt; public static java.lang.String getNestedString(java.lang.String, java.lang.String, java.lang.String);
387 &gt; public static boolean isWhitespace(java.lang.String);
388 &gt; public static java.lang.String reverseDelimited(java.lang.String, char);
389 &gt; public static java.lang.String abbreviate(java.lang.String, int);
390 &gt; public static java.lang.String abbreviate(java.lang.String, int, int);
391 &gt; public static java.lang.String difference(java.lang.String, java.lang.String);
392 &gt; public static int differenceAt(java.lang.String, java.lang.String);
393 &lt; public static boolean containsOnly(java.lang.String, char[]);
394 ---
395 &gt; static {};
396
397 org.apache.commons.lang.ObjectUtils
398 --------------------
399 &gt; public static java.lang.StringBuffer appendIdentityToString(java.lang.StringBuffer, java.lang.Object);
400 &gt; public static java.lang.String toString(java.lang.Object);
401 &gt; public static java.lang.String toString(java.lang.Object, java.lang.String);
402 &lt; org.apache.commons.lang.ObjectUtils.Null(org.apache.commons.lang.ObjectUtils$1);
403 ---
404 &gt; org.apache.commons.lang.ObjectUtils.Null();
405 &gt; static {};
406
407 org.apache.commons.lang.exception.NestableDelegate
408 --------------------
409 &gt; public static boolean topDown;
410 &gt; public static boolean trimStackFrames;
411 &lt; org.apache.commons.lang.exception.NestableDelegate(org.apache.commons.lang.exception.Nestable);
412 &lt; java.lang.String getMessage(int);
413 &lt; java.lang.String getMessage(java.lang.String);
414 &lt; java.lang.String getMessages()[];
415 &lt; java.lang.Throwable getThrowable(int);
416 &lt; int getThrowableCount();
417 &lt; java.lang.Throwable getThrowables()[];
418 &lt; int indexOfThrowable(java.lang.Class, int);
419 ---
420 &gt; public org.apache.commons.lang.exception.NestableDelegate(org.apache.commons.lang.exception.Nestable);
421 &gt; public java.lang.String getMessage(int);
422 &gt; public java.lang.String getMessage(java.lang.String);
423 &gt; public java.lang.String getMessages()[];
424 &gt; public java.lang.Throwable getThrowable(int);
425 &gt; public int getThrowableCount();
426 &gt; public java.lang.Throwable getThrowables()[];
427 &gt; public int indexOfThrowable(java.lang.Class, int);
428 &gt; protected java.lang.String getStackFrames(java.lang.Throwable)[];
429 &gt; protected void trimStackFrames(java.util.List);
430
431 org.apache.commons.lang.exception.ExceptionUtils
432 --------------------
433 &lt; protected static final java.lang.String CAUSE_METHOD_NAMES[];
434 &lt; protected static final java.lang.Object CAUSE_METHOD_PARAMS[];
435 ---
436 &gt; static final java.lang.String WRAPPED_MARKER;
437 &lt; protected org.apache.commons.lang.exception.ExceptionUtils();
438 ---
439 &gt; public org.apache.commons.lang.exception.ExceptionUtils();
440 &gt; public static void addCauseMethodName(java.lang.String);
441 &gt; public static boolean isThrowableNested();
442 &gt; public static boolean isNestedThrowable(java.lang.Throwable);
443 &gt; public static void printRootCauseStackTrace(java.lang.Throwable);
444 &gt; public static void printRootCauseStackTrace(java.lang.Throwable, java.io.PrintStream);
445 &gt; public static void printRootCauseStackTrace(java.lang.Throwable, java.io.PrintWriter);
446 &gt; public static java.lang.String getRootCauseStackTrace(java.lang.Throwable)[];
447 &gt; public static void removeCommonFrames(java.util.List, java.util.List);
448 &gt; public static java.lang.String getFullStackTrace(java.lang.Throwable);
449 &gt; static java.util.List getStackFrameList(java.lang.Throwable);
450
451 org.apache.commons.lang.CharRange
452 --------------------
453 &lt; class org.apache.commons.lang.CharRange extends java.lang.Object {
454 ---
455 &gt; public final class org.apache.commons.lang.CharRange extends java.lang.Object implements java.io.Serializable {
456 &gt; public org.apache.commons.lang.CharRange(char,boolean);
457 &lt; public org.apache.commons.lang.CharRange(java.lang.String,java.lang.String);
458 ---
459 &gt; public org.apache.commons.lang.CharRange(char,char,boolean);
460 &lt; public void setStart(char);
461 &lt; public void setEnd(char);
462 &lt; public boolean isRange();
463 &lt; public boolean inRange(char);
464 &lt; public void setNegated(boolean);
465 ---
466 &gt; public boolean contains(char);
467 &gt; public boolean contains(org.apache.commons.lang.CharRange);
468 &gt; public boolean equals(java.lang.Object);
469 &gt; public int hashCode();
470 &gt; static {};
471
472 org.apache.commons.lang.ObjectUtils$1
473 --------------------
474 &lt; Compiled from ObjectUtils.java
475 &lt; class org.apache.commons.lang.ObjectUtils$1 extends java.lang.Object {
476 &lt; }
477 ---
478 &gt; Class 'org.apache.commons.lang.ObjectUtils$1' has been removed
479
480 org.apache.commons.lang.ObjectUtils$Null
481 --------------------
482 &lt; org.apache.commons.lang.ObjectUtils.Null(org.apache.commons.lang.ObjectUtils$1);
483 ---
484 &gt; org.apache.commons.lang.ObjectUtils.Null();
485 &gt; static {};
486
487 org.apache.commons.lang.SystemUtils
488 --------------------
489 &gt; public static final java.lang.String FILE_ENCODING;
490 &gt; public static final java.lang.String JAVA_RUNTIME_NAME;
491 &gt; public static final java.lang.String JAVA_RUNTIME_VERSION;
492 &gt; public static final java.lang.String JAVA_VM_INFO;
493 &gt; public static final java.lang.String USER_COUNTRY;
494 &gt; public static final java.lang.String USER_LANGUAGE;
495 &gt; public static final float JAVA_VERSION_FLOAT;
496 &gt; public static final int JAVA_VERSION_INT;
497 &gt; public static final boolean IS_OS_AIX;
498 &gt; public static final boolean IS_OS_HP_UX;
499 &gt; public static final boolean IS_OS_IRIX;
500 &gt; public static final boolean IS_OS_LINUX;
501 &gt; public static final boolean IS_OS_MAC;
502 &gt; public static final boolean IS_OS_MAC_OSX;
503 &gt; public static final boolean IS_OS_OS2;
504 &gt; public static final boolean IS_OS_SOLARIS;
505 &gt; public static final boolean IS_OS_SUN_OS;
506 &gt; public static final boolean IS_OS_WINDOWS;
507 &gt; public static final boolean IS_OS_WINDOWS_2000;
508 &gt; public static final boolean IS_OS_WINDOWS_95;
509 &gt; public static final boolean IS_OS_WINDOWS_98;
510 &gt; public static final boolean IS_OS_WINDOWS_ME;
511 &gt; public static final boolean IS_OS_WINDOWS_NT;
512 &gt; public static final boolean IS_OS_WINDOWS_XP;
513 &gt; public static boolean isJavaVersionAtLeast(int);
514
515 org.apache.commons.lang.SerializationUtils
516 --------------------
517 &gt; public org.apache.commons.lang.SerializationUtils();
518
519 org.apache.commons.lang.RandomStringUtils
520 --------------------
521 &gt; public static java.lang.String random(int, int, int, boolean, boolean, char[], java.util.Random);
522
523 org.apache.commons.lang.CharSet
524 --------------------
525 &lt; public class org.apache.commons.lang.CharSet extends java.lang.Object {
526 ---
527 &gt; public class org.apache.commons.lang.CharSet extends java.lang.Object implements java.io.Serializable {
528 &gt; public static final org.apache.commons.lang.CharSet EMPTY;
529 &gt; public static final org.apache.commons.lang.CharSet ASCII_ALPHA;
530 &gt; public static final org.apache.commons.lang.CharSet ASCII_ALPHA_LOWER;
531 &gt; public static final org.apache.commons.lang.CharSet ASCII_ALPHA_UPPER;
532 &gt; public static final org.apache.commons.lang.CharSet ASCII_NUMERIC;
533 &gt; protected static final java.util.Map COMMON;
534 &gt; public static org.apache.commons.lang.CharSet getInstance(java.lang.String);
535 &gt; protected org.apache.commons.lang.CharSet(java.lang.String);
536 &lt; public boolean contains(char);
537 &gt; public org.apache.commons.lang.CharRange getCharRanges()[];
538 &gt; public boolean contains(char);
539 &gt; public boolean equals(java.lang.Object);
540 &gt; public int hashCode();
541 &gt; static {};
542
543 org.apache.commons.lang.CharSetUtils
544 --------------------
545 &gt; public static java.lang.String keep(java.lang.String, java.lang.String);
546 &gt; public static java.lang.String keep(java.lang.String, java.lang.String[]);
547
548 org.apache.commons.lang.builder.ToStringBuilder
549 --------------------
550 &lt; public org.apache.commons.lang.builder.ToStringBuilder(java.lang.Object);
551 &lt; public org.apache.commons.lang.builder.ToStringBuilder(java.lang.Object,org.apache.commons.lang.builder.ToStringStyle);
552 &lt; public org.apache.commons.lang.builder.ToStringBuilder(java.lang.Object,org.apache.commons.lang.builder.ToStringStyle,java.lang.StringBuffer);
553 &lt; public static void setDefaultStyle(org.apache.commons.lang.builder.ToStringStyle);
554 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.Object);
555 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, java.lang.Object);
556 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, java.lang.Object, boolean);
557 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(long);
558 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, long);
559 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(int);
560 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, int);
561 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(short);
562 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, short);
563 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(char);
564 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, char);
565 ---
566 &gt; public static java.lang.String reflectionToString(java.lang.Object, org.apache.commons.lang.builder.ToStringStyle, boolean, java.lang.Class);
567 &gt; public static void setDefaultStyle(org.apache.commons.lang.builder.ToStringStyle);
568 &gt; public org.apache.commons.lang.builder.ToStringBuilder(java.lang.Object);
569 &gt; public org.apache.commons.lang.builder.ToStringBuilder(java.lang.Object,org.apache.commons.lang.builder.ToStringStyle);
570 &gt; public org.apache.commons.lang.builder.ToStringBuilder(java.lang.Object,org.apache.commons.lang.builder.ToStringStyle,java.lang.StringBuffer);
571 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(boolean);
572 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(boolean[]);
573 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, byte);
574 ---
575 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(byte[]);
576 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(char);
577 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(char[]);
578 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, double);
579 ---
580 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(double[]);
581 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, float);
582 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(boolean);
583 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, boolean);
584 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.Object[]);
585 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, java.lang.Object[]);
586 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, java.lang.Object[], boolean);
587 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(long[]);
588 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, long[]);
589 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, long[], boolean);
590 ---
591 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(float[]);
592 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(int);
593 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, int[]);
594 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, int[], boolean);
595 ---
596 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(long);
597 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(long[]);
598 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.Object);
599 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.Object[]);
600 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(short);
601 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, short[]);
602 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, short[], boolean);
603 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(char[]);
604 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, char[]);
605 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, char[], boolean);
606 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(byte[]);
607 ---
608 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, boolean);
609 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, boolean[]);
610 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, boolean[], boolean);
611 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, byte);
612 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(double[]);
613 ---
614 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, char);
615 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, char[]);
616 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, char[], boolean);
617 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, double);
618 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(float[]);
619 ---
620 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, float);
621 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(boolean[]);
622 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, boolean[]);
623 &lt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, boolean[], boolean);
624 ---
625 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, int);
626 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, int[]);
627 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, int[], boolean);
628 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, long);
629 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, long[]);
630 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, long[], boolean);
631 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, java.lang.Object);
632 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, java.lang.Object, boolean);
633 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, java.lang.Object[]);
634 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, java.lang.Object[], boolean);
635 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, short);
636 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, short[]);
637 &gt; public org.apache.commons.lang.builder.ToStringBuilder append(java.lang.String, short[], boolean);
638 &gt; public org.apache.commons.lang.builder.ToStringBuilder appendAsObjectToString(java.lang.Object);
639 &gt; public org.apache.commons.lang.builder.ToStringBuilder appendSuper(java.lang.String);
640 &gt; public org.apache.commons.lang.builder.ToStringBuilder appendToString(java.lang.String);
641 &gt; public org.apache.commons.lang.builder.ToStringStyle getStyle();
642 &gt; public java.lang.Object getObject();
643
644 org.apache.commons.lang.builder.StandardToStringStyle
645 --------------------
646 &gt; public boolean isUseShortClassName();
647 &gt; public void setUseShortClassName(boolean);
648 &gt; public boolean isFieldSeparatorAtStart();
649 &gt; public void setFieldSeparatorAtStart(boolean);
650 &gt; public boolean isFieldSeparatorAtEnd();
651 &gt; public void setFieldSeparatorAtEnd(boolean);
652
653 org.apache.commons.lang.builder.ToStringStyle
654 --------------------
655 &gt; public void appendSuper(java.lang.StringBuffer, java.lang.String);
656 &gt; public void appendToString(java.lang.StringBuffer, java.lang.String);
657 &gt; protected void removeLastFieldSeparator(java.lang.StringBuffer);
658 &gt; protected void reflectionAppendArrayDetail(java.lang.StringBuffer, java.lang.String, java.lang.Object);
659 &gt; protected boolean isUseShortClassName();
660 &gt; protected void setUseShortClassName(boolean);
661 &gt; protected boolean isFieldSeparatorAtStart();
662 &gt; protected void setFieldSeparatorAtStart(boolean);
663 &gt; protected boolean isFieldSeparatorAtEnd();
664 &gt; protected void setFieldSeparatorAtEnd(boolean);
665
666 org.apache.commons.lang.builder.HashCodeBuilder
667 --------------------
668 &gt; public static int reflectionHashCode(int, int, java.lang.Object, boolean, java.lang.Class);
669 &gt; public org.apache.commons.lang.builder.HashCodeBuilder appendSuper(int);
670
671 org.apache.commons.lang.builder.CompareToBuilder
672 --------------------
673 &gt; public static int reflectionCompare(java.lang.Object, java.lang.Object, boolean, java.lang.Class);
674 &gt; public org.apache.commons.lang.builder.CompareToBuilder appendSuper(int);
675 &gt; public org.apache.commons.lang.builder.CompareToBuilder append(java.lang.Object, java.lang.Object, java.util.Comparator);
676 &gt; public org.apache.commons.lang.builder.CompareToBuilder append(java.lang.Object[], java.lang.Object[], java.util.Comparator);
677
678 org.apache.commons.lang.builder.EqualsBuilder
679 --------------------
680 &gt; public static boolean reflectionEquals(java.lang.Object, java.lang.Object, boolean, java.lang.Class);
681 &gt; public org.apache.commons.lang.builder.EqualsBuilder appendSuper(boolean);
682 </source>
683 </p>
684 </section>
685
686 </body>
687 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>2.1 Release Notes</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="Lang 2.1 Release Notes">
25 <p>
26 These are the release notes and advice for upgrading Commons-Lang from
27 version 2.0 to version 2.1.
28 <source>
29 INTRODUCTION:
30
31 This document contains the release notes for the 2.1 version of Apache Jakarta Commons Lang.
32 Commons Lang is a set of utility functions and reusable components that
33 should be of use in any Java environment.
34
35
36 INCOMPATIBLE CHANGES:
37
38 - The Nestable interface defines the method indexOfThrowable(Class).
39 Previously the implementations checked only for a specific Class.
40 Now they check for subclasses of that Class as well.
41 For most situations this will be the expected behaviour (ie. its a bug fix).
42 If it causes problems, please use the ExceptionUtils.indexOfThrowable(Class) method instead.
43 Note that the ExceptionUtils method is available in v1.0 and v2.0 of commons-lang and has not been changed.
44 (An alternative to this is to change the public static matchSubclasses flag on NestableDelegate.
45 However, we don't recommend that as a long-term solution.)
46
47 - The StopWatch class has had much extra validation added.
48 If your code previously relied on unusual aspects, it may no longer work.
49
50 - Starting with version 2.1, Ant version 1.6.x is required to build. Copy
51 junit.jar to ANT_HOME/lib. You can get JUnit from http://www.junit.org. See the developer's guide
52 for more details.
53
54
55 DEPRECATIONS:
56
57 - The enum package has been renamed to enums for JDK1.5 compilance.
58 All functionality is identical, just the package has changed.
59 This package will be removed in v3.0.
60
61 - NumberUtils.stringToInt - renamed to toInt
62
63 - DateUtils - four constants, MILLIS_IN_* have been deprecated as they were defined
64 as int not long. The replacements are MILLIS_PER_*.
65
66
67 NEW FEATURES:
68
69 New:
70 - Mutable package - contains basic classes that hold an Object or primitive
71 and provide both get and set methods.
72 - DurationFormatUtils - provides various methods for formatting durations
73 - CharEncoding - definitions of constants for character encoding work
74 - CharUtils - utilities for working with characters
75
76 Updated:
77 - ArrayUtils - many more methods, especially List-like methods
78 - BooleanUtils - isTrue and isFalse methods that handle null
79 - ClassUtils - primitive to wrapper class conversion methods
80 - ClassUtils - class name comparator
81 - IllegalClassException - extra constructor for common instanceof case
82 - NotImplementedException - supports nested exceptions
83 - ObjectUtils - hashcode method handling null
84 - StringUtils - isAsciiPrintable to check the contents of a string
85 -- ordinalIndexOf to find the nth index of a string
86 -- various remove methods to remove parts of a string
87 -- various split methods to provide more control over splitting a string
88 -- defaultIfEmpty to default a string if null or empty
89 - SystemUtils - methods to get system properties as File objects
90 -- extra constants representing system properties
91 - Validate - new methods to check whether all elements in a collection are of a specific type
92 - WordUtils - new methods to capitalize based on a set of specified delimiters
93
94 - EqualsBuilder - now provides setter to internal state
95 - ToStringStyle - new style, short prefix style
96 - ReflectionToStringBuilder - more flags to control the output with regards to statics
97
98 - ExceptionUtils - added indexOfType methods that check subclasses, thus leaving the existing
99 indexOfThrowable method untouched (see incompatible changes section)
100
101 - NumberUtils - various string to number parsing methods added
102
103 - DateUtils - methods added to compare dates in various ways
104 -- method to parse a date string using multiple patterns
105 - FastDateFormat - extra formatting methods that take in a millisecond long value
106 -- additional static factory methods
107 - StopWatch - new methods for split behaviour
108
109
110 BUG FIXES:
111
112 19331 General case: infinite loop: ToStringBuilder.reflectionToString
113 23174 EqualsBuilder.append(Object[], Object[]) throws NPE
114 23356 Make DurationFormatUtils public!
115 23557 WordUtils.capitalizeFully(String str) should take a delimiters
116 23683 New method for converting a primitive Class to its corresponding wrapper
117 23430 Minor javadoc fixes for StringUtils.contains(String, String)
118 23590 make optional parameters in FastDateFormat really optional
119 24056 Documentation error in StringUtils.replace
120 25227 StringEscapeUtils.unescapeHtml() doesn't handle hex entities
121 25454 new StringUtils.replaceChars behaves differently from old Ch
122 25560 DateUtils.truncate() is off by one hour when using a date in DST switch 'zone'
123 25627 DateUtils constants should be long
124 25683 Add method that validates Collection elements are a correct
125 25849 Add SystemUtils methods for directory properties.
126 26616 ClassCastException in Enum.equals(Object)
127 26699 Tokenizer Enhancements: reset input string, static CSV
128 26734 NullPointerException in EqualsBuilder.append(Object[], Object[])
129 26877 Add SystemUtils.AWT_TOOLKIT and others.
130 26922 public static boolean DateUtils.equals(Date dt1, Date dt2)
131 27592 WordUtils capitalize improvement
132 27876 ReflectionToStringBuilder.toString(null) throws exception by design
133 27877 Make ClassUtils methods null-safe and not throw an IAE.
134 28468 StringUtils.defaultString: Documentation error
135 28554 Add hashCode-support to class ObjectUtils
136 29082 Enhancement of ExceptionUtils.CAUSE_METHOD_NAMES
137 29149 StringEscapeUtils.unescapeHtml() doesn't handle an empty entity
138 29294 lang.math.Fraction class deficiencies
139 29673 ExceptionUtils: new getCause() methodname (for tomcat)
140 29794 Add convenience format(long) methods to FastDateForma
141 30328 HashCodeBuilder does not use the same values as Boolean (fixed as documentation)
142 30334 New class proposal: CharacterEncoding
143 30674 parseDate class from HttpClient's DateParser class
144 30815 ArrayUtils.isEquals() throws ClassCastException when array1
145 30929 Nestable.indexOfThrowable(Class) uses Class.equals() to match
146 31395 DateUtils.truncate oddity at the far end of the Date spectrum
147 31478 Compile error with JDK 5 "enum" is a keyword
148 31572 o.a.c.lang.enum.ValuedEnum: 'enum'is a keyword in JDK1.5.0
149 31933 ToStringStyle setArrayEnd handled null incorrectly
150 32133 SystemUtils fails init on HP-UX
151 32198 Error in JavaDoc for StringUtils.chomp(String, String)
152 32625 Can't subclass EqualsBuilder because isEquals is private
153 33067 EqualsBuilder.append(Object[], Object[]) crashes with a NullPointerException if an element of the first array is null
154 33069 EqualsBuilder.append(Object[], Object[]) incorrectly checks that rhs[i] is instance of lhs[i]'s class
155 33574 unbalanced ReflectionToStringBuilder
156 33737 ExceptionUtils.addCauseMethodName(String) does not check for duplicates.
157 </source>
158 </p>
159 </section>
160
161 </body>
162 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>2.2 Release Notes</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="Lang 2.2 Release Notes">
25 <p>
26 These are the release notes and advice for upgrading Commons-Lang from
27 version 2.1 to version 2.2.
28 <source>
29 INTRODUCTION:
30
31 This document contains the release notes for the 2.2 version of Apache Jakarta Commons Lang.
32 Commons Lang is a set of utility functions and reusable components that
33 should be of use in any Java environment.
34
35 INCOMPATIBLE CHANGES WITH VERSION 2.1:
36
37 - None
38
39 DEPRECATIONS FROM 2.1 to 2.2:
40
41 - None
42
43 BUG FIXES IN 2.2:
44
45 <a href="https://issues.apache.org/jira/browse/LANG-2">LANG-2</a> javadoc example for StringUtils.splitByWholeSeparator incorrect
46 <a href="https://issues.apache.org/jira/browse/LANG-3">LANG-3</a> PADDING array in StringUtils overflows on '\uffff'
47 <a href="https://issues.apache.org/jira/browse/LANG-10">LANG-10</a> [patch] ClassUtils.primitiveToWrapper and Void
48 <a href="https://issues.apache.org/jira/browse/LANG-21">LANG-21</a> escapeXML() -&gt; Not escaping low characters
49 <a href="https://issues.apache.org/jira/browse/LANG-25">LANG-25</a> DurationFormatUtils.formatDurationISO() javadoc is missing T in duration string between date and time part
50 <a href="https://issues.apache.org/jira/browse/LANG-37">LANG-37</a> unit test for org.apache.commons.lang.text.StrBuilder
51 <a href="https://issues.apache.org/jira/browse/LANG-42">LANG-42</a> EqualsBuilder.append(Object[], Object[]) crashes with a NullPointerException if an element of the first array is null
52 <a href="https://issues.apache.org/jira/browse/LANG-45">LANG-45</a> StrBuilderTest#testReplaceStringString fails.
53 <a href="https://issues.apache.org/jira/browse/LANG-50">LANG-50</a> Replace Clover with Cobertura
54 <a href="https://issues.apache.org/jira/browse/LANG-59">LANG-59</a> DateUtils.truncate method is buggy when dealing with DST switching hours
55 <a href="https://issues.apache.org/jira/browse/LANG-100">LANG-100</a> RandomStringUtils.random() family of methods create invalid Unicode sequences
56 <a href="https://issues.apache.org/jira/browse/LANG-105">LANG-105</a> ExceptionUtils goes into infinite loop in getThrowables is throwable.getCause() == throwable
57 <a href="https://issues.apache.org/jira/browse/LANG-106">LANG-106</a> StringUtils#getLevenshteinDistance() performance is sub-optimal
58 <a href="https://issues.apache.org/jira/browse/LANG-112">LANG-112</a> Wrong length check in StrTokenizer.StringMatcher
59 <a href="https://issues.apache.org/jira/browse/LANG-117">LANG-117</a> FastDateFormat: wrong format for date "01.01.1000"
60 <a href="https://issues.apache.org/jira/browse/LANG-122">LANG-122</a> EscapeUtil.escapeHtml() should clarify that it does not escape ' chars to &apos;
61 <a href="https://issues.apache.org/jira/browse/LANG-123">LANG-123</a> Unclear javadoc for DateUtils.iterator()
62 <a href="https://issues.apache.org/jira/browse/LANG-127">LANG-127</a> Minor tweak to fix of bug # 26616
63 <a href="https://issues.apache.org/jira/browse/LANG-130">LANG-130</a> Memory "leak" in StringUtils
64 <a href="https://issues.apache.org/jira/browse/LANG-140">LANG-140</a> DurationFormatUtils.formatPeriod() returns the wrong result
65 <a href="https://issues.apache.org/jira/browse/LANG-141">LANG-141</a> Fraction.toProperString() returns -1/1 for -1
66 <a href="https://issues.apache.org/jira/browse/LANG-148">LANG-148</a> Performance modifications on StringUtils.replace
67 <a href="https://issues.apache.org/jira/browse/LANG-150">LANG-150</a> StringEscapeUtils.unescapeHtml skips first entity after standalone ampersand
68 <a href="https://issues.apache.org/jira/browse/LANG-152">LANG-152</a> DurationFormatUtils.formatDurationWords "11 &lt;units&gt;" gets converted to "11 &lt;unit&gt;"
69 <a href="https://issues.apache.org/jira/browse/LANG-259">LANG-259</a> ValuedEnum.compareTo(Object other) not typesafe - it easily could be...
70 <a href="https://issues.apache.org/jira/browse/LANG-261">LANG-261</a> Error in an example in the javadoc of the StringUtils.splitPreserveAllTokens() method
71 <a href="https://issues.apache.org/jira/browse/LANG-264">LANG-264</a> ToStringBuilder/HashCodeBuilder javadoc code examples
72 <a href="https://issues.apache.org/jira/browse/LANG-271">LANG-271</a> LocaleUtils test fails under Mustang
73 <a href="https://issues.apache.org/jira/browse/LANG-272">LANG-272</a> Minor build and checkstyle changes
74 <a href="https://issues.apache.org/jira/browse/LANG-277">LANG-277</a> Javadoc errors on StringUtils.splitPreserveAllTokens(String, char)
75 <a href="https://issues.apache.org/jira/browse/LANG-278">LANG-278</a> javadoc for StringUtils.removeEnd is incorrect
76
77 IMPROVEMENTS IN 2.2:
78
79 <a href="https://issues.apache.org/jira/browse/LANG-159">LANG-159</a> Add WordUtils.getInitials(String)
80 <a href="https://issues.apache.org/jira/browse/LANG-161">LANG-161</a> Add methods and tests to StrBuilder
81 <a href="https://issues.apache.org/jira/browse/LANG-162">LANG-162</a> replace() length calculation improvement
82 <a href="https://issues.apache.org/jira/browse/LANG-165">LANG-165</a> parseDate with TimeZone
83 <a href="https://issues.apache.org/jira/browse/LANG-166">LANG-166</a> New interpolation features
84 <a href="https://issues.apache.org/jira/browse/LANG-169">LANG-169</a> Implementation of escape/unescapeHtml methods with Writer
85 <a href="https://issues.apache.org/jira/browse/LANG-176">LANG-176</a> CompareToBuilder excludeFields for reflection method
86 <a href="https://issues.apache.org/jira/browse/LANG-186">LANG-186</a> Request for MutableBoolean implementation
87 <a href="https://issues.apache.org/jira/browse/LANG-194">LANG-194</a> add generic add method to DateUtils
88 <a href="https://issues.apache.org/jira/browse/LANG-198">LANG-198</a> New method for EqualsBuilder
89 <a href="https://issues.apache.org/jira/browse/LANG-212">LANG-212</a> New ExceptionUtils method setCause()
90 <a href="https://issues.apache.org/jira/browse/LANG-216">LANG-216</a> Provides a Class.getPublicMethod which returns public invocable Method
91 <a href="https://issues.apache.org/jira/browse/LANG-217">LANG-217</a> Add Mutable&lt;Type&gt; to&lt;Type&gt;() methods.
92 <a href="https://issues.apache.org/jira/browse/LANG-220">LANG-220</a> Tokenizer Enhancements: reset input string, static CSV/TSV factories
93 <a href="https://issues.apache.org/jira/browse/LANG-226">LANG-226</a> Using ReflectionToStringBuilder and excluding secure fields
94 <a href="https://issues.apache.org/jira/browse/LANG-242">LANG-242</a> Trivial cleanup of javadoc in various files
95 <a href="https://issues.apache.org/jira/browse/LANG-246">LANG-246</a> CompositeFormat
96 <a href="https://issues.apache.org/jira/browse/LANG-250">LANG-250</a> Performance boost for RandomStringUtils
97 <a href="https://issues.apache.org/jira/browse/LANG-254">LANG-254</a> Enhanced Class.forName version
98 <a href="https://issues.apache.org/jira/browse/LANG-260">LANG-260</a> StringEscapeUtils should expose escape*() methods taking Writer argument
99 <a href="https://issues.apache.org/jira/browse/LANG-263">LANG-263</a> Add StringUtils.containsIgnoreCase(...)
100 <a href="https://issues.apache.org/jira/browse/LANG-267">LANG-267</a> Support char array converters on ArrayUtils
101 <a href="https://issues.apache.org/jira/browse/LANG-270">LANG-270</a> minor javadoc improvements for StringUtils.stripXxx() methods
102 New ExceptionUtils methods getMessage/getRootCauseMessage
103
104 </source>
105 </p>
106 </section>
107
108 </body>
109 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>2.3 Release Notes</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="Lang 2.3 Release Notes">
25 <p>
26 These are the release notes and advice for upgrading Commons-Lang from
27 version 2.2 to version 2.3.
28 <source>
29 INTRODUCTION:
30
31 This document contains the release notes for the 2.3 version of Apache
32 Jakarta Commons Lang.
33 Commons Lang is a set of utility functions and reusable components that
34 should be of use in any Java environment.
35
36 INCOMPATIBLE CHANGES WITH VERSION 2.2:
37
38 - Calling stop on a suspended StopWatch will no longer change the underlying time.
39 It's very unlikely anyone was relying on that bug as a feature.
40
41 ADDITIONAL INCOMPATIBLE CHANGES WITH VERSION 2.0:
42
43 - The Nestable interface defines the method indexOfThrowable(Class).
44 Previously the implementations checked only for a specific Class.
45 Now they check for subclasses of that Class as well.
46 For most situations this will be the expected behaviour (ie. its a bug fix).
47 If it causes problems, please use the ExceptionUtils.indexOfThrowable(Class) method instead.
48 Note that the ExceptionUtils method is available in v1.0 and v2.0 of commons-lang and has not been changed.
49 (An alternative to this is to change the public static matchSubclasses flag on NestableDelegate.
50 However, we don't recommend that as a long-term solution.)
51
52 - The StopWatch class has had much extra validation added.
53 If your code previously relied on unusual aspects, it may no longer work.
54
55 - Starting with version 2.1, Ant version 1.6.x is required to build. Copy
56 junit.jar to ANT_HOME/lib. You can get JUnit from http://www.junit.org. See the developer's guide
57 for more details.
58
59 DEPRECATIONS FROM 2.2 to 2.3:
60
61 - None
62
63 DEPRECATIONS FROM 2.1 to 2.2:
64
65 - None
66
67 DEPRECATIONS FROM 2.0 to 2.1:
68
69 - The enum package has been renamed to enums for JDK1.5 compilance.
70 All functionality is identical, just the package has changed.
71 This package will be removed in v3.0.
72
73 - NumberUtils.stringToInt - renamed to toInt
74
75 - DateUtils - four constants, MILLIS_IN_* have been deprecated as they were defined
76 as int not long. The replacements are MILLIS_PER_*.
77
78
79 BUG FIXES IN 2.3:
80
81 * [LANG-69 ] - ToStringBuilder throws StackOverflowError when an Object cycle exists
82 * [LANG-102] - Refactor Entities methods
83 * [LANG-153] - Can't XMLDecode an Enum
84 * [LANG-262] - Use of enum prevents a classloader from being garbage collected resuling in out of memory exceptions.
85 * [LANG-279] - HashCodeBuilder throws java.lang.StackOverflowError when an object contains a cycle.
86 * [LANG-281] - DurationFormatUtils returns wrong result
87 * [LANG-286] - Serialization - not backwards compatible
88 * [LANG-292] - unescapeXml("&amp;12345678;") should be "&amp;12345678;"
89 * [LANG-294] - StrBuilder.replaceAll and StrBuilder.deleteAll can throw ArrayIndexOutOfBoundsException.
90 * [LANG-295] - StrBuilder contains usages of thisBuf.length when they should use size
91 * [LANG-299] - Bug in method appendFixedWidthPadRight of class StrBuilder causes an ArrayIndexOutOfBoundsException
92 * [LANG-300] - NumberUtils.createNumber throws NumberFormatException for one digit long
93 * [LANG-303] - FastDateFormat.mRules is not transient or serializable
94 * [LANG-304] - NullPointerException in isAvailableLocale(Locale)
95 * [LANG-313] - Wrong behavior of Entities.unescape
96 * [LANG-315] - StopWatch: suspend() acts as split(), if followed by stop()
97
98 IMPROVEMENTS IN 2.3:
99
100 * [LANG-258] - Enum JavaDoc
101 * [LANG-266] - Wish for StringUtils.join(Collection, *)
102 * [LANG-268] - StringUtils.join should allow you to pass a range for it (so it only joins a part of the array)
103 * [LANG-275] - StringUtils substringsBetween
104 * [LANG-282] - Create more tests to test out the +=31 replacement code in DurationFormatUtils.
105 * [LANG-287] - Optimize StringEscapeUtils.unescapeXml(String)
106 * [LANG-289] - NumberUtils.max(byte[]) and NumberUtils.min(byte[]) are missing
107 * [LANG-291] - Null-safe comparison methods for finding most recent / least recent dates.
108 * [LANG-306] - StrBuilder appendln/appendAll/appendSeparator
109 * [LANG-310] - BooleanUtils isNotTrue/isNotFalse
110 * [LANG-314] - Tests fail to pass when building with Maven 2
111
112 </source>
113 </p>
114 </section>
115
116 </body>
117 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>2.4 Release Notes</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="Lang 2.4 Release Notes">
25 <p>
26 These are the release notes and advice for upgrading Commons-Lang from
27 version 2.3 to version 2.4. <br/><br/>See '<a href="article2_4.html">What's new in 2.4?</a>' for more information.
28 <source>
29 INTRODUCTION:
30
31 This document contains the release notes for the 2.4 version of Apache Commons Lang.
32 Commons Lang is a set of utility functions and reusable components that should be of use in any Java environment.
33
34 Lang 2.4 no longer attempts to target the Java 1.1 environment and now targets Java 1.2. While previous versions
35 were built for 1.1, some parts were using methods that were only available in 1.2, and the Enum class had
36 become dependent on Java 1.3.
37
38 INCOMPATIBLE CHANGES WITH VERSION 2.3:
39
40 - None
41
42 INCOMPATIBLE CHANGES WITH VERSION 2.2:
43
44 - Calling stop on a suspended StopWatch will no longer change the underlying time.
45 It's very unlikely anyone was relying on that bug as a feature.
46
47 ADDITIONAL INCOMPATIBLE CHANGES WITH VERSION 2.0:
48
49 - The Nestable interface defines the method indexOfThrowable(Class).
50 Previously the implementations checked only for a specific Class.
51 Now they check for subclasses of that Class as well.
52 For most situations this will be the expected behaviour (ie. its a bug fix).
53 If it causes problems, please use the ExceptionUtils.indexOfThrowable(Class) method instead.
54 Note that the ExceptionUtils method is available in v1.0 and v2.0 of commons-lang and has not been changed.
55 (An alternative to this is to change the public static matchSubclasses flag on NestableDelegate.
56 However, we don't recommend that as a long-term solution.)
57
58 - The StopWatch class has had much extra validation added.
59 If your code previously relied on unusual aspects, it may no longer work.
60
61 - Starting with version 2.1, Ant version 1.6.x is required to build. Copy
62 junit.jar to ANT_HOME/lib. You can get JUnit from http://www.junit.org. See the developer's guide
63 for more details.
64
65 DEPRECATIONS FROM 2.3 to 2.4:
66
67 - ObjectUtils.appendIdentityToString(StringBuffer, Object) - has very odd semantics, use
68 ObjectUtils.identityToString(StringBuffer, Object) instead.
69
70 - public static java.util.Date add(java.util.Date, int, int) - it is not intended for this
71 method to be public. Please let us know if you use this.
72
73 DEPRECATIONS FROM 2.2 to 2.3:
74
75 - None
76
77 DEPRECATIONS FROM 2.1 to 2.2:
78
79 - None
80
81 DEPRECATIONS FROM 2.0 to 2.1:
82
83 - The enum package has been renamed to enums for JDK1.5 compilance.
84 All functionality is identical, just the package has changed.
85 This package will be removed in v3.0.
86
87 - NumberUtils.stringToInt - renamed to toInt
88
89 - DateUtils - four constants, MILLIS_IN_* have been deprecated as they were defined
90 as int not long. The replacements are MILLIS_PER_*.
91
92
93 BUG FIXES IN 2.4:
94
95 * [LANG-76 ] - EnumUtils.getEnum() doesn't work well in 1.5
96 * [LANG-328] - LocaleUtils.toLocale() rejects strings with only language+variant
97 * [LANG-334] - Enum is not thread-safe
98 * [LANG-346] - Dates.round() behaves incorrectly for minutes and seconds
99 * [LANG-349] - Deadlock using ReflectionToStringBuilder
100 * [LANG-353] - Javadoc Example for EqualsBuilder is questionable
101 * [LANG-360] - Why does appendIdentityToString return null?
102 * [LANG-361] - BooleanUtils toBooleanObject javadoc does not match implementation
103 * [LANG-363] - StringEscapeUtils..escapeJavaScript() method did not escape '/' into '\/', it will make IE render page uncorrectly
104 * [LANG-364] - Documentation bug for ignoreEmptyTokens accessors in StrTokenizer
105 * [LANG-365] - BooleanUtils.toBoolean() - invalid drop-thru in case statement causes StringIndexOutOfBoundsException
106 * [LANG-367] - FastDateFormat thread safety
107 * [LANG-368] - FastDateFormat getDateInstance() and getDateTimeInstance() assume Locale.getDefault() won't change
108 * [LANG-369] - ExceptionUtils not thread-safe
109 * [LANG-372] - ToStringBuilder: MULTI_LINE_STYLE does not print anything from appendToString methods.
110 * [LANG-380] - infinite loop in Fraction.reduce when numerator == 0
111 * [LANG-381] - NumberUtils.min(floatArray) returns wrong value if floatArray[0] happens to be Float.NaN
112 * [LANG-385] - http://commons.apache.org/lang/developerguide.html "Building" section is incorrect and incomplete
113 * [LANG-393] - EqualsBuilder don't compare BigDecimals correctly
114 * [LANG-399] - Javadoc bugs - cannot find object
115 * [LANG-410] - Ambiguous / confusing names in StringUtils replace* methods
116 * [LANG-412] - StrBuilder appendFixedWidth does not handle nulls
117 * [LANG-414] - DateUtils.round() often fails
118
119 IMPROVEMENTS IN 2.4:
120
121 * [LANG-180] - adding a StringUtils.replace method that takes an array or List of replacement strings
122 * [LANG-192] - Split camel case strings
123 * [LANG-257] - Add new splitByWholeSeparatorPreserveAllTokens() methods to StringUtils
124 * [LANG-269] - Shouldn't Commons Lang's StringUtils have a "common" string method?
125 * [LANG-298] - ClassUtils.getShortClassName and ClassUtils.getPackageName and class of array
126 * [LANG-321] - Add toArray() method to IntRange and LongRange classes
127 * [LANG-322] - ClassUtils.getShortClassName(String) inefficient
128 * [LANG-326] - StringUtils: startsWith / endsWith / startsWithIgnoreCase / endsWithIgnoreCase / removeStartIgnoreCase / removeEndIgnoreCase methods
129 * [LANG-329] - Pointless synchronized in ThreadLocal.initialValue should be removed
130 * [LANG-333] - ArrayUtils.toClass
131 * [LANG-337] - Utility class constructor javadocs should acknowledge that they may sometimes be used, e.g. with Velocity.
132 * [LANG-338] - truncateNicely method which avoids truncating in the middle of a word
133 * [LANG-345] - Optimize HashCodeBuilder.append(Object)
134 * [LANG-351] - Extension to ClassUtils: Obtain the primitive class from a wrapper
135 * [LANG-356] - Add getStartTime to StopWatch
136 * [LANG-362] - Add ExtendedMessageFormat to org.apache.commons.lang.text
137 * [LANG-371] - ToStringStyle javadoc should show examples of styles
138 * [LANG-374] - Add escaping for CSV columns to StringEscapeUtils
139 * [LANG-375] - add SystemUtils.IS_OS_WINDOWS_VISTA field
140 * [LANG-379] - Calculating A date fragment in any time-unit
141 * [LANG-383] - Adding functionality to DateUtils to allow direct setting of various fields.
142 * [LANG-402] - OSGi-ify Lang
143 * [LANG-404] - Add Calendar flavour format methods to DateFormatUtils
144 * [LANG-407] - StringUtils.length(String) returns null-safe length
145 * [LANG-413] - Memory usage improvement for StringUtils#getLevenshteinDistance()
146
147 </source>
148 </p>
149 </section>
150
151 </body>
152 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>2.5 Release Notes</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="Lang 2.5 Release Notes">
25 <p>
26 These are the release notes and advice for upgrading Commons-Lang from
27 version 2.4 to version 2.5. <br/><br/>See '<a href="article2_5.html">What's new in 2.5?</a>' for more information.
28 <source>
29 INTRODUCTION:
30
31 This document contains the release notes for the 2.5 version of Apache Commons Lang.
32 Commons Lang is a set of utility functions and reusable components that should be of use in any Java environment.
33
34 Lang 2.5 no longer attempts to target the Java 1.2 environment and now targets Java 1.3.
35
36 IMPROVEMENTS IN 2.5
37 ===================
38
39 * [LANG-583] - ArrayUtils - add isNotEmpty() methods
40 * [LANG-534] - ArrayUtils - add nullToEmpty() methods
41 * [LANG-454] - CharRange - provide an iterator that lets you walk the chars in the range
42 * [LANG-514] - CharRange - add more readable static builder methods
43 * [ ] - ClassUtils - new isAssignable() methods with autoboxing
44 * [LANG-535] - ClassUtils - add support to getShortClassName and getPackageName for arrays
45 * [LANG-434] - DateUtils - add ceiling() method
46 * [LANG-486] - DateUtils - add parseDateStrictly() method
47 * [LANG-466] - EqualsBuilder - add reset() method
48 * [LANG-461] - NumberUtils - add toByte() and toShort() methods
49 * [LANG-522] - Mutable numbers - add string constructors
50 * [ ] - MutableBoolean - add toBoolean(), isTrue() and isFalse() methods
51 * [LANG-422] - StrBuilder - add appendSeparator() methods with an alternative default separator if the StrBuilder is currently empty
52 * [LANG-555] - SystemUtils - add IS_OS_WINDOWS_7 constant
53 * [LANG-554] - SystemUtils - add IS_JAVA_1_7 constant for JDK 1.7
54 * [LANG-405] - StringUtils - add abbreviateMiddle() method
55 * [LANG-569] - StringUtils - add indexOfIgnoreCase() and lastIndexOfIgnoreCase() methods
56 * [LANG-471] - StringUtils - add isAllUpperCase() and isAllLowerCase() methods
57 * [LANG-469] - StringUtils - add lastOrdinalIndexOf() method to complement the existing ordinalIndexOf() method
58 * [LANG-348] - StringUtils - add repeat() method
59 * [LANG-445] - StringUtils - add startsWithAny() method
60 * [LANG-430] - StringUtils - add upperCase(String, Locale) and lowerCase(String, Locale) methods
61 * [LANG-416] - New Reflection package containing ConstructorUtils, FieldUtils, MemberUtils and MethodUtils
62
63 BUG FIXES IN 2.5
64 ================
65
66 * [LANG-494] - CharSet - Synchronizing the COMMON Map so that getInstance doesn't miss a put from a subclass in another thread
67 * [LANG-500] - ClassUtils - improving performance of getAllInterfaces
68 * [LANG-587] - ClassUtils - toClass() throws NullPointerException on null array element
69 * [LANG-530] - DateUtils - Fix parseDate() cannot parse ISO8601 dates produced by FastDateFormat
70 * [LANG-440] - DateUtils - round() doesn't work correct for Calendar.AM_PM
71 * [LANG-443] - DateUtils - improve tests
72 * [LANG-204] - Entities - multithreaded initialization
73 * [LANG-506] - Entities - missing final modifiers; thread-safety issues
74 * [LANG-76] - EnumUtils - getEnum() doesn't work well in 1.5+
75 * [LANG-584] - ExceptionUtils - use immutable lock target
76 * [LANG-477] - ExtendedMessageFormat - OutOfMemory with a pattern containing single quotes
77 * [LANG-538] - FastDateFormat - call getTime() on a calendar to ensure timezone is in the right state
78 * [LANG-547] - FastDateFormat - Remove unused field
79 * [LANG-511] - LocaleUtils - initialization of available locales can be deferred
80 * [LANG-457] - NumberUtils - createNumber() thows a StringIndexOutOfBoundsException for "l"
81 * [LANG-521] - NumberUtils - isNumber(String) and createNumber(String) both modified to support '2.'
82 * [LANG-432] - StringUtils - improve handling of case-insensitive Strings
83 * [LANG-552] - StringUtils - replaceEach() no longer NPEs when null appears in the last String[]
84 * [LANG-460] - StringUtils - correct JavaDocs for startsWith() and startsWithIgnoreCase()
85 * [LANG-421] - StringEscapeUtils - escapeJava() escapes '/' characters
86 * [LANG-450] - StringEscapeUtils - change escapeJavaStyleString() to throw UnhandledException instead swallowing IOException
87 * [LANG-419] - WordUtils - fix StringIndexOutOfBoundsException when lower is greater than the String length
88 * [LANG-523] - StrBuilder - Performance improvement by doubling the size of the String in ensureCapacity
89 * [LANG-575] - Compare, Equals and HashCode builders - use ArrayUtils to avoid creating a temporary List
90 * [LANG-467] - EqualsBuilder - removing the special handling of BigDecimal (LANG-393) to use compareTo
91 * [LANG-574] - HashCodeBuilder - Performance improvement: check for isArray to short-circuit the 9 instanceof checks
92 * [LANG-520] - HashCodeBuilder - Changing the hashCode() method to return toHashCode()
93 * [LANG-459] - HashCodeBuilder - reflectionHashCode() can generate incorrect hashcodes
94 * [LANG-586] - HashCodeBuilder and ToStringStyle - use of ThreadLocal causes memory leaks in container environments
95 * [LANG-487] - ToStringBuilder - make default style thread-safe
96 * [LANG-472] - RandomUtils - nextLong() always produces even numbers
97 * [LANG-592] - RandomUtils - RandomUtils tests are failing frequently
98
99 </source>
100 </p>
101 </section>
102
103 </body>
104 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>2.6 Release Notes</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="Lang 2.6 Release Notes">
25 <p>
26 These are the release notes and advice for upgrading Commons-Lang from
27 version 2.5 to version 2.6. <br/><br/>.
28 <source>
29 INTRODUCTION:
30
31 This document contains the release notes for the 2.6 version of Apache Commons Lang.
32 Commons Lang is a set of utility functions and reusable components that should be of use in any Java environment.
33
34
35 COMPATIBILITY WITH 2.5
36 ======================
37 Lang 2.6 is binary compatible release with Lang 2.5, containing bug fixes and small enhancements.
38
39 Lang 2.6 requires a minimum of JDK 1.3.
40
41
42 IMPROVEMENTS IN 2.6
43 ===================
44
45 * [LANG-633] - BooleanUtils: use same optimization in toBooleanObject(String) as in toBoolean(String)
46 * [LANG-599] - ClassUtils: allow Dots as Inner Class Separators in getClass()
47 * [LANG-594] - DateUtils: equal and compare functions up to most significant field
48 * [LANG-632] - DateUtils: provide a Date to Calendar convenience method
49 * [LANG-576] - ObjectUtils: add clone methods to ObjectUtils
50 * [LANG-667] - ObjectUtils: add a Null-safe compare() method
51 * [LANG-670] - ObjectUtils: add notEqual() method
52 * [LANG-302] - StrBuilder: implement clone() method
53 * [LANG-640] - StringUtils: add a normalizeSpace() method
54 * [LANG-614] - StringUtils: add endsWithAny() method
55 * [LANG-655] - StringUtils: add defaultIfBlank() method
56 * [LANG-596] - StrSubstitutor: add a replace(String, Properties) variant
57 * [LANG-482] - StrSubstitutor: support substitution in variable names
58 * [LANG-669] - Use StrBuilder instead of StringBuffer to improve performance where sync. is not an issue
59
60 BUG FIXES IN 2.6
61 ================
62
63 * [LANG-629] - CharSet: make the underlying set synchronized
64 * [LANG-635] - CompareToBuilder: fix passing along compareTransients to the reflectionCompare method
65 * [LANG-636] - ExtendedMessageFormat doesn't override equals(Object)
66 * [LANG-645] - FastDateFormat: fix to properly include the locale when formatting a Date
67 * [LANG-638] - NumberUtils: createNumber() throws a StringIndexOutOfBoundsException when argument containing "e" and "E" is passed in
68 * [LANG-607] - StringUtils methods do not handle Unicode 2.0+ supplementary characters correctly
69 * [LANG-624] - SystemUtils: getJavaVersionAsFloat throws StringIndexOutOfBoundsException on Android runtime/Dalvik VM
70 * [BEANUTILS-381] - MemberUtils: getMatchingAccessibleMethod does not correctly handle inheritance and method overloading
71
72 OTHER CHANGES IN 2.6
73 ====================
74
75 * [LANG-600] - Javadoc is incorrect for lastIndexOf() method
76 * [LANG-628] - Javadoc for HashCodeBuilder.append(boolean) does not match implementation
77 * [LANG-643] - Javadoc StringUtils.left() claims to throw an exception on negative lenth, but doesn't
78 * [LANG-370] - Javadoc - document thread safety
79 * [LANG-623] - Test for StringUtils replaceChars() icelandic characters
80
81 </source>
82 </p>
83 </section>
84
85 </body>
86 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document>
18 <properties>
19 <title>Upgrade from 2.5 to 3.0</title>
20 <author email="dev@commons.apache.org">Commons Documentation Team</author>
21 </properties>
22 <body>
23
24 <section name="Upgrade to 3.0">
25 <p>
26 For advice on upgrading Commons-Lang from version 2.5 to version 3.0 see
27 '<a href="article3_0.html">What's new in 3.0?</a>'.
28 <source>
29 INTRODUCTION:
30
31 This document contains the release notes for the 3.0 version of Apache Commons Lang.
32 Commons Lang is a set of utility functions and reusable components that should be of use in any
33 Java environment.
34
35 Lang 3.0 now targets Java 5.0, making use of features that arrived with Java 5.0 such as generics,
36 variable arguments, autoboxing, concurrency and formatted output.
37
38 ADDITIONS IN 3.0
39 ================
40
41 [LANG-276] MutableBigDecimal and MutableBigInteger.
42 [LANG-285] Wish : method unaccent.
43 [LANG-358] ObjectUtils.coalesce.
44 [LANG-386] LeftOf/RightOfNumber in Range convenience methods necessary.
45 [LANG-435] Add ClassUtils.isAssignable() variants with autoboxing.
46 [LANG-444] StringUtils.emptyToNull.
47 [LANG-482] Enhance StrSubstitutor to support nested ${var-${subvr}} expansion
48 [LANG-482] StrSubstitutor now supports substitution in variable names.
49 [LANG-496] A generic implementation of the Lazy initialization pattern.
50 [LANG-497] Addition of ContextedException and ContextedRuntimeException.
51 [LANG-498] Add StringEscapeUtils.escapeText() methods.
52 [LANG-499] Add support for the handling of ExecutionExceptions.
53 [LANG-501] Add support for background initialization.
54 [LANG-529] Add a concurrent package.
55 [LANG-533] Validate: support for validating blank strings.
56 [LANG-537] Add ArrayUtils.toArray to create generic arrays.
57 [LANG-545] Add ability to create a Future for a constant.
58 [LANG-546] Add methods to Validate to check whether the index is valid for the array/list/string.
59 [LANG-553] Add TypeUtils class to provide utility code for working with generic types.
60 [LANG-559] Added isAssignableFrom and isInstanceOf validation methods.
61 [LANG-559] Added validState validation method.
62 [LANG-560] New TimedSemaphore class.
63 [LANG-582] Provide an implementation of the ThreadFactory interface.
64 [LANG-588] Create a basic Pair&lt;L, R&gt; class.
65 [LANG-594] DateUtils equal &amp; compare functions up to most significant field.
66 [LANG-601] Add Builder Interface / Update Builders to Implement It.
67 [LANG-609] Support lazy initialization using atomic variables
68 [LANG-610] Extend exception handling in ConcurrentUtils to runtime exceptions.
69 [LANG-614] StringUtils.endsWithAny method
70 [LANG-640] Add normalizeSpace to StringUtils
71 [LANG-644] Provide documentation about the new concurrent package
72 [LANG-649] BooleanUtils.toBooleanObject to support single character input
73 [LANG-651] Add AnnotationUtils
74 [LANG-653] Provide a very basic ConcurrentInitializer implementation
75 [LANG-655] Add StringUtils.defaultIfBlank()
76 [LANG-667] Add a Null-safe compare() method to ObjectUtils
77 [LANG-676] Documented potential NPE if auto-boxing occurs for some BooleanUtils methods
78 [LANG-678] Add support for ConcurrentMap.putIfAbsent()
79 [LANG-692] Add hashCodeMulti varargs method
80
81 REMOVALS IN 3.0
82 ===============
83
84 [LANG-438] Remove @deprecateds.
85 [LANG-492] Remove code handled now by the JDK.
86 [LANG-493] Remove code that does not hold enough value to remain.
87 [LANG-590] Remove JDK 1.2/1.3 bug handling in StringUtils.indexOf(String, String, int).
88 [LANG-673] WordUtils.abbreviate() removed
89 [LANG-691] Removed DateUtils.UTC_TIME_ZONE
90
91 IMPROVEMENTS IN 3.0
92 ===================
93
94 [LANG-290] EnumUtils for JDK 5.0.
95 [LANG-336] Finally start using generics.
96 [LANG-355] StrBuilder should implement CharSequence and Appendable.
97 [LANG-396] Investigate for vararg usages.
98 [LANG-424] Improve Javadoc for StringUtils class.
99 [LANG-458] Refactor Validate.java to eliminate code redundancy.
100 [LANG-479] Document where in SVN trunk is.
101 [LANG-504] bring ArrayUtils.isEmpty to the generics world.
102 [LANG-505] Rewrite StringEscapeUtils.
103 [LANG-507] StringEscapeUtils.unescapeJava should support \u+ notation.
104 [LANG-510] Convert StringUtils API to take CharSequence.
105 [LANG-513] Better EnumUtils.
106 [LANG-528] Mutable classes should implement an appropriately typed Mutable interface.
107 [LANG-539] Compile commons.lang for CDC 1.1/Foundation 1.1.
108 [LANG-540] Make NumericEntityEscaper immutable.
109 [LANG-541] Replace StringBuffer with StringBuilder.
110 [LANG-548] Use Iterable on API instead of Collection.
111 [LANG-551] Replace Range classes with generic version.
112 [LANG-562] Change Maven groupId.
113 [LANG-563] Change Java package name.
114 [LANG-570] Do the test cases really still require main() and suite() methods?.
115 [LANG-579] Add new Validate methods.
116 [LANG-599] ClassUtils.getClass(): Allow Dots as Inner Class Separators.
117 [LANG-605] DefaultExceptionContext overwrites values in recursive situations.
118 [LANG-668] Change ObjectUtils min() &amp; max() functions to use varargs rather than just two parameters
119 [LANG-681] Push down WordUtils to "text" sub-package.
120
121 BUG FIXES IN 3.0
122 ================
123
124 [LANG-11] Depend on JDK 1.5+.
125 [LANG-302] StrBuilder does not implement clone().
126 [LANG-339] StringEscapeUtils.escapeHtml() escapes multibyte characters like Chinese, Japanes, etc.
127 [LANG-369] ExceptionUtils not thread-safe.
128 [LANG-418] Javadoc incorrect for StringUtils.endsWithIgnoreCase.
129 [LANG-428] StringUtils.isAlpha, isAlphanumeric and isNumeric now return false for ""
130 [LANG-439] StringEscapeUtils.escapeHTML() does not escape chars (0x00-0x20).
131 [LANG-448] Lower Ascii Characters don't get encoded by Entities.java.
132 [LANG-468] JDK 1.5 build/runtime failure on LANG-393 (EqualsBuilder).
133 [LANG-474] Fixes for thread safety.
134 [LANG-478] StopWatch does not resist to system time changes.
135 [LANG-480] StringEscapeUtils.escapeHtml incorrectly converts Unicode characters above U+00FFFF into 2 characters.
136 [LANG-481] Possible race-conditions in hashCode of the range classes.
137 [LANG-564] Improve StrLookup API documentation.
138 [LANG-568] @SuppressWarnings("unchecked") is used too generally.
139 [LANG-571] ArrayUtils.add(T[] array, T element) can create unexpected ClassCastException.
140 [LANG-585] exception.DefaultExceptionContext.getFormattedExceptionMessage catches Throwable.
141 [LANG-596] StrSubstitutor should also handle the default properties of a java.util.Properties class
142 [LANG-600] Javadoc is incorrect for public static int lastIndexOf(String str, String searchStr).
143 [LANG-602] ContextedRuntimeException no longer an 'unchecked' exception.
144 [LANG-606] EqualsBuilder causes StackOverflowException.
145 [LANG-608] Some StringUtils methods should take an int character instead of char to use String API features.
146 [LANG-617] StringEscapeUtils.escapeXML() can't process UTF-16 supplementary characters
147 [LANG-624] SystemUtils.getJavaVersionAsFloat throws StringIndexOutOfBoundsException on Android runtime/Dalvik VM
148 [LANG-629] Charset may not be threadsafe, because the HashSet is not synch.
149 [LANG-638] NumberUtils createNumber throws a StringIndexOutOfBoundsException when argument containing "e" and "E" is passed in
150 [LANG-643] Javadoc StringUtils.left() claims to throw on negative len, but doesn't
151 [LANG-645] FastDateFormat.format() outputs incorrect week of year because locale isn't respected
152 [LANG-646] StringEscapeUtils.unescapeJava doesn't handle octal escapes and Unicode with extra u
153 [LANG-656] Example StringUtils.indexOfAnyBut("zzabyycdxx", '') = 0 incorrect
154 [LANG-658] Some Entitys like &amp;Ouml; are not matched properly against its ISO8859-1 representation
155 [LANG-659] EntityArrays typo: {"\u2122", "&amp;minus;"}, // minus sign, U+2212 ISOtech
156 [LANG-66] StringEscaper.escapeXml() escapes characters &gt; 0x7f.
157 [LANG-662] org.apache.commons.lang3.math.Fraction does not reduce (Integer.MIN_VALUE, 2^k)
158 [LANG-663] org.apache.commons.lang3.math.Fraction does not always succeed in multiplyBy and divideBy
159 [LANG-664] NumberUtils.isNumber(String) is not right when the String is "1.1L"
160 [LANG-672] Doc bug in DateUtils#ceiling
161 [LANG-677] DateUtils.isSameLocalTime compares using 12 hour clock and not 24 hour
162 [LANG-685] EqualsBuilder synchronizes on HashCodeBuilder.
163 [LANG-703] StringUtils.join throws NPE when toString returns null for one of objects in collection
164 [LANG-710] StringIndexOutOfBoundsException when calling unescapeHtml4("&amp;#03")
165
166 </source>
167 </p>
168 </section>
169
170 </body>
171 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17
18 <document>
19
20 <properties>
21 <title>Commons Lang - User guide</title>
22 <author email="dev@commons.apache.org">Commons Documentation Team</author>
23 </properties>
24
25 <body>
26 <!-- $Id: userguide.xml 1148224 2011-07-19 08:28:56Z bayard $ -->
27
28 <section name='User guide for Commons "Lang"'>
29 <div align="center">
30 <h1>The Commons <em>Lang</em> Package</h1>
31 <h2>Users Guide</h2>
32 <br />
33 <a href="#Description">[Description]</a>
34 <a href="#lang3.">[lang3.*]</a>
35 <a href="#lang3.builder.">[lang3.builder.*]</a>
36 <a href="#lang3.math.">[lang3.math.*]</a>
37 <a href="#lang3.mutable.">[lang3.mutable.*]</a>
38 <a href="#lang3.text.">[lang3.text.*]</a>
39 <a href="#lang3.time.">[lang3.time.*]</a>
40 <a href="#lang3.concurrent.">[lang3.concurrent.*]</a>
41 <br /><br />
42 </div>
43 </section>
44
45 <section name="Description">
46 <p>The Commons Lang library provides much needed additions to the standard JDK's java.lang package. Very generic, very reusable components for everyday use.</p>
47 <p>The top level package contains various Utils classes, whilst there are various subpackages including math, concurrent and builder. Using the Utils classes is generally simplicity itself. They are the equivalent of global functions in another language, a collection of stand-alone, thread-safe, static methods. In contrast, subpackages may contain interfaces which may have to be implemented or classes which may need to be extended to get the full functionality from the code. They may, however, contain more global-like functions. </p>
48 <p>Lang 3.0 is JDK 1.5+; before that Lang was JDK 1.2+. In both cases you can find features of later JDKs being maintained by us and likely to be removed or modified in favour of the JDK in the next major version. Note that Lang 3.0 uses a different package than its predecessors, allowing it to be used at the same time as an earlier version. </p>
49 <p>You will find deprecated methods as you stroll through the Lang documentation. These are removed in the next major version. </p>
50 <p>Before we begin, it's a good time to mention the Utils classes. They all contain empty public constructors with warnings not to use. This may seem an odd thing to do, but it allows tools like Velocity to access the class as if it were a bean. In other words, yes we know about private constructors and have chosen not to use them. </p>
51 </section>
52
53 <section name="lang3.*">
54 <subsection name="String manipulation - StringUtils, StringEscapeUtils, RandomStringUtils, Tokenizer, WordUtils">
55 <p>Lang has a series of String utilities. The first is StringUtils, oodles and oodles of functions which tweak, transform, squeeze and cuddle java.lang.Strings. In addition to StringUtils, there are a series of other String manipulating classes; RandomStringUtils, StringEscapeUtils and Tokenizer. RandomStringUtils speaks for itself. It's provides ways in which to generate pieces of text, such as might be used for default passwords. StringEscapeUtils contains methods to escape and unescape Java, JavaScript, HTML, XML and SQL. Tokenizer is an improved alternative to java.util.StringTokenizer. </p>
56 <p>These are ideal classes to start using if you're looking to get into Lang. StringUtils' capitalize, substringBetween/Before/After, split and join are good methods to begin with. If you use java.sql.Statements a lot, StringEscapeUtils.escapeSql might be of interest. </p>
57 <p>In addition to these classes, WordUtils is another String manipulator. It works on Strings at the word level, for example WordUtils.capitalize will capitalize every word in a piece of text. WordUtils also contains methods to wrap text. </p>
58 </subsection>
59
60 <subsection name="Character handling - CharSetUtils, CharSet, CharRange, CharUtils">
61 <p>In addition to dealing with Strings, it's also important to deal with chars and Characters. CharUtils exists for this purpose, while CharSetUtils exists for set-manipulation of Strings. Be careful, although CharSetUtils takes an argument of type String, it is only as a set of characters. For example, <code>CharSetUtils.delete("testtest", "tr")</code> will remove all t's and all r's from the String, not just the String "tr". </p>
62 <p>CharRange and CharSet are both used internally by CharSetUtils, and will probaby rarely be used. </p>
63 </subsection>
64
65 <subsection name="JVM interaction - SystemUtils, CharEncoding">
66 <p>SystemUtils is a simple little class which makes it easy to find out information about which platform you are on. For some, this is a necessary evil. It was never something I expected to use myself until I was trying to ensure that Commons Lang itself compiled under JDK 1.2. Having pushed out a few JDK 1.3 bits that had slipped in (<code>Collections.EMPTY_MAP</code> is a classic offender), I then found that one of the Unit Tests was dying mysteriously under JDK 1.2, but ran fine under JDK 1.3. There was no obvious solution and I needed to move onwards, so the simple solution was to wrap that particular test in a <code>if(SystemUtils.isJavaVersionAtLeast(1.3f)) {</code>, make a note and move on. </p>
67 <p>The CharEncoding class is also used to interact with the Java environment and may be used to see which character encodings are supported in a particular environment. </p>
68 </subsection>
69
70 <subsection name="Serialization - SerializationUtils, SerializationException">
71 <p>Serialization doesn't have to be that hard! A simple util class can take away the pain, plus it provides a method to clone an object by unserializing and reserializing, an old Java trick.</p>
72 </subsection>
73
74 <subsection name="Assorted functions - ObjectUtils, ClassUtils, ArrayUtils, BooleanUtils">
75 <p>Would you believe it, ObjectUtils contains handy functions for Objects, mainly null-safe implementations of the methods on java.lang.Object. </p>
76 <p>ClassUtils is largely a set of helper methods for reflection. Of special note are the comparators hidden away in ClassUtils, useful for sorting Class and Package objects by name; however they merely sort alphabetically and don't understand the common habit of sorting <code>java</code> and <code>javax</code> first. </p>
77 <p>Next up, ArrayUtils. This is a big one with many methods and many overloads of these methods so it is probably worth an in depth look here. Before we begin, assume that every method mentioned is overloaded for all the primitives and for Object. Also, the short-hand 'xxx' implies a generic primitive type, but usually also includes Object. </p>
78 <ul>
79 <li>ArrayUtils provides singleton empty arrays for all the basic types. These will largely be of use in the Collections API with its toArray methods, but also will be of use with methods which want to return an empty array on error. </li>
80 <li><code>add(xxx[], xxx)</code> will add a primitive type to an array, resizing the array as you'd expect. Object is also supported. </li>
81 <li><code>clone(xxx[])</code> clones a primitive or Object array. </li>
82 <li><code>contains(xxx[], xxx)</code> searches for a primitive or Object in a primitive or Object array. </li>
83 <li><code>getLength(Object)</code> returns the length of any array or an IllegalArgumentException if the parameter is not an array. <code>hashCode(Object)</code>, <code>equals(Object, Object)</code>, <code>toString(Object)</code> </li>
84 <li><code>indexOf(xxx[], xxx)</code> and <code>indexOf(xxx[], xxx, int)</code> are copies of the classic String methods, but this time for primitive/Object arrays. In addition, a lastIndexOf set of methods exists. </li>
85 <li><code>isEmpty(xxx[])</code> lets you know if an array is zero-sized or null. </li>
86 <li><code>isSameLength(xxx[], xxx[])</code> returns true if the arrays are the same length. </li>
87 <li>Along side the add methods, there are also remove methods of two types. The first type remove the value at an index, <code>remove(xxx[], int)</code>, while the second type remove the first value from the array, <code>remove(xxx[], xxx)</code>. </li>
88 <li>Nearing the end now. The <code>reverse(xxx[])</code> method turns an array around. </li>
89 <li>The <code>subarray(xxx[], int, int)</code> method splices an array out of a larger array. </li>
90 <li>Primitive to primitive wrapper conversion is handled by the <code>toObject(xxx[])</code> and <code>toPrimitive(Xxx[])</code> methods. </li>
91 </ul>
92 <p>Lastly, <code>ArrayUtils.toMap(Object[])</code> is worthy of special note. It is not a heavily overloaded method for working with arrays, but a simple way to create Maps from literals. </p>
93 <h5>Using toMap</h5>
94 <source>
95 Map colorMap = MapUtils.toMap(new String[][] {{
96 {"RED", "#FF0000"},
97 {"GREEN", "#00FF00"},
98 {"BLUE", "#0000FF"}
99 });
100 </source>
101
102 <p>Our final util class is BooleanUtils. It contains various Boolean acting methods, probably of most interest is the <code>BooleanUtils.toBoolean(String)</code> method which turns various positive/negative Strings into a Boolean object, and not just true/false as with Boolean.valueOf. </p>
103 </subsection>
104
105 <subsection name="Flotsam - BitField, Validate">
106 <p>On reaching the end of our package, we are left with a couple of classes that haven't fit any of the topics so far. </p>
107 <p>The BitField class provides a wrapper class around the classic bitmask integer, whilst the Validate class may be used for assertions (remember, we support Java 1.2). </p>
108 </subsection>
109 </section>
110
111 <section name="lang3.builder.*">
112 <!--
113 CompareToBuilder
114 EqualsBuilder
115 HashCodeBuilder
116 ReflectionToStringBuilder
117 StandardToStringStyle
118 ToStringBuilder
119 ToStringStyle
120 -->
121 <p>When you write a hashcode, do you check Bloch's Effective Java? No? You just hack in a quick number? Well HashCodeBuilder will save your day. It, and its buddies (EqualsBuilder, CompareToBuilder, ToStringBuilder), take care of the nasty bits while you focus on the important bits, like which fields will go into making up the hashcode.</p>
122 </section>
123
124 <section name="lang3.math.*">
125 <!--
126 Fraction
127 NumberUtils
128 RandomUtils
129 -->
130 <p>Although Commons-Math also exists, some basic mathematical functions are contained within Lang. These include classes to a Fraction class, various utilities for random numbers, and the flagship class, NumberUtils which contains a handful of classic number functions. </p>
131 <p>There are two aspects of this package I would like to highlight. The first is <code>NumberUtils.createNumber(String)</code>, a method which does its best to convert a String into a Number object. You have no idea what type of Number it will return, so you should call the relevant <code>xxxValue</code> method when you reach the point of needing a number. NumberUtils also has a related <code>isNumber</code> method. </p>
132 </section>
133
134 <section name="lang3.mutable.*">
135 <!--
136 Mutable
137 MutableByte
138 MutableDouble
139 MutableFloat
140 MutableInt
141 MutableLong
142 MutableObject
143 MutableShort
144 -->
145 <p>New in 2.1, the mutable package provides mutable wrappers for primitive values (such as int, long, etc.) and Object. These wrappers are simiar to the wrappers provided by the Java API, but allow the wrapped value to be changed without needing to create a separate wrapper object.
146 </p>
147 </section>
148
149 <section name="lang3.text.*">
150 <!--
151 CompositeFormat
152 StrLookup
153 StrSubstitutor
154 StrBuilder
155 StrMatcher
156 StrTokenizer
157 -->
158 <p>The text package was added in Lang 2.2. It provides, amongst other classes, a replacement for StringBuffer named <code>StrBuilder</code>, a class for substituting variables within a String named <code>StrSubstitutor</code> and a replacement for StringTokenizer named <code>StrTokenizer</code>. While somewhat ungainly, the <code>Str</code> prefix has been used to ensure we don't clash with any current or future standard Java classes. </p>
159 </section>
160
161 <section name="lang3.time.*">
162 <!--
163 DateFormatUtils
164 DateUtils
165 DurationFormatUtils
166 FastDateFormat
167 StopWatch
168 -->
169 <p>Lang 2.0 saw the arrival of a time package. It contains some basic utilities for manipulating time (a delorean, police box and grandfather clock?). These include a StopWatch for simple performance measurements and an optimised FastDateFormat class. </p>
170 <p>New in Lang 2.1 is the DurationFormatUtils class, which provides various methods for formatting durations. </p>
171 </section>
172
173 <section name="lang3.concurrent.*">
174 <p>
175 In Lang 3.0 a new <em>concurrent</em> package was introduced containing
176 interfaces and classes to support programming with multiple threads. Its
177 aim is to serve as an extension of the <em>java.util.concurrent</em>
178 package of the JDK.
179 </p>
180
181 <subsection name="Concurrent initializers">
182 <p>
183 A group of classes deals with the correct creation and initialization of
184 objects that are accessed by multiple threads. All these classes implement
185 the <code>ConcurrentInitializer</code> interface which provides just a
186 single method:
187 </p>
188 <source><![CDATA[
189 public interface ConcurrentInitializer<T> {
190 T get() throws ConcurrentException;
191 }
192 ]]></source>
193 <p>
194 A <code>ConcurrentInitializer</code> produces an object. By calling the
195 <code>get()</code> method the object managed by the initializer can be
196 obtained. There are different implementations of the interface available
197 addressing various use cases:
198 </p>
199 <p>
200 <code>ConstantInitializer</code> is a very straightforward implementation of
201 the <code>ConcurrentInitializer</code> interface: An instance is passed an
202 object when it is constructed. In its <code>get()</code> method it simply
203 returns this object. This is useful, for instance in unit tests or in cases
204 when you want to pass a specific object to a component which expects a
205 <code>ConcurrentInitializer</code>.
206 </p>
207 <p>
208 The <code>LazyInitializer</code> class can be used to defer the creation of
209 an object until it is actually used. This makes sense, for instance, if the
210 creation of the object is expensive and would slow down application startup
211 or if the object is needed only for special executions. <code>LazyInitializer</code>
212 implements the <em>double-check idiom for an instance field</em> as
213 discussed in Joshua Bloch's "Effective Java", 2nd edition, item 71. It
214 uses <strong>volatile</strong> fields to reduce the amount of
215 synchronization. Note that this idiom is appropriate for instance fields
216 only. For <strong>static</strong> fields there are superior alternatives.
217 </p>
218 <p>
219 We provide an example use case to demonstrate the usage of this class: A
220 server application uses multiple worker threads to process client requests.
221 If such a request causes a fatal error, an administrator is to be notified
222 using a special messaging service. We assume that the creation of the
223 messaging service is an expensive operation. So it should only be performed
224 if an error actually occurs. Here is where <code>LazyInitializer</code>
225 comes into play. We create a specialized subclass for creating and
226 initializing an instance of our messaging service. <code>LazyInitializer</code>
227 declares an abstract <code>initialize()</code> method which we have to
228 implement to create the messaging service object:
229 </p>
230 <source><![CDATA[
231 public class MessagingServiceInitializer
232 extends LazyInitializer<MessagingService> {
233 protected MessagingService initialize() throws ConcurrentException {
234 // Do all necessary steps to create and initialize the service object
235 MessagingService service = ...
236
237 return service;
238 }
239 }
240 ]]></source>
241 <p>
242 Now each server thread is passed a reference to a shared instance of our
243 new <code>MessagingServiceInitializer</code> class. The threads run in a
244 loop processing client requests. If an error is detected, the messaging
245 service is obtained from the initializer, and the administrator is
246 notified:
247 </p>
248 <source><![CDATA[
249 public class ServerThread implements Runnable {
250 /** The initializer for obtaining the messaging service. */
251 private final ConcurrentInitializer<MessagingService> initializer;
252
253 public ServerThread(ConcurrentInitializer<MessagingService> init) {
254 initializer = init;
255 }
256
257 public void run() {
258 while (true) {
259 try {
260 // wait for request
261 // process request
262 } catch (FatalServerException ex) {
263 // get messaging service
264 try {
265 MessagingService svc = initializer.get();
266 svc.notifyAdministrator(ex);
267 } catch (ConcurrentException cex) {
268 cex.printStackTrace();
269 }
270 }
271 }
272 }
273 }
274 ]]></source>
275 <p>
276 The <code>AtomicInitializer</code> class is very similar to
277 <code>LazyInitializer</code>. It serves the same purpose: to defer the
278 creation of an object until it is needed. The internal structure is also
279 very similar. Again there is an abstract <code>initialize()</code> method
280 which has to be implemented by concrete subclasses in order to create and
281 initialize the managed object. Actually, in our example above we can turn
282 the <code>MessagingServiceInitializer</code> into an atomic initializer by
283 simply changing the <strong>extends</strong> declaration to refer to
284 <code>AtomicInitializer&lt;MessagingService&gt;</code> as super class.
285 </p>
286 <p>
287 The difference between <code>AtomicInitializer</code> and
288 <code>LazyInitializer</code> is that the former uses classes from the
289 <code>java.util.concurrent.atomic</code> package for its implementation
290 (hence the name). This has the advantage that no synchronization is needed,
291 thus the implementation is usually more efficient than the one of the
292 <code>LazyInitializer</code> class. However, there is one drawback: Under
293 high load, if multiple threads access the initializer concurrently, it is
294 possible that the <code>initialize()</code> method is invoked multiple
295 times. The class guarantees that <code>get()</code> always returns the
296 same object though; so objects created accidently are immideately discarded.
297 </p>
298 <p>
299 With <code>AtomicSafeInitializer</code> there is yet another variant
300 implementing the lazy initializing pattern. Its implementation is close to
301 <code>AtomicInitializer</code>; it also uses atomic variables internally
302 and therefore does not need synchronization. The name &quot;Safe&quot; is
303 derived from the fact that it implements an additional check which guarantees
304 that the <code>initialize()</code> method is called only once. So it
305 behaves exactly in the same way as <code>LazyInitializer</code>.
306 </p>
307 <p>
308 Now, which one of the lazy initializer implementations should you use?
309 First of all we have to state that is is problematic to give general
310 recommendations regarding the performance of these classes. The initializers
311 make use of low-level functionality whose efficiency depends on multiple
312 factors including the target platform and the number of concurrent threads.
313 So developers should make their own benchmarks in scenarios close to their
314 specific use cases. The following statements are rules of thumb which have
315 to be verified in practice.
316 </p>
317 <p>
318 <code>AtomicInitializer</code> is probably the most efficient implementation
319 due to its lack of synchronization and further checks. Its main drawback is
320 that the <code>initialize()</code> method can be called multiple
321 times. In cases where this is not an issue <code>AtomicInitializer</code> is
322 a good choice. <code>AtomicSafeInitializer</code> and
323 <code>LazyInitializer</code> both guarantee that the initialization method
324 is called only once. Because <code>AtomicSafeInitializer</code> does not
325 use synchronization it is probably slightly more efficient than
326 <code>LazyInitializer</code>, but the concrete numbers might depend on the
327 level of concurrency.
328 </p>
329 <p>
330 Another implementation of the <code>ConcurrentInitializer</code> interface
331 is <code>BackgroundInitializer</code>. It is again an abstract base class
332 with an <code>initialize()</code> method that has to be defined by concrete
333 subclasses. The idea of <code>BackgroundInitializer</code> is that it calls
334 the <code>initialize()</code> method in a separate worker thread. An
335 application creates a background initializer and starts it. Then it can
336 continue with its work while the initializer runs in parallel. When the
337 application needs the results of the initializer it calls its
338 <code>get()</code> method. <code>get()</code> blocks until the initialization
339 is complete. This is useful for instance at application startup. Here
340 initialization steps (e.g. reading configuration files, opening a database
341 connection, etc.) can be run in background threads while the application
342 shows a splash screen and constructs its UI.
343 </p>
344 <p>
345 As a concrete example consider an application that has to read the content
346 of a URL - maybe a page with news - which is to be displayed to the user after
347 login. Because loading the data over the network can take some time a
348 specialized implementation of <code>BackgroundInitializer</code> can be
349 created for this purpose:
350 </p>
351 <source><![CDATA[
352 public class URLLoader extends BackgroundInitializer<String> {
353 /** The URL to be loaded. */
354 private final URL url;
355
356 public URLLoader(URL u) {
357 url = u;
358 }
359
360 protected String initialize() throws ConcurrentException {
361 try {
362 InputStream in = url.openStream();
363 // read content into string
364 ...
365 return content;
366 } catch (IOException ioex) {
367 throw new ConcurrentException(ioex);
368 }
369 }
370 }
371 ]]></source>
372 <p>
373 An application creates an instance of <code>URLLoader</code> and starts it.
374 Then it can do other things. When it needs the content of the URL it calls
375 the initializer's <code>get()</code> method:
376 </p>
377 <source><![CDATA[
378 URL url = new URL("http://www.application-home-page.com/");
379 URLLoader loader = new URLLoader(url);
380 loader.start(); // this starts the background initialization
381
382 // do other stuff
383 ...
384 // now obtain the content of the URL
385 String content;
386 try {
387 content = loader.get(); // this may block
388 } catch (ConcurrentException cex) {
389 content = "Error when loading URL " + url;
390 }
391 // display content
392 ]]></source>
393 <p>
394 Related to <code>BackgroundInitializer</code> is the
395 <code>MultiBackgroundInitializer</code> class. As the name implies, this
396 class can handle multiplie initializations in parallel. The basic usage
397 scenario is that a <code>MultiBackgroundInitializer</code> instance is
398 created. Then an arbitrary number of <code>BackgroundInitializer</code>
399 objects is added using the <code>addInitializer()</code> method. When adding
400 an initializer a string has to be provided which is later used to obtain
401 the result for this initializer. When all initializers have been added the
402 <code>start()</code> method is called. This starts processing of all
403 initializers. Later the <code>get()</code> method can be called. It waits
404 until all initializers have finished their initialization. <code>get()</code>
405 returns an object of type <code>MultiBackgroundInitializer.MultiBackgroundInitializerResults</code>.
406 This object provides information about all initializations that have been
407 performed. It can be checked whether a specific initializer was successful
408 or threw an exception. Of course, all initialization results can be queried.
409 </p>
410 <p>
411 With <code>MultiBackgroundInitializer</code> we can extend our example to
412 perform multiple initialization steps. Suppose that in addition to loading
413 a web site we also want to create a JPA entity manager factory and read a
414 configuration file. We assume that corresponding <code>BackgroundInitializer</code>
415 implementations exist. The following example fragment shows the usage of
416 <code>MultiBackgroundInitializer</code> for this purpose:
417 </p>
418 <source><![CDATA[
419 MultiBackgroundInitializer initializer = new MultiBackgroundInitializer();
420 initializer.addInitializer("url", new URLLoader(url));
421 initializer.addInitializer("jpa", new JPAEMFInitializer());
422 initializer.addInitializer("config", new ConfigurationInitializer());
423 initializer.start(); // start background processing
424
425 // do other interesting things in parallel
426 ...
427 // evaluate the results of background initialization
428 MultiBackgroundInitializer.MultiBackgroundInitializerResults results =
429 initializer.get();
430 String urlContent = (String) results.getResultObject("url");
431 EntityManagerFactory emf =
432 (EntityManagerFactory) results.getResultObject("jpa");
433 ...
434 ]]></source>
435 <p>
436 The child initializers are added to the multi initializer and are assigned
437 a unique name. The object returned by the <code>get()</code> method is then
438 queried for the single results using these unique names.
439 </p>
440 <p>
441 If background initializers - including <code>MultiBackgroundInitializer</code>
442 - are created using the standard constructor, they create their own
443 <code>ExecutorService</code> which is used behind the scenes to execute the
444 worker tasks. It is also possible to pass in an <code>ExecutorService</code>
445 when the initializer is constructed. That way client code can configure
446 the <code>ExecutorService</code> according to its specific needs; for
447 instance, the number of threads available could be limited.
448 </p>
449 </subsection>
450
451 <subsection name="Utility classes">
452 <p>
453 Another group of classes in the new <code>concurrent</code> package offers
454 some generic functionality related to concurrency. There is the
455 <code>ConcurrentUtils</code> class with a bunch of static utility methods.
456 One focus of this class is dealing with exceptions thrown by JDK classes.
457 Many JDK classes of the executor framework throw exceptions of type
458 <code>ExecutionException</code> if something goes wrong. The root cause of
459 these exceptions can also be a runtime exception or even an error. In
460 typical Java programming you often do not want to deal with runtime
461 exceptions directly; rather you let them fall through the hierarchy of
462 method invocations until they reach a central exception handler. Checked
463 exceptions in contrast are usually handled close to their occurrence. With
464 <code>ExecutionException</code> this principle is violated. Because it is a
465 checked exception, an application is forced to handle it even if the cause
466 is a runtime exception. So you typically have to inspect the cause of the
467 <code>ExecutionException</code> and test whether it is a checked exception
468 which has to be handled. If this is not the case, the causing exception can
469 be rethrown.
470 </p>
471 <p>
472 The <code>extractCause()</code> method of <code>ConcurrentUtils</code> does
473 this work for you. It is passed an <code>ExecutionException</code> and tests
474 its root cause. If this is an error or a runtime exception, it is directly
475 rethrown. Otherwise, an instance of <code>ConcurrentException</code> is
476 created and initialized with the root cause. (<code>ConcurrentException</code>
477 is a new exception class in the <code>o.a.c.l.concurrent</code> package.)
478 So if you get such a <code>ConcurrentException</code>, you can be sure that
479 the original cause for the <code>ExecutionException</code> was a checked
480 exception. For users who prefer runtime exceptions in general there is also
481 an <code>extractCauseUnchecked()</code> method which behaves like
482 <code>extractCause()</code>, but returns the unchecked exception
483 <code>ConcurrentRuntimeException</code> instead.
484 </p>
485 <p>
486 In addition to the <code>extractCause()</code> methods there are
487 corresponding <code>handleCause()</code> methods. These methods extract the
488 cause of the passed in <code>ExecutionException</code> and throw the
489 resulting <code>ConcurrentException</code> or <code>ConcurrentRuntimeException</code>.
490 This makes it easy to transform an <code>ExecutionException</code> into a
491 <code>ConcurrentException</code> ignoring unchecked exceptions:
492 </p>
493 <source><![CDATA[
494 Future<Object> future = ...;
495 try {
496 Object result = future.get();
497 ...
498 } catch (ExecutionException eex) {
499 ConcurrentUtils.handleCause(eex);
500 }
501 ]]></source>
502 <p>
503 There is also some support for the concurrent initializers introduced in
504 the last sub section. The <code>initialize()</code> method is passed a
505 <code>ConcurrentInitializer</code> object and returns the object created by
506 this initializer. It is null-safe. The <code>initializeUnchecked()</code>
507 method works analogously, but a <code>ConcurrentException</code> throws by the
508 initializer is rethrown as a <code>ConcurrentRuntimeException</code>. This
509 is especially useful if the specific <code>ConcurrentInitializer</code>
510 does not throw checked exceptions. Using this method the code for requesting
511 the object of an initializer becomes less verbose. The direct invocation
512 looks as follows:
513 </p>
514 <source><![CDATA[
515 ConcurrentInitializer<MyClass> initializer = ...;
516 try {
517 MyClass obj = initializer.get();
518 // do something with obj
519 } catch (ConcurrentException cex) {
520 // exception handling
521 }
522 ]]></source>
523 <p>
524 Using the <code>initializeUnchecked()</code> method, this becomes:
525 </p>
526 <source><![CDATA[
527 ConcurrentInitializer<MyClass> initializer = ...;
528 MyClass obj = ConcurrentUtils.initializeUnchecked(initializer);
529 // do something with obj
530 ]]></source>
531 <p>
532 Another utility class deals with the creation of threads. When using the
533 <em>Executor</em> framework new in JDK 1.5 the developer usually does not
534 have to care about creating threads; the executors create the threads they
535 need on demand. However, sometimes it is desired to set some properties of
536 the newly created worker threads. This is possible through the
537 <code>ThreadFactory</code> interface; an implementation of this interface
538 has to be created and pased to an executor on creation time. Currently, the
539 JDK does not provide an implementation of <code>ThreadFactory</code>, so
540 one has to start from scratch.
541 </p>
542 <p>
543 With <code>BasicThreadFactory</code> Commons Lang has an implementation of
544 <code>ThreadFactory</code> that works out of the box for many common use
545 cases. For instance, it is possible to set a naming pattern for the new
546 threads, set the daemon flag and a priority, or install a handler for
547 uncaught exceptions. Instances of <code>BasicThreadFactory</code> are
548 created and configured using the nested <code>Builder</code> class. The
549 following example shows a typical usage scenario:
550 </p>
551 <source><![CDATA[
552 BasicThreadFactory factory = new BasicThreadFactory.Builder()
553 .namingPattern("worker-thread-%d")
554 .daemon(true)
555 .uncaughtExceptionHandler(myHandler)
556 .build();
557 ExecutorService exec = Executors.newSingleThreadExecutor(factory);
558 ]]></source>
559 <p>
560 The nested <code>Builder</code> class defines some methods for configuring
561 the new <code>BasicThreadFactory</code> instance. Objects of this class are
562 immutable, so these attributes cannot be changed later. The naming pattern
563 is a string which can be passed to <code>String.format()</code>. The
564 placeholder <em>%d</em> is replaced by an increasing counter value. An
565 instance can wrap another <code>ThreadFactory</code> implementation; this
566 is achieved by calling the builder's <code>wrappedFactory()</code> method.
567 This factory is then used for creating new threads; after that the specific
568 attributes are applied to the new thread. If no wrapped factory is set, the
569 default factory provided by the JDK is used.
570 </p>
571 </subsection>
572
573 <subsection name="Synchronization objects">
574 <p>
575 The <code>concurrent</code> package also provides some support for specific
576 synchronization problems with threads.
577 </p>
578 <p>
579 <code>TimedSemaphore</code> allows restricted access to a resource in a
580 given time frame. Similar to a semaphore, a number of permits can be
581 acquired. What is new is the fact that the permits available are related to
582 a given time unit. For instance, the timed semaphore can be configured to
583 allow 10 permits in a second. Now multiple threads access the semaphore
584 and call its <code>acquire()</code> method. The semaphore keeps track about
585 the number of granted permits in the current time frame. Only 10 calls are
586 allowd; if there are further callers, they are blocked until the time
587 frame (one second in this example) is over. Then all blocking threads are
588 released, and the counter of available permits is reset to 0. So the game
589 can start anew.
590 </p>
591 <p>
592 What are use cases for <code>TimedSemaphore</code>? One example is to
593 artificially limit the load produced by multiple threads. Consider a batch
594 application accessing a database to extract statistical data. The
595 application runs multiple threads which issue database queries in parallel
596 and perform some calculation on the results. If the database to be processed
597 is huge and is also used by a production system, multiple factors have to be
598 balanced: On one hand, the time required for the statistical evaluation
599 should not take too long. Therefore you will probably use a larger number
600 of threads because most of its life time a thread will just wait for the
601 database to return query results. On the other hand, the load on the
602 database generated by all these threads should be limited so that the
603 responsiveness of the production system is not affected. With a
604 <code>TimedSemaphore</code> object this can be achieved. The semaphore can
605 be configured to allow e.g. 100 queries per second. After these queries
606 have been sent to the database the threads have to wait until the second is
607 over - then they can query again. By fine-tuning the limit enforced by the
608 semaphore a good balance between performance and database load can be
609 established. It is even possible to change the number of available permits
610 at runtime. So this number can be reduced during the typical working hours
611 and increased at night.
612 </p>
613 <p>
614 The following code examples demonstrate parts of the implementation of such
615 a scenario. First the batch application has to create an instance of
616 <code>TimedSemaphore</code> and to initialize its properties with default
617 values:
618 </p>
619 <source><![CDATA[
620 TimedSemaphore semaphore = new TimedSemaphore(1, TimeUnit.SECONDS, 100);
621 ]]></source>
622 <p>
623 Here we specify that the semaphore should allow 100 permits in one second.
624 This is effectively the limit of database queries per second in our
625 example use case. Next the server threads issuing database queries and
626 performing statistical operations can be initialized. They are passed a
627 reference to the semaphore at creation time. Before they execute a query
628 they have to acquire a permit.
629 </p>
630 <source><![CDATA[
631 public class StatisticsTask implements Runnable {
632 /** The semaphore for limiting database load. */
633 private final TimedSemaphore semaphore;
634
635 public StatisticsTask(TimedSemaphore sem, Connection con) {
636 semaphore = sem;
637 ...
638 }
639
640 /**
641 * The main processing method. Executes queries and evaluates their results.
642 */
643 public void run() {
644 try {
645 while (!isDone()) {
646 semaphore.acquire(); // enforce the load limit
647
648 executeAndEvaluateQuery();
649 }
650 } catch (InterruptedException iex) {
651 // fall through
652 }
653 }
654 }
655 ]]></source>
656 <p>
657 The important line here is the call to <code>semaphore.acquire()</code>.
658 If the number of permits in the current time frame has not yet been reached,
659 the call returns immediately. Otherwise, it blocks until the end of the
660 time frame. The last piece missing is a scheduler service which adapts the
661 number of permits allowed by the semaphore according to the time of day. We
662 assume that this service is pretty simple and knows only two different time
663 slots: working shift and night shift. The service is triggered periodically.
664 It then determines the current time slot and configures the timed semaphore
665 accordingly.
666 </p>
667 <source><![CDATA[
668 public class SchedulerService {
669 /** The semaphore for limiting database load. */
670 private final TimedSemaphore semaphore;
671 ...
672
673 /**
674 * Configures the timed semaphore based on the current time of day. This
675 * method is called periodically.
676 */
677 public void configureTimedSemaphore() {
678 int limit;
679 if (isWorkshift()) {
680 limit = 50; // low database load
681 } else {
682 limit = 250; // high database load
683 }
684
685 semaphore.setLimit(limit);
686 }
687 }
688 ]]></source>
689 <p>
690 With the <code>setLimit()</code> method the number of permits allowed for
691 a time frame can be changed. There are some other methods for querying the
692 internal state of a timed semaphore. Also some statistical data is available,
693 e.g. the average number of <code>acquire()</code> calls per time frame. When
694 a timed semaphore is no more needed, its <code>shutdown()</code> method has
695 to be called.
696 </p>
697 </subsection>
698 </section>
699 </body>
700 </document>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import static java.lang.annotation.ElementType.FIELD;
19 import static java.lang.annotation.RetentionPolicy.RUNTIME;
20 import static org.apache.commons.lang3.AnnotationUtilsTest.Stooge.CURLY;
21 import static org.apache.commons.lang3.AnnotationUtilsTest.Stooge.LARRY;
22 import static org.apache.commons.lang3.AnnotationUtilsTest.Stooge.MOE;
23 import static org.apache.commons.lang3.AnnotationUtilsTest.Stooge.SHEMP;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertTrue;
27
28 import java.lang.annotation.ElementType;
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.Target;
31 import java.lang.reflect.Array;
32 import java.lang.reflect.Field;
33 import java.lang.reflect.InvocationHandler;
34 import java.lang.reflect.Method;
35 import java.lang.reflect.Proxy;
36 import java.util.Collection;
37 import java.util.Map;
38
39 import org.junit.Before;
40 import org.junit.Test;
41
42 /**
43 * @version $Id: AnnotationUtilsTest.java 1132388 2011-06-05 12:44:13Z sebb $
44 */
45 public class AnnotationUtilsTest {
46 @TestAnnotation(
47 booleanValue = false,
48 booleanValues = { false },
49 byteValue = 0,
50 byteValues = { 0 },
51 charValue = 0,
52 charValues = { 0 },
53 doubleValue = 0,
54 doubleValues = { 0 },
55 floatValue = 0,
56 floatValues = { 0 },
57 intValue = 0,
58 intValues = { 0 },
59 longValue = 0,
60 longValues = { 0 },
61 nest = @NestAnnotation(
62 booleanValue = false,
63 booleanValues = { false },
64 byteValue = 0,
65 byteValues = { 0 },
66 charValue = 0,
67 charValues = { 0 },
68 doubleValue = 0,
69 doubleValues = { 0 },
70 floatValue = 0,
71 floatValues = { 0 },
72 intValue = 0,
73 intValues = { 0 },
74 longValue = 0,
75 longValues = { 0 },
76 shortValue = 0,
77 shortValues = { 0 },
78 stooge = CURLY,
79 stooges = { MOE, LARRY, SHEMP },
80 string = "",
81 strings = { "" },
82 type = Object.class,
83 types = { Object.class }
84 ),
85 nests = {
86 @NestAnnotation(
87 booleanValue = false,
88 booleanValues = { false },
89 byteValue = 0,
90 byteValues = { 0 },
91 charValue = 0,
92 charValues = { 0 },
93 doubleValue = 0,
94 doubleValues = { 0 },
95 floatValue = 0,
96 floatValues = { 0 },
97 intValue = 0,
98 intValues = { 0 },
99 longValue = 0,
100 longValues = { 0 },
101 shortValue = 0,
102 shortValues = { 0 },
103 stooge = CURLY,
104 stooges = { MOE, LARRY, SHEMP },
105 string = "",
106 strings = { "" },
107 type = Object[].class,
108 types = { Object[].class }
109 )
110 },
111 shortValue = 0,
112 shortValues = { 0 },
113 stooge = SHEMP,
114 stooges = { MOE, LARRY, CURLY },
115 string = "",
116 strings = { "" },
117 type = Object.class,
118 types = { Object.class }
119 )
120 public Object dummy1;
121
122 @TestAnnotation(
123 booleanValue = false,
124 booleanValues = { false },
125 byteValue = 0,
126 byteValues = { 0 },
127 charValue = 0,
128 charValues = { 0 },
129 doubleValue = 0,
130 doubleValues = { 0 },
131 floatValue = 0,
132 floatValues = { 0 },
133 intValue = 0,
134 intValues = { 0 },
135 longValue = 0,
136 longValues = { 0 },
137 nest = @NestAnnotation(
138 booleanValue = false,
139 booleanValues = { false },
140 byteValue = 0,
141 byteValues = { 0 },
142 charValue = 0,
143 charValues = { 0 },
144 doubleValue = 0,
145 doubleValues = { 0 },
146 floatValue = 0,
147 floatValues = { 0 },
148 intValue = 0,
149 intValues = { 0 },
150 longValue = 0,
151 longValues = { 0 },
152 shortValue = 0,
153 shortValues = { 0 },
154 stooge = CURLY,
155 stooges = { MOE, LARRY, SHEMP },
156 string = "",
157 strings = { "" },
158 type = Object.class,
159 types = { Object.class }
160 ),
161 nests = {
162 @NestAnnotation(
163 booleanValue = false,
164 booleanValues = { false },
165 byteValue = 0,
166 byteValues = { 0 },
167 charValue = 0,
168 charValues = { 0 },
169 doubleValue = 0,
170 doubleValues = { 0 },
171 floatValue = 0,
172 floatValues = { 0 },
173 intValue = 0,
174 intValues = { 0 },
175 longValue = 0,
176 longValues = { 0 },
177 shortValue = 0,
178 shortValues = { 0 },
179 stooge = CURLY,
180 stooges = { MOE, LARRY, SHEMP },
181 string = "",
182 strings = { "" },
183 type = Object[].class,
184 types = { Object[].class }
185 )
186 },
187 shortValue = 0,
188 shortValues = { 0 },
189 stooge = SHEMP,
190 stooges = { MOE, LARRY, CURLY },
191 string = "",
192 strings = { "" },
193 type = Object.class,
194 types = { Object.class }
195 )
196 public Object dummy2;
197
198 @TestAnnotation(
199 booleanValue = false,
200 booleanValues = { false },
201 byteValue = 0,
202 byteValues = { 0 },
203 charValue = 0,
204 charValues = { 0 },
205 doubleValue = 0,
206 doubleValues = { 0 },
207 floatValue = 0,
208 floatValues = { 0 },
209 intValue = 0,
210 intValues = { 0 },
211 longValue = 0,
212 longValues = { 0 },
213 nest = @NestAnnotation(
214 booleanValue = false,
215 booleanValues = { false },
216 byteValue = 0,
217 byteValues = { 0 },
218 charValue = 0,
219 charValues = { 0 },
220 doubleValue = 0,
221 doubleValues = { 0 },
222 floatValue = 0,
223 floatValues = { 0 },
224 intValue = 0,
225 intValues = { 0 },
226 longValue = 0,
227 longValues = { 0 },
228 shortValue = 0,
229 shortValues = { 0 },
230 stooge = CURLY,
231 stooges = { MOE, LARRY, SHEMP },
232 string = "",
233 strings = { "" },
234 type = Object.class,
235 types = { Object.class }
236 ),
237 nests = {
238 @NestAnnotation(
239 booleanValue = false,
240 booleanValues = { false },
241 byteValue = 0,
242 byteValues = { 0 },
243 charValue = 0,
244 charValues = { 0 },
245 doubleValue = 0,
246 doubleValues = { 0 },
247 floatValue = 0,
248 floatValues = { 0 },
249 intValue = 0,
250 intValues = { 0 },
251 longValue = 0,
252 longValues = { 0 },
253 shortValue = 0,
254 shortValues = { 0 },
255 stooge = CURLY,
256 stooges = { MOE, LARRY, SHEMP },
257 string = "",
258 strings = { "" },
259 type = Object[].class,
260 types = { Object[].class }
261 ),
262 //add a second NestAnnotation to break equality:
263 @NestAnnotation(
264 booleanValue = false,
265 booleanValues = { false },
266 byteValue = 0,
267 byteValues = { 0 },
268 charValue = 0,
269 charValues = { 0 },
270 doubleValue = 0,
271 doubleValues = { 0 },
272 floatValue = 0,
273 floatValues = { 0 },
274 intValue = 0,
275 intValues = { 0 },
276 longValue = 0,
277 longValues = { 0 },
278 shortValue = 0,
279 shortValues = { 0 },
280 stooge = CURLY,
281 stooges = { MOE, LARRY, SHEMP },
282 string = "",
283 strings = { "" },
284 type = Object[].class,
285 types = { Object[].class }
286 )
287 },
288 shortValue = 0,
289 shortValues = { 0 },
290 stooge = SHEMP,
291 stooges = { MOE, LARRY, CURLY },
292 string = "",
293 strings = { "" },
294 type = Object.class,
295 types = { Object.class }
296 )
297 public Object dummy3;
298
299 @NestAnnotation(
300 booleanValue = false,
301 booleanValues = { false },
302 byteValue = 0,
303 byteValues = { 0 },
304 charValue = 0,
305 charValues = { 0 },
306 doubleValue = 0,
307 doubleValues = { 0 },
308 floatValue = 0,
309 floatValues = { 0 },
310 intValue = 0,
311 intValues = { 0 },
312 longValue = 0,
313 longValues = { 0 },
314 shortValue = 0,
315 shortValues = { 0 },
316 stooge = CURLY,
317 stooges = { MOE, LARRY, SHEMP },
318 string = "",
319 strings = { "" },
320 type = Object[].class,
321 types = { Object[].class }
322 )
323 public Object dummy4;
324
325 @Target(FIELD)
326 @Retention(RUNTIME)
327 public @interface TestAnnotation {
328 String string();
329 String[] strings();
330 Class<?> type();
331 Class<?>[] types();
332 byte byteValue();
333 byte[] byteValues();
334 short shortValue();
335 short[] shortValues();
336 int intValue();
337 int[] intValues();
338 char charValue();
339 char[] charValues();
340 long longValue();
341 long[] longValues();
342 float floatValue();
343 float[] floatValues();
344 double doubleValue();
345 double[] doubleValues();
346 boolean booleanValue();
347 boolean[] booleanValues();
348 Stooge stooge();
349 Stooge[] stooges();
350 NestAnnotation nest();
351 NestAnnotation[] nests();
352 }
353
354 public @interface NestAnnotation {
355 String string();
356 String[] strings();
357 Class<?> type();
358 Class<?>[] types();
359 byte byteValue();
360 byte[] byteValues();
361 short shortValue();
362 short[] shortValues();
363 int intValue();
364 int[] intValues();
365 char charValue();
366 char[] charValues();
367 long longValue();
368 long[] longValues();
369 float floatValue();
370 float[] floatValues();
371 double doubleValue();
372 double[] doubleValues();
373 boolean booleanValue();
374 boolean[] booleanValues();
375 Stooge stooge();
376 Stooge[] stooges();
377 }
378
379 public static enum Stooge {
380 MOE, LARRY, CURLY, JOE, SHEMP;
381 }
382
383 private Field field1;
384 private Field field2;
385 private Field field3;
386 private Field field4;
387
388 @Before
389 public void setup() throws Exception {
390 field1 = getClass().getDeclaredField("dummy1");
391 field2 = getClass().getDeclaredField("dummy2");
392 field3 = getClass().getDeclaredField("dummy3");
393 field4 = getClass().getDeclaredField("dummy4");
394 }
395
396 @Test
397 public void testEquivalence() {
398 assertTrue(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field2.getAnnotation(TestAnnotation.class)));
399 assertTrue(AnnotationUtils.equals(field2.getAnnotation(TestAnnotation.class), field1.getAnnotation(TestAnnotation.class)));
400 }
401
402 @Test
403 public void testSameInstance() {
404 assertTrue(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field1.getAnnotation(TestAnnotation.class)));
405 }
406
407 @Test
408 public void testNonEquivalentAnnotationsOfSameType() {
409 assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field3.getAnnotation(TestAnnotation.class)));
410 assertFalse(AnnotationUtils.equals(field3.getAnnotation(TestAnnotation.class), field1.getAnnotation(TestAnnotation.class)));
411 }
412
413 @Test
414 public void testAnnotationsOfDifferingTypes() {
415 assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field4.getAnnotation(NestAnnotation.class)));
416 assertFalse(AnnotationUtils.equals(field4.getAnnotation(NestAnnotation.class), field1.getAnnotation(TestAnnotation.class)));
417 }
418
419 @Test
420 public void testOneArgNull() {
421 assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), null));
422 assertFalse(AnnotationUtils.equals(null, field1.getAnnotation(TestAnnotation.class)));
423 }
424
425 @Test
426 public void testBothArgsNull() {
427 assertTrue(AnnotationUtils.equals(null, null));
428 }
429
430 @Test
431 public void testIsValidAnnotationMemberType() {
432 for (Class<?> type : new Class[] { byte.class, short.class, int.class, char.class,
433 long.class, float.class, double.class, boolean.class, String.class, Class.class,
434 NestAnnotation.class, TestAnnotation.class, Stooge.class, ElementType.class }) {
435 assertTrue(AnnotationUtils.isValidAnnotationMemberType(type));
436 assertTrue(AnnotationUtils.isValidAnnotationMemberType(Array.newInstance(type, 0)
437 .getClass()));
438 }
439 for (Class<?> type : new Class[] { Object.class, Map.class, Collection.class }) {
440 assertFalse(AnnotationUtils.isValidAnnotationMemberType(type));
441 assertFalse(AnnotationUtils.isValidAnnotationMemberType(Array.newInstance(type, 0)
442 .getClass()));
443 }
444 }
445
446 @Test(timeout = 666000)
447 public void testGeneratedAnnotationEquivalentToRealAnnotation() throws Exception {
448 final Test real = getClass().getDeclaredMethod(
449 "testGeneratedAnnotationEquivalentToRealAnnotation").getAnnotation(Test.class);
450
451 InvocationHandler generatedTestInvocationHandler = new InvocationHandler() {
452
453 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
454 if ("equals".equals(method.getName()) && method.getParameterTypes().length == 1) {
455 return Boolean.valueOf(proxy == args[0]);
456 }
457 if ("hashCode".equals(method.getName()) && method.getParameterTypes().length == 0) {
458 return Integer.valueOf(System.identityHashCode(proxy));
459 }
460 if ("toString".equals(method.getName()) && method.getParameterTypes().length == 0) {
461 return "Test proxy";
462 }
463 return method.invoke(real, args);
464 }
465 };
466
467 Test generated = (Test) Proxy.newProxyInstance(Thread.currentThread()
468 .getContextClassLoader(), new Class[] { Test.class },
469 generatedTestInvocationHandler);
470 assertTrue(real.equals(generated));
471 assertFalse(generated.equals(real));
472 assertTrue(AnnotationUtils.equals(generated, real));
473 assertTrue(AnnotationUtils.equals(real, generated));
474
475 Test generated2 = (Test) Proxy.newProxyInstance(Thread.currentThread()
476 .getContextClassLoader(), new Class[] { Test.class },
477 generatedTestInvocationHandler);
478 assertFalse(generated.equals(generated2));
479 assertFalse(generated2.equals(generated));
480 assertTrue(AnnotationUtils.equals(generated, generated2));
481 assertTrue(AnnotationUtils.equals(generated2, generated));
482 }
483
484 @Test(timeout = 666000)
485 public void testHashCode() throws Exception {
486 final Test test = getClass().getDeclaredMethod("testHashCode").getAnnotation(Test.class);
487 assertEquals(test.hashCode(), AnnotationUtils.hashCode(test));
488 final TestAnnotation testAnnotation1 = field1.getAnnotation(TestAnnotation.class);
489 assertEquals(testAnnotation1.hashCode(), AnnotationUtils.hashCode(testAnnotation1));
490 final TestAnnotation testAnnotation3 = field3.getAnnotation(TestAnnotation.class);
491 assertEquals(testAnnotation3.hashCode(), AnnotationUtils.hashCode(testAnnotation3));
492 }
493
494 @Test(timeout = 666000)
495 public void testToString() throws Exception {
496 final Test testAnno = getClass().getDeclaredMethod("testToString")
497 .getAnnotation(Test.class);
498 String toString = AnnotationUtils.toString(testAnno);
499 assertTrue(toString.startsWith("@org.junit.Test("));
500 assertTrue(toString.endsWith(")"));
501 assertTrue(toString.contains("expected=class org.junit.Test$None"));
502 assertTrue(toString.contains("timeout=666000"));
503 assertTrue(toString.contains(", "));
504 }
505
506 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3;
18
19 import java.util.Arrays;
20
21 import junit.framework.TestCase;
22
23 /**
24 * Tests ArrayUtils add methods.
25 *
26 * @version $Id: ArrayUtilsAddTest.java 1153490 2011-08-03 13:53:35Z ggregory $
27 */
28 public class ArrayUtilsAddTest extends TestCase {
29
30 public void testJira567(){
31 Number[] n;
32 // Valid array construction
33 n = ArrayUtils.addAll(new Number[]{Integer.valueOf(1)}, new Long[]{Long.valueOf(2)});
34 assertEquals(2,n.length);
35 assertEquals(Number.class,n.getClass().getComponentType());
36 try {
37 // Invalid - can't store Long in Integer array
38 n = ArrayUtils.addAll(new Integer[]{Integer.valueOf(1)}, new Long[]{Long.valueOf(2)});
39 fail("Should have generated IllegalArgumentException");
40 } catch (IllegalArgumentException expected) {
41 }
42 }
43
44 public void testAddObjectArrayBoolean() {
45 boolean[] newArray;
46 newArray = ArrayUtils.add((boolean[])null, false);
47 assertTrue(Arrays.equals(new boolean[]{false}, newArray));
48 assertEquals(Boolean.TYPE, newArray.getClass().getComponentType());
49 newArray = ArrayUtils.add((boolean[])null, true);
50 assertTrue(Arrays.equals(new boolean[]{true}, newArray));
51 assertEquals(Boolean.TYPE, newArray.getClass().getComponentType());
52 boolean[] array1 = new boolean[]{true, false, true};
53 newArray = ArrayUtils.add(array1, false);
54 assertTrue(Arrays.equals(new boolean[]{true, false, true, false}, newArray));
55 assertEquals(Boolean.TYPE, newArray.getClass().getComponentType());
56 }
57
58 public void testAddObjectArrayByte() {
59 byte[] newArray;
60 newArray = ArrayUtils.add((byte[])null, (byte)0);
61 assertTrue(Arrays.equals(new byte[]{0}, newArray));
62 assertEquals(Byte.TYPE, newArray.getClass().getComponentType());
63 newArray = ArrayUtils.add((byte[])null, (byte)1);
64 assertTrue(Arrays.equals(new byte[]{1}, newArray));
65 assertEquals(Byte.TYPE, newArray.getClass().getComponentType());
66 byte[] array1 = new byte[]{1, 2, 3};
67 newArray = ArrayUtils.add(array1, (byte)0);
68 assertTrue(Arrays.equals(new byte[]{1, 2, 3, 0}, newArray));
69 assertEquals(Byte.TYPE, newArray.getClass().getComponentType());
70 newArray = ArrayUtils.add(array1, (byte)4);
71 assertTrue(Arrays.equals(new byte[]{1, 2, 3, 4}, newArray));
72 assertEquals(Byte.TYPE, newArray.getClass().getComponentType());
73 }
74
75 public void testAddObjectArrayChar() {
76 char[] newArray;
77 newArray = ArrayUtils.add((char[])null, (char)0);
78 assertTrue(Arrays.equals(new char[]{0}, newArray));
79 assertEquals(Character.TYPE, newArray.getClass().getComponentType());
80 newArray = ArrayUtils.add((char[])null, (char)1);
81 assertTrue(Arrays.equals(new char[]{1}, newArray));
82 assertEquals(Character.TYPE, newArray.getClass().getComponentType());
83 char[] array1 = new char[]{1, 2, 3};
84 newArray = ArrayUtils.add(array1, (char)0);
85 assertTrue(Arrays.equals(new char[]{1, 2, 3, 0}, newArray));
86 assertEquals(Character.TYPE, newArray.getClass().getComponentType());
87 newArray = ArrayUtils.add(array1, (char)4);
88 assertTrue(Arrays.equals(new char[]{1, 2, 3, 4}, newArray));
89 assertEquals(Character.TYPE, newArray.getClass().getComponentType());
90 }
91
92 public void testAddObjectArrayDouble() {
93 double[] newArray;
94 newArray = ArrayUtils.add((double[])null, 0);
95 assertTrue(Arrays.equals(new double[]{0}, newArray));
96 assertEquals(Double.TYPE, newArray.getClass().getComponentType());
97 newArray = ArrayUtils.add((double[])null, 1);
98 assertTrue(Arrays.equals(new double[]{1}, newArray));
99 assertEquals(Double.TYPE, newArray.getClass().getComponentType());
100 double[] array1 = new double[]{1, 2, 3};
101 newArray = ArrayUtils.add(array1, 0);
102 assertTrue(Arrays.equals(new double[]{1, 2, 3, 0}, newArray));
103 assertEquals(Double.TYPE, newArray.getClass().getComponentType());
104 newArray = ArrayUtils.add(array1, 4);
105 assertTrue(Arrays.equals(new double[]{1, 2, 3, 4}, newArray));
106 assertEquals(Double.TYPE, newArray.getClass().getComponentType());
107 }
108
109 public void testAddObjectArrayFloat() {
110 float[] newArray;
111 newArray = ArrayUtils.add((float[])null, 0);
112 assertTrue(Arrays.equals(new float[]{0}, newArray));
113 assertEquals(Float.TYPE, newArray.getClass().getComponentType());
114 newArray = ArrayUtils.add((float[])null, 1);
115 assertTrue(Arrays.equals(new float[]{1}, newArray));
116 assertEquals(Float.TYPE, newArray.getClass().getComponentType());
117 float[] array1 = new float[]{1, 2, 3};
118 newArray = ArrayUtils.add(array1, 0);
119 assertTrue(Arrays.equals(new float[]{1, 2, 3, 0}, newArray));
120 assertEquals(Float.TYPE, newArray.getClass().getComponentType());
121 newArray = ArrayUtils.add(array1, 4);
122 assertTrue(Arrays.equals(new float[]{1, 2, 3, 4}, newArray));
123 assertEquals(Float.TYPE, newArray.getClass().getComponentType());
124 }
125
126 public void testAddObjectArrayInt() {
127 int[] newArray;
128 newArray = ArrayUtils.add((int[])null, 0);
129 assertTrue(Arrays.equals(new int[]{0}, newArray));
130 assertEquals(Integer.TYPE, newArray.getClass().getComponentType());
131 newArray = ArrayUtils.add((int[])null, 1);
132 assertTrue(Arrays.equals(new int[]{1}, newArray));
133 assertEquals(Integer.TYPE, newArray.getClass().getComponentType());
134 int[] array1 = new int[]{1, 2, 3};
135 newArray = ArrayUtils.add(array1, 0);
136 assertTrue(Arrays.equals(new int[]{1, 2, 3, 0}, newArray));
137 assertEquals(Integer.TYPE, newArray.getClass().getComponentType());
138 newArray = ArrayUtils.add(array1, 4);
139 assertTrue(Arrays.equals(new int[]{1, 2, 3, 4}, newArray));
140 assertEquals(Integer.TYPE, newArray.getClass().getComponentType());
141 }
142
143 public void testAddObjectArrayLong() {
144 long[] newArray;
145 newArray = ArrayUtils.add((long[])null, 0);
146 assertTrue(Arrays.equals(new long[]{0}, newArray));
147 assertEquals(Long.TYPE, newArray.getClass().getComponentType());
148 newArray = ArrayUtils.add((long[])null, 1);
149 assertTrue(Arrays.equals(new long[]{1}, newArray));
150 assertEquals(Long.TYPE, newArray.getClass().getComponentType());
151 long[] array1 = new long[]{1, 2, 3};
152 newArray = ArrayUtils.add(array1, 0);
153 assertTrue(Arrays.equals(new long[]{1, 2, 3, 0}, newArray));
154 assertEquals(Long.TYPE, newArray.getClass().getComponentType());
155 newArray = ArrayUtils.add(array1, 4);
156 assertTrue(Arrays.equals(new long[]{1, 2, 3, 4}, newArray));
157 assertEquals(Long.TYPE, newArray.getClass().getComponentType());
158 }
159
160 public void testAddObjectArrayShort() {
161 short[] newArray;
162 newArray = ArrayUtils.add((short[])null, (short)0);
163 assertTrue(Arrays.equals(new short[]{0}, newArray));
164 assertEquals(Short.TYPE, newArray.getClass().getComponentType());
165 newArray = ArrayUtils.add((short[])null, (short)1);
166 assertTrue(Arrays.equals(new short[]{1}, newArray));
167 assertEquals(Short.TYPE, newArray.getClass().getComponentType());
168 short[] array1 = new short[]{1, 2, 3};
169 newArray = ArrayUtils.add(array1, (short)0);
170 assertTrue(Arrays.equals(new short[]{1, 2, 3, 0}, newArray));
171 assertEquals(Short.TYPE, newArray.getClass().getComponentType());
172 newArray = ArrayUtils.add(array1, (short)4);
173 assertTrue(Arrays.equals(new short[]{1, 2, 3, 4}, newArray));
174 assertEquals(Short.TYPE, newArray.getClass().getComponentType());
175 }
176
177 public void testAddObjectArrayObject() {
178 Object[] newArray;
179
180 //show that not casting is okay
181 newArray = ArrayUtils.add((Object[])null, "a");
182 assertTrue(Arrays.equals((new String[]{"a"}), newArray));
183 assertTrue(Arrays.equals((new Object[]{"a"}), newArray));
184 assertEquals(String.class, newArray.getClass().getComponentType());
185
186 //show that not casting to Object[] is okay and will assume String based on "a"
187 String[] newStringArray = ArrayUtils.add(null, "a");
188 assertTrue(Arrays.equals((new String[]{"a"}), newStringArray));
189 assertTrue(Arrays.equals((new Object[]{"a"}), newStringArray));
190 assertEquals(String.class, newStringArray.getClass().getComponentType());
191
192 String[] stringArray1 = new String[]{"a", "b", "c"};
193 newArray = ArrayUtils.add(stringArray1, null);
194 assertTrue(Arrays.equals((new String[]{"a", "b", "c", null}), newArray));
195 assertEquals(String.class, newArray.getClass().getComponentType());
196
197 newArray = ArrayUtils.add(stringArray1, "d");
198 assertTrue(Arrays.equals((new String[]{"a", "b", "c", "d"}), newArray));
199 assertEquals(String.class, newArray.getClass().getComponentType());
200
201 Number[] numberArray1 = new Number[]{Integer.valueOf(1), Double.valueOf(2)};
202 newArray = ArrayUtils.add(numberArray1, Float.valueOf(3));
203 assertTrue(Arrays.equals((new Number[]{Integer.valueOf(1), Double.valueOf(2), Float.valueOf(3)}), newArray));
204 assertEquals(Number.class, newArray.getClass().getComponentType());
205
206 numberArray1 = null;
207 newArray = ArrayUtils.add(numberArray1, Float.valueOf(3));
208 assertTrue(Arrays.equals((new Float[]{Float.valueOf(3)}), newArray));
209 assertEquals(Float.class, newArray.getClass().getComponentType());
210 }
211
212 public void testLANG571(){
213 String[] stringArray=null;
214 String aString=null;
215 try {
216 @SuppressWarnings("unused")
217 String[] sa = ArrayUtils.add(stringArray, aString);
218 fail("Should have caused IllegalArgumentException");
219 } catch (IllegalArgumentException iae){
220 //expected
221 }
222 try {
223 @SuppressWarnings("unused")
224 String[] sa = ArrayUtils.add(stringArray, 0, aString);
225 fail("Should have caused IllegalArgumentException");
226 } catch (IllegalArgumentException iae){
227 //expected
228 }
229 }
230
231 public void testAddObjectArrayToObjectArray() {
232 assertNull(ArrayUtils.addAll((Object[]) null, (Object[]) null));
233 Object[] newArray;
234 String[] stringArray1 = new String[]{"a", "b", "c"};
235 String[] stringArray2 = new String[]{"1", "2", "3"};
236 newArray = ArrayUtils.addAll(stringArray1, (String[]) null);
237 assertNotSame(stringArray1, newArray);
238 assertTrue(Arrays.equals(stringArray1, newArray));
239 assertTrue(Arrays.equals((new String[]{"a", "b", "c"}), newArray));
240 assertEquals(String.class, newArray.getClass().getComponentType());
241 newArray = ArrayUtils.addAll(null, stringArray2);
242 assertNotSame(stringArray2, newArray);
243 assertTrue(Arrays.equals(stringArray2, newArray));
244 assertTrue(Arrays.equals((new String[]{"1", "2", "3"}), newArray));
245 assertEquals(String.class, newArray.getClass().getComponentType());
246 newArray = ArrayUtils.addAll(stringArray1, stringArray2);
247 assertTrue(Arrays.equals((new String[]{"a", "b", "c", "1", "2", "3"}), newArray));
248 assertEquals(String.class, newArray.getClass().getComponentType());
249 newArray = ArrayUtils.addAll(ArrayUtils.EMPTY_STRING_ARRAY, (String[]) null);
250 assertTrue(Arrays.equals(ArrayUtils.EMPTY_STRING_ARRAY, newArray));
251 assertTrue(Arrays.equals((new String[]{}), newArray));
252 assertEquals(String.class, newArray.getClass().getComponentType());
253 newArray = ArrayUtils.addAll(null, ArrayUtils.EMPTY_STRING_ARRAY);
254 assertTrue(Arrays.equals(ArrayUtils.EMPTY_STRING_ARRAY, newArray));
255 assertTrue(Arrays.equals((new String[]{}), newArray));
256 assertEquals(String.class, newArray.getClass().getComponentType());
257 newArray = ArrayUtils.addAll(ArrayUtils.EMPTY_STRING_ARRAY, ArrayUtils.EMPTY_STRING_ARRAY);
258 assertTrue(Arrays.equals(ArrayUtils.EMPTY_STRING_ARRAY, newArray));
259 assertTrue(Arrays.equals((new String[]{}), newArray));
260 assertEquals(String.class, newArray.getClass().getComponentType());
261 String[] stringArrayNull = new String []{null};
262 newArray = ArrayUtils.addAll(stringArrayNull, stringArrayNull);
263 assertTrue(Arrays.equals((new String[]{null, null}), newArray));
264 assertEquals(String.class, newArray.getClass().getComponentType());
265
266 // boolean
267 assertTrue( Arrays.equals( new boolean[] { true, false, false, true },
268 ArrayUtils.addAll( new boolean[] { true, false }, new boolean[] { false, true } ) ) );
269
270 assertTrue( Arrays.equals( new boolean[] { false, true },
271 ArrayUtils.addAll( null, new boolean[] { false, true } ) ) );
272
273 assertTrue( Arrays.equals( new boolean[] { true, false },
274 ArrayUtils.addAll( new boolean[] { true, false }, null ) ) );
275
276 // char
277 assertTrue( Arrays.equals( new char[] { 'a', 'b', 'c', 'd' },
278 ArrayUtils.addAll( new char[] { 'a', 'b' }, new char[] { 'c', 'd' } ) ) );
279
280 assertTrue( Arrays.equals( new char[] { 'c', 'd' },
281 ArrayUtils.addAll( null, new char[] { 'c', 'd' } ) ) );
282
283 assertTrue( Arrays.equals( new char[] { 'a', 'b' },
284 ArrayUtils.addAll( new char[] { 'a', 'b' }, null ) ) );
285
286 // byte
287 assertTrue( Arrays.equals( new byte[] { (byte) 0, (byte) 1, (byte) 2, (byte) 3 },
288 ArrayUtils.addAll( new byte[] { (byte) 0, (byte) 1 }, new byte[] { (byte) 2, (byte) 3 } ) ) );
289
290 assertTrue( Arrays.equals( new byte[] { (byte) 2, (byte) 3 },
291 ArrayUtils.addAll( null, new byte[] { (byte) 2, (byte) 3 } ) ) );
292
293 assertTrue( Arrays.equals( new byte[] { (byte) 0, (byte) 1 },
294 ArrayUtils.addAll( new byte[] { (byte) 0, (byte) 1 }, null ) ) );
295
296 // short
297 assertTrue( Arrays.equals( new short[] { (short) 10, (short) 20, (short) 30, (short) 40 },
298 ArrayUtils.addAll( new short[] { (short) 10, (short) 20 }, new short[] { (short) 30, (short) 40 } ) ) );
299
300 assertTrue( Arrays.equals( new short[] { (short) 30, (short) 40 },
301 ArrayUtils.addAll( null, new short[] { (short) 30, (short) 40 } ) ) );
302
303 assertTrue( Arrays.equals( new short[] { (short) 10, (short) 20 },
304 ArrayUtils.addAll( new short[] { (short) 10, (short) 20 }, null ) ) );
305
306 // int
307 assertTrue( Arrays.equals( new int[] { 1, 1000, -1000, -1 },
308 ArrayUtils.addAll( new int[] { 1, 1000 }, new int[] { -1000, -1 } ) ) );
309
310 assertTrue( Arrays.equals( new int[] { -1000, -1 },
311 ArrayUtils.addAll( null, new int[] { -1000, -1 } ) ) );
312
313 assertTrue( Arrays.equals( new int[] { 1, 1000 },
314 ArrayUtils.addAll( new int[] { 1, 1000 }, null ) ) );
315
316 // long
317 assertTrue( Arrays.equals( new long[] { 1L, -1L, 1000L, -1000L },
318 ArrayUtils.addAll( new long[] { 1L, -1L }, new long[] { 1000L, -1000L } ) ) );
319
320 assertTrue( Arrays.equals( new long[] { 1000L, -1000L },
321 ArrayUtils.addAll( null, new long[] { 1000L, -1000L } ) ) );
322
323 assertTrue( Arrays.equals( new long[] { 1L, -1L },
324 ArrayUtils.addAll( new long[] { 1L, -1L }, null ) ) );
325
326 // float
327 assertTrue( Arrays.equals( new float[] { 10.5f, 10.1f, 1.6f, 0.01f },
328 ArrayUtils.addAll( new float[] { 10.5f, 10.1f }, new float[] { 1.6f, 0.01f } ) ) );
329
330 assertTrue( Arrays.equals( new float[] { 1.6f, 0.01f },
331 ArrayUtils.addAll( null, new float[] { 1.6f, 0.01f } ) ) );
332
333 assertTrue( Arrays.equals( new float[] { 10.5f, 10.1f },
334 ArrayUtils.addAll( new float[] { 10.5f, 10.1f }, null ) ) );
335
336 // double
337 assertTrue( Arrays.equals( new double[] { Math.PI, -Math.PI, 0, 9.99 },
338 ArrayUtils.addAll( new double[] { Math.PI, -Math.PI }, new double[] { 0, 9.99 } ) ) );
339
340 assertTrue( Arrays.equals( new double[] { 0, 9.99 },
341 ArrayUtils.addAll( null, new double[] { 0, 9.99 } ) ) );
342
343 assertTrue( Arrays.equals( new double[] { Math.PI, -Math.PI },
344 ArrayUtils.addAll( new double[] { Math.PI, -Math.PI }, null ) ) );
345
346 }
347
348 public void testAddObjectAtIndex() {
349 Object[] newArray;
350 newArray = ArrayUtils.add((Object[])null, 0, "a");
351 assertTrue(Arrays.equals((new String[]{"a"}), newArray));
352 assertTrue(Arrays.equals((new Object[]{"a"}), newArray));
353 assertEquals(String.class, newArray.getClass().getComponentType());
354 String[] stringArray1 = new String[]{"a", "b", "c"};
355 newArray = ArrayUtils.add(stringArray1, 0, null);
356 assertTrue(Arrays.equals((new String[]{null, "a", "b", "c"}), newArray));
357 assertEquals(String.class, newArray.getClass().getComponentType());
358 newArray = ArrayUtils.add(stringArray1, 1, null);
359 assertTrue(Arrays.equals((new String[]{"a", null, "b", "c"}), newArray));
360 assertEquals(String.class, newArray.getClass().getComponentType());
361 newArray = ArrayUtils.add(stringArray1, 3, null);
362 assertTrue(Arrays.equals((new String[]{"a", "b", "c", null}), newArray));
363 assertEquals(String.class, newArray.getClass().getComponentType());
364 newArray = ArrayUtils.add(stringArray1, 3, "d");
365 assertTrue(Arrays.equals((new String[]{"a", "b", "c", "d"}), newArray));
366 assertEquals(String.class, newArray.getClass().getComponentType());
367 assertEquals(String.class, newArray.getClass().getComponentType());
368
369 Object[] o = new Object[] {"1", "2", "4"};
370 Object[] result = ArrayUtils.add(o, 2, "3");
371 Object[] result2 = ArrayUtils.add(o, 3, "5");
372
373 assertNotNull(result);
374 assertEquals(4, result.length);
375 assertEquals("1", result[0]);
376 assertEquals("2", result[1]);
377 assertEquals("3", result[2]);
378 assertEquals("4", result[3]);
379 assertNotNull(result2);
380 assertEquals(4, result2.length);
381 assertEquals("1", result2[0]);
382 assertEquals("2", result2[1]);
383 assertEquals("4", result2[2]);
384 assertEquals("5", result2[3]);
385
386 // boolean tests
387 boolean[] booleanArray = ArrayUtils.add( null, 0, true );
388 assertTrue( Arrays.equals( new boolean[] { true }, booleanArray ) );
389 try {
390 booleanArray = ArrayUtils.add( null, -1, true );
391 } catch(IndexOutOfBoundsException e) {
392 assertEquals("Index: -1, Length: 0", e.getMessage());
393 }
394 booleanArray = ArrayUtils.add( new boolean[] { true }, 0, false);
395 assertTrue( Arrays.equals( new boolean[] { false, true }, booleanArray ) );
396 booleanArray = ArrayUtils.add( new boolean[] { false }, 1, true);
397 assertTrue( Arrays.equals( new boolean[] { false, true }, booleanArray ) );
398 booleanArray = ArrayUtils.add( new boolean[] { true, false }, 1, true);
399 assertTrue( Arrays.equals( new boolean[] { true, true, false }, booleanArray ) );
400 try {
401 booleanArray = ArrayUtils.add( new boolean[] { true, false }, 4, true);
402 } catch(IndexOutOfBoundsException e) {
403 assertEquals("Index: 4, Length: 2", e.getMessage());
404 }
405 try {
406 booleanArray = ArrayUtils.add( new boolean[] { true, false }, -1, true);
407 } catch(IndexOutOfBoundsException e) {
408 assertEquals("Index: -1, Length: 2", e.getMessage());
409 }
410
411 // char tests
412 char[] charArray = ArrayUtils.add( (char[]) null, 0, 'a' );
413 assertTrue( Arrays.equals( new char[] { 'a' }, charArray ) );
414 try {
415 charArray = ArrayUtils.add( (char[]) null, -1, 'a' );
416 } catch(IndexOutOfBoundsException e) {
417 assertEquals("Index: -1, Length: 0", e.getMessage());
418 }
419 charArray = ArrayUtils.add( new char[] { 'a' }, 0, 'b');
420 assertTrue( Arrays.equals( new char[] { 'b', 'a' }, charArray ) );
421 charArray = ArrayUtils.add( new char[] { 'a', 'b' }, 0, 'c');
422 assertTrue( Arrays.equals( new char[] { 'c', 'a', 'b' }, charArray ) );
423 charArray = ArrayUtils.add( new char[] { 'a', 'b' }, 1, 'k');
424 assertTrue( Arrays.equals( new char[] { 'a', 'k', 'b' }, charArray ) );
425 charArray = ArrayUtils.add( new char[] { 'a', 'b', 'c' }, 1, 't');
426 assertTrue( Arrays.equals( new char[] { 'a', 't', 'b', 'c' }, charArray ) );
427 try {
428 charArray = ArrayUtils.add( new char[] { 'a', 'b' }, 4, 'c');
429 } catch(IndexOutOfBoundsException e) {
430 assertEquals("Index: 4, Length: 2", e.getMessage());
431 }
432 try {
433 charArray = ArrayUtils.add( new char[] { 'a', 'b' }, -1, 'c');
434 } catch(IndexOutOfBoundsException e) {
435 assertEquals("Index: -1, Length: 2", e.getMessage());
436 }
437
438 // short tests
439 short[] shortArray = ArrayUtils.add( new short[] { 1 }, 0, (short) 2);
440 assertTrue( Arrays.equals( new short[] { 2, 1 }, shortArray ) );
441 try {
442 shortArray = ArrayUtils.add( (short[]) null, -1, (short) 2);
443 } catch(IndexOutOfBoundsException e) {
444 assertEquals("Index: -1, Length: 0", e.getMessage());
445 }
446 shortArray = ArrayUtils.add( new short[] { 2, 6 }, 2, (short) 10);
447 assertTrue( Arrays.equals( new short[] { 2, 6, 10 }, shortArray ) );
448 shortArray = ArrayUtils.add( new short[] { 2, 6 }, 0, (short) -4);
449 assertTrue( Arrays.equals( new short[] { -4, 2, 6 }, shortArray ) );
450 shortArray = ArrayUtils.add( new short[] { 2, 6, 3 }, 2, (short) 1);
451 assertTrue( Arrays.equals( new short[] { 2, 6, 1, 3 }, shortArray ) );
452 try {
453 shortArray = ArrayUtils.add( new short[] { 2, 6 }, 4, (short) 10);
454 } catch(IndexOutOfBoundsException e) {
455 assertEquals("Index: 4, Length: 2", e.getMessage());
456 }
457 try {
458 shortArray = ArrayUtils.add( new short[] { 2, 6 }, -1, (short) 10);
459 } catch(IndexOutOfBoundsException e) {
460 assertEquals("Index: -1, Length: 2", e.getMessage());
461 }
462
463 // byte tests
464 byte[] byteArray = ArrayUtils.add( new byte[] { 1 }, 0, (byte) 2);
465 assertTrue( Arrays.equals( new byte[] { 2, 1 }, byteArray ) );
466 try {
467 byteArray = ArrayUtils.add( (byte[]) null, -1, (byte) 2);
468 } catch(IndexOutOfBoundsException e) {
469 assertEquals("Index: -1, Length: 0", e.getMessage());
470 }
471 byteArray = ArrayUtils.add( new byte[] { 2, 6 }, 2, (byte) 3);
472 assertTrue( Arrays.equals( new byte[] { 2, 6, 3 }, byteArray ) );
473 byteArray = ArrayUtils.add( new byte[] { 2, 6 }, 0, (byte) 1);
474 assertTrue( Arrays.equals( new byte[] { 1, 2, 6 }, byteArray ) );
475 byteArray = ArrayUtils.add( new byte[] { 2, 6, 3 }, 2, (byte) 1);
476 assertTrue( Arrays.equals( new byte[] { 2, 6, 1, 3 }, byteArray ) );
477 try {
478 byteArray = ArrayUtils.add( new byte[] { 2, 6 }, 4, (byte) 3);
479 } catch(IndexOutOfBoundsException e) {
480 assertEquals("Index: 4, Length: 2", e.getMessage());
481 }
482 try {
483 byteArray = ArrayUtils.add( new byte[] { 2, 6 }, -1, (byte) 3);
484 } catch(IndexOutOfBoundsException e) {
485 assertEquals("Index: -1, Length: 2", e.getMessage());
486 }
487
488 // int tests
489 int[] intArray = ArrayUtils.add( new int[] { 1 }, 0, 2);
490 assertTrue( Arrays.equals( new int[] { 2, 1 }, intArray ) );
491 try {
492 intArray = ArrayUtils.add( (int[]) null, -1, 2);
493 } catch(IndexOutOfBoundsException e) {
494 assertEquals("Index: -1, Length: 0", e.getMessage());
495 }
496 intArray = ArrayUtils.add( new int[] { 2, 6 }, 2, 10);
497 assertTrue( Arrays.equals( new int[] { 2, 6, 10 }, intArray ) );
498 intArray = ArrayUtils.add( new int[] { 2, 6 }, 0, -4);
499 assertTrue( Arrays.equals( new int[] { -4, 2, 6 }, intArray ) );
500 intArray = ArrayUtils.add( new int[] { 2, 6, 3 }, 2, 1);
501 assertTrue( Arrays.equals( new int[] { 2, 6, 1, 3 }, intArray ) );
502 try {
503 intArray = ArrayUtils.add( new int[] { 2, 6 }, 4, 10);
504 } catch(IndexOutOfBoundsException e) {
505 assertEquals("Index: 4, Length: 2", e.getMessage());
506 }
507 try {
508 intArray = ArrayUtils.add( new int[] { 2, 6 }, -1, 10);
509 } catch(IndexOutOfBoundsException e) {
510 assertEquals("Index: -1, Length: 2", e.getMessage());
511 }
512
513 // long tests
514 long[] longArray = ArrayUtils.add( new long[] { 1L }, 0, 2L);
515 assertTrue( Arrays.equals( new long[] { 2L, 1L }, longArray ) );
516 try {
517 longArray = ArrayUtils.add( (long[]) null, -1, 2L);
518 } catch(IndexOutOfBoundsException e) {
519 assertEquals("Index: -1, Length: 0", e.getMessage());
520 }
521 longArray = ArrayUtils.add( new long[] { 2L, 6L }, 2, 10L);
522 assertTrue( Arrays.equals( new long[] { 2L, 6L, 10L }, longArray ) );
523 longArray = ArrayUtils.add( new long[] { 2L, 6L }, 0, -4L);
524 assertTrue( Arrays.equals( new long[] { -4L, 2L, 6L }, longArray ) );
525 longArray = ArrayUtils.add( new long[] { 2L, 6L, 3L }, 2, 1L);
526 assertTrue( Arrays.equals( new long[] { 2L, 6L, 1L, 3L }, longArray ) );
527 try {
528 longArray = ArrayUtils.add( new long[] { 2L, 6L }, 4, 10L);
529 } catch(IndexOutOfBoundsException e) {
530 assertEquals("Index: 4, Length: 2", e.getMessage());
531 }
532 try {
533 longArray = ArrayUtils.add( new long[] { 2L, 6L }, -1, 10L);
534 } catch(IndexOutOfBoundsException e) {
535 assertEquals("Index: -1, Length: 2", e.getMessage());
536 }
537
538 // float tests
539 float[] floatArray = ArrayUtils.add( new float[] { 1.1f }, 0, 2.2f);
540 assertTrue( Arrays.equals( new float[] { 2.2f, 1.1f }, floatArray ) );
541 try {
542 floatArray = ArrayUtils.add( (float[]) null, -1, 2.2f);
543 } catch(IndexOutOfBoundsException e) {
544 assertEquals("Index: -1, Length: 0", e.getMessage());
545 }
546 floatArray = ArrayUtils.add( new float[] { 2.3f, 6.4f }, 2, 10.5f);
547 assertTrue( Arrays.equals( new float[] { 2.3f, 6.4f, 10.5f }, floatArray ) );
548 floatArray = ArrayUtils.add( new float[] { 2.6f, 6.7f }, 0, -4.8f);
549 assertTrue( Arrays.equals( new float[] { -4.8f, 2.6f, 6.7f }, floatArray ) );
550 floatArray = ArrayUtils.add( new float[] { 2.9f, 6.0f, 0.3f }, 2, 1.0f);
551 assertTrue( Arrays.equals( new float[] { 2.9f, 6.0f, 1.0f, 0.3f }, floatArray ) );
552 try {
553 floatArray = ArrayUtils.add( new float[] { 2.3f, 6.4f }, 4, 10.5f);
554 } catch(IndexOutOfBoundsException e) {
555 assertEquals("Index: 4, Length: 2", e.getMessage());
556 }
557 try {
558 floatArray = ArrayUtils.add( new float[] { 2.3f, 6.4f }, -1, 10.5f);
559 } catch(IndexOutOfBoundsException e) {
560 assertEquals("Index: -1, Length: 2", e.getMessage());
561 }
562
563 // double tests
564 double[] doubleArray = ArrayUtils.add( new double[] { 1.1 }, 0, 2.2);
565 assertTrue( Arrays.equals( new double[] { 2.2, 1.1 }, doubleArray ) );
566 try {
567 doubleArray = ArrayUtils.add( (double[]) null, -1, 2.2);
568 } catch(IndexOutOfBoundsException e) {
569 assertEquals("Index: -1, Length: 0", e.getMessage());
570 }
571 doubleArray = ArrayUtils.add( new double[] { 2.3, 6.4 }, 2, 10.5);
572 assertTrue( Arrays.equals( new double[] { 2.3, 6.4, 10.5 }, doubleArray ) );
573 doubleArray = ArrayUtils.add( new double[] { 2.6, 6.7 }, 0, -4.8);
574 assertTrue( Arrays.equals( new double[] { -4.8, 2.6, 6.7 }, doubleArray ) );
575 doubleArray = ArrayUtils.add( new double[] { 2.9, 6.0, 0.3 }, 2, 1.0);
576 assertTrue( Arrays.equals( new double[] { 2.9, 6.0, 1.0, 0.3 }, doubleArray ) );
577 try {
578 doubleArray = ArrayUtils.add( new double[] { 2.3, 6.4 }, 4, 10.5);
579 } catch(IndexOutOfBoundsException e) {
580 assertEquals("Index: 4, Length: 2", e.getMessage());
581 }
582 try {
583 doubleArray = ArrayUtils.add( new double[] { 2.3, 6.4 }, -1, 10.5);
584 } catch(IndexOutOfBoundsException e) {
585 assertEquals("Index: -1, Length: 2", e.getMessage());
586 }
587 }
588
589 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3;
18
19 import static org.junit.Assert.*;
20
21 import java.util.Arrays;
22
23 import org.junit.Test;
24
25 /**
26 * Tests ArrayUtils remove and removeElement methods.
27 *
28 * @version $Id: ArrayUtilsRemoveMultipleTest.java 1147507 2011-07-17 00:30:04Z mbenson $
29 */
30 public class ArrayUtilsRemoveMultipleTest {
31
32 @Test
33 public void testRemoveAllObjectArray() {
34 Object[] array;
35 array = ArrayUtils.removeAll(new Object[] { "a" }, 0);
36 assertArrayEquals(ArrayUtils.EMPTY_OBJECT_ARRAY, array);
37 assertEquals(Object.class, array.getClass().getComponentType());
38 array = ArrayUtils.removeAll(new Object[] { "a", "b" }, 0, 1);
39 assertArrayEquals(ArrayUtils.EMPTY_OBJECT_ARRAY, array);
40 assertEquals(Object.class, array.getClass().getComponentType());
41 array = ArrayUtils.removeAll(new Object[] { "a", "b", "c" }, 1, 2);
42 assertArrayEquals(new Object[] { "a" }, array);
43 assertEquals(Object.class, array.getClass().getComponentType());
44 array = ArrayUtils.removeAll(new Object[] { "a", "b", "c", "d" }, 1, 2);
45 assertArrayEquals(new Object[] { "a", "d" }, array);
46 assertEquals(Object.class, array.getClass().getComponentType());
47 array = ArrayUtils.removeAll(new Object[] { "a", "b", "c", "d" }, 0, 3);
48 assertArrayEquals(new Object[] { "b", "c" }, array);
49 assertEquals(Object.class, array.getClass().getComponentType());
50 array = ArrayUtils.removeAll(new Object[] { "a", "b", "c", "d" }, 0, 1, 3);
51 assertArrayEquals(new Object[] { "c" }, array);
52 assertEquals(Object.class, array.getClass().getComponentType());
53 array = ArrayUtils.removeAll(new Object[] { "a", "b", "c", "d", "e" }, 0, 1, 3);
54 assertArrayEquals(new Object[] { "c", "e" }, array);
55 assertEquals(Object.class, array.getClass().getComponentType());
56 array = ArrayUtils.removeAll(new Object[] { "a", "b", "c", "d", "e" }, 0, 2, 4);
57 assertArrayEquals(new Object[] { "b", "d" }, array);
58 assertEquals(Object.class, array.getClass().getComponentType());
59 array = ArrayUtils.removeAll(new Object[] { "a", "b", "c", "d" }, 0, 1, 3, 0, 1, 3);
60 assertArrayEquals(new Object[] { "c" }, array);
61 assertEquals(Object.class, array.getClass().getComponentType());
62 array = ArrayUtils.removeAll(new Object[] { "a", "b", "c", "d" }, 2, 1, 0, 3);
63 assertArrayEquals(ArrayUtils.EMPTY_OBJECT_ARRAY, array);
64 assertEquals(Object.class, array.getClass().getComponentType());
65 array = ArrayUtils.removeAll(new Object[] { "a", "b", "c", "d" }, 2, 0, 1, 3, 0, 2, 1, 3);
66 assertArrayEquals(ArrayUtils.EMPTY_OBJECT_ARRAY, array);
67 assertEquals(Object.class, array.getClass().getComponentType());
68 }
69
70 @Test
71 public void testRemoveAllObjectArrayRemoveNone() {
72 Object[] array1 = new Object[] { "foo", "bar", "baz" };
73 Object[] array2 = ArrayUtils.removeAll(array1);
74 assertNotSame(array1, array2);
75 assertArrayEquals(array1, array2);
76 assertEquals(Object.class, array2.getClass().getComponentType());
77 }
78
79 @Test(expected = IndexOutOfBoundsException.class)
80 public void testRemoveAllObjectArrayNegativeIndex() {
81 ArrayUtils.removeAll(new Object[] { "a", "b" }, -1);
82 }
83
84 @Test(expected = IndexOutOfBoundsException.class)
85 public void testRemoveAllObjectArrayOutOfBoundsIndex() {
86 ArrayUtils.removeAll(new Object[] { "a", "b" }, 2);
87 }
88
89 @Test(expected = IndexOutOfBoundsException.class)
90 public void testRemoveAllNullObjectArray() {
91 ArrayUtils.remove((Object[]) null, 0);
92 }
93
94 @Test
95 public void testRemoveAllNumberArray() {
96 Number[] inarray = { Integer.valueOf(1), Long.valueOf(2L), Byte.valueOf((byte) 3) };
97 assertEquals(3, inarray.length);
98 Number[] outarray;
99 outarray = ArrayUtils.removeAll(inarray, 1);
100 assertArrayEquals(new Number[] { Integer.valueOf(1), Byte.valueOf((byte) 3) }, outarray);
101 assertEquals(Number.class, outarray.getClass().getComponentType());
102 outarray = ArrayUtils.removeAll(outarray, 1);
103 assertArrayEquals(new Number[] { Integer.valueOf(1) }, outarray);
104 assertEquals(Number.class, outarray.getClass().getComponentType());
105 outarray = ArrayUtils.removeAll(outarray, 0);
106 assertEquals(0, outarray.length);
107 assertEquals(Number.class, outarray.getClass().getComponentType());
108
109 outarray = ArrayUtils.removeAll(inarray, 0, 1);
110 assertArrayEquals(new Number[] { Byte.valueOf((byte) 3) }, outarray);
111 assertEquals(Number.class, outarray.getClass().getComponentType());
112 outarray = ArrayUtils.removeAll(inarray, 0, 2);
113 assertArrayEquals(new Number[] { Long.valueOf(2L) }, outarray);
114 assertEquals(Number.class, outarray.getClass().getComponentType());
115 outarray = ArrayUtils.removeAll(inarray, 1, 2);
116 assertArrayEquals(new Number[] { Integer.valueOf(1) }, outarray);
117 assertEquals(Number.class, outarray.getClass().getComponentType());
118 }
119
120 @Test
121 public void testRemoveAllBooleanArray() {
122 boolean[] array;
123 array = ArrayUtils.removeAll(new boolean[] { true }, 0);
124 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, array));
125 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
126 array = ArrayUtils.removeAll(new boolean[] { true, false }, 0);
127 assertTrue(Arrays.equals(new boolean[] { false }, array));
128 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
129 array = ArrayUtils.removeAll(new boolean[] { true, false }, 1);
130 assertTrue(Arrays.equals(new boolean[] { true }, array));
131 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
132 array = ArrayUtils.removeAll(new boolean[] { true, false, true }, 1);
133 assertTrue(Arrays.equals(new boolean[] { true, true }, array));
134 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
135
136 array = ArrayUtils.removeAll(new boolean[] { true, false }, 0, 1);
137 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, array));
138 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
139 array = ArrayUtils.removeAll(new boolean[] { true, false, false }, 0, 1);
140 assertTrue(Arrays.equals(new boolean[] { false }, array));
141 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
142 array = ArrayUtils.removeAll(new boolean[] { true, false, false }, 0, 2);
143 assertTrue(Arrays.equals(new boolean[] { false }, array));
144 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
145 array = ArrayUtils.removeAll(new boolean[] { true, false, false }, 1, 2);
146 assertTrue(Arrays.equals(new boolean[] { true }, array));
147 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
148 array = ArrayUtils.removeAll(new boolean[] { true, false, true, false, true }, 0, 2, 4);
149 assertTrue(Arrays.equals(new boolean[] { false, false }, array));
150 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
151 array = ArrayUtils.removeAll(new boolean[] { true, false, true, false, true }, 1, 3);
152 assertTrue(Arrays.equals(new boolean[] { true, true, true }, array));
153 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
154 array = ArrayUtils.removeAll(new boolean[] { true, false, true, false, true }, 1, 3, 4);
155 assertTrue(Arrays.equals(new boolean[] { true, true }, array));
156 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
157 array = ArrayUtils.removeAll(new boolean[] { true, false, true, false, true, false, true }, 0, 2, 4, 6);
158 assertTrue(Arrays.equals(new boolean[] { false, false, false }, array));
159 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
160 array = ArrayUtils.removeAll(new boolean[] { true, false, true, false, true, false, true }, 1, 3, 5);
161 assertTrue(Arrays.equals(new boolean[] { true, true, true, true }, array));
162 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
163 array = ArrayUtils.removeAll(new boolean[] { true, false, true, false, true, false, true }, 0, 1, 2);
164 assertTrue(Arrays.equals(new boolean[] { false, true, false, true }, array));
165 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
166 }
167
168 @Test
169 public void testRemoveAllBooleanArrayRemoveNone() {
170 boolean[] array1 = new boolean[] { true, false };
171 boolean[] array2 = ArrayUtils.removeAll(array1);
172 assertNotSame(array1, array2);
173 assertTrue(Arrays.equals(array1, array2));
174 assertEquals(boolean.class, array2.getClass().getComponentType());
175 }
176
177 @Test(expected = IndexOutOfBoundsException.class)
178 public void testRemoveAllBooleanArrayNegativeIndex() {
179 ArrayUtils.removeAll(new boolean[] { true, false }, -1);
180 }
181
182 @Test(expected = IndexOutOfBoundsException.class)
183 public void testRemoveAllBooleanArrayOutOfBoundsIndex() {
184 ArrayUtils.removeAll(new boolean[] { true, false }, 2);
185 }
186
187 @Test(expected = IndexOutOfBoundsException.class)
188 public void testRemoveAllNullBooleanArray() {
189 ArrayUtils.removeAll((boolean[]) null, 0);
190 }
191
192 @Test
193 public void testRemoveAllByteArray() {
194 byte[] array;
195 array = ArrayUtils.removeAll(new byte[] { 1 }, 0);
196 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BYTE_ARRAY, array));
197 assertEquals(Byte.TYPE, array.getClass().getComponentType());
198 array = ArrayUtils.removeAll(new byte[] { 1, 2 }, 0);
199 assertTrue(Arrays.equals(new byte[] { 2 }, array));
200 assertEquals(Byte.TYPE, array.getClass().getComponentType());
201 array = ArrayUtils.removeAll(new byte[] { 1, 2 }, 1);
202 assertTrue(Arrays.equals(new byte[] { 1 }, array));
203 assertEquals(Byte.TYPE, array.getClass().getComponentType());
204 array = ArrayUtils.removeAll(new byte[] { 1, 2, 1 }, 1);
205 assertTrue(Arrays.equals(new byte[] { 1, 1 }, array));
206 assertEquals(Byte.TYPE, array.getClass().getComponentType());
207
208 array = ArrayUtils.removeAll(new byte[] { 1, 2 }, 0, 1);
209 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BYTE_ARRAY, array));
210 assertEquals(Byte.TYPE, array.getClass().getComponentType());
211 array = ArrayUtils.removeAll(new byte[] { 1, 2, 3 }, 0, 1);
212 assertTrue(Arrays.equals(new byte[] { 3 }, array));
213 assertEquals(Byte.TYPE, array.getClass().getComponentType());
214 array = ArrayUtils.removeAll(new byte[] { 1, 2, 3 }, 1, 2);
215 assertTrue(Arrays.equals(new byte[] { 1 }, array));
216 assertEquals(Byte.TYPE, array.getClass().getComponentType());
217 array = ArrayUtils.removeAll(new byte[] { 1, 2, 3 }, 0, 2);
218 assertTrue(Arrays.equals(new byte[] { 2 }, array));
219 assertEquals(Byte.TYPE, array.getClass().getComponentType());
220 array = ArrayUtils.removeAll(new byte[] { 1, 2, 3, 4, 5 }, 1, 3);
221 assertTrue(Arrays.equals(new byte[] { 1, 3, 5 }, array));
222 assertEquals(Byte.TYPE, array.getClass().getComponentType());
223 array = ArrayUtils.removeAll(new byte[] { 1, 2, 3, 4, 5 }, 0, 2, 4);
224 assertTrue(Arrays.equals(new byte[] { 2, 4 }, array));
225 assertEquals(Byte.TYPE, array.getClass().getComponentType());
226 array = ArrayUtils.removeAll(new byte[] { 1, 2, 3, 4, 5, 6, 7 }, 1, 3, 5);
227 assertTrue(Arrays.equals(new byte[] { 1, 3, 5, 7 }, array));
228 assertEquals(Byte.TYPE, array.getClass().getComponentType());
229 array = ArrayUtils.removeAll(new byte[] { 1, 2, 3, 4, 5, 6, 7 }, 0, 2, 4, 6);
230 assertTrue(Arrays.equals(new byte[] { 2, 4, 6 }, array));
231 assertEquals(Byte.TYPE, array.getClass().getComponentType());
232 }
233
234 @Test
235 public void testRemoveAllByteArrayRemoveNone() {
236 byte[] array1 = new byte[] { 1, 2 };
237 byte[] array2 = ArrayUtils.removeAll(array1);
238 assertNotSame(array1, array2);
239 assertArrayEquals(array1, array2);
240 assertEquals(byte.class, array2.getClass().getComponentType());
241 }
242
243 @Test(expected = IndexOutOfBoundsException.class)
244 public void testRemoveAllByteArrayNegativeIndex() {
245 ArrayUtils.removeAll(new byte[] { 1, 2 }, -1);
246 }
247
248 @Test(expected = IndexOutOfBoundsException.class)
249 public void testRemoveAllByteArrayOutOfBoundsIndex() {
250 ArrayUtils.removeAll(new byte[] { 1, 2 }, 2);
251 }
252
253 @Test(expected = IndexOutOfBoundsException.class)
254 public void testRemoveAllNullByteArray() {
255 ArrayUtils.removeAll((byte[]) null, 0);
256 }
257
258 @Test
259 public void testRemoveAllCharArray() {
260 char[] array;
261 array = ArrayUtils.removeAll(new char[] { 'a' }, 0);
262 assertTrue(Arrays.equals(ArrayUtils.EMPTY_CHAR_ARRAY, array));
263 assertEquals(Character.TYPE, array.getClass().getComponentType());
264 array = ArrayUtils.removeAll(new char[] { 'a', 'b' }, 0);
265 assertTrue(Arrays.equals(new char[] { 'b' }, array));
266 assertEquals(Character.TYPE, array.getClass().getComponentType());
267 array = ArrayUtils.removeAll(new char[] { 'a', 'b' }, 1);
268 assertTrue(Arrays.equals(new char[] { 'a' }, array));
269 assertEquals(Character.TYPE, array.getClass().getComponentType());
270 array = ArrayUtils.removeAll(new char[] { 'a', 'b', 'c' }, 1);
271 assertTrue(Arrays.equals(new char[] { 'a', 'c' }, array));
272 assertEquals(Character.TYPE, array.getClass().getComponentType());
273
274 array = ArrayUtils.removeAll(new char[] { 'a', 'b' }, 0, 1);
275 assertTrue(Arrays.equals(ArrayUtils.EMPTY_CHAR_ARRAY, array));
276 assertEquals(Character.TYPE, array.getClass().getComponentType());
277 array = ArrayUtils.removeAll(new char[] { 'a', 'b', 'c' }, 0, 1);
278 assertTrue(Arrays.equals(new char[] { 'c' }, array));
279 assertEquals(Character.TYPE, array.getClass().getComponentType());
280 array = ArrayUtils.removeAll(new char[] { 'a', 'b', 'c' }, 1, 2);
281 assertTrue(Arrays.equals(new char[] { 'a' }, array));
282 assertEquals(Character.TYPE, array.getClass().getComponentType());
283 array = ArrayUtils.removeAll(new char[] { 'a', 'b', 'c' }, 0, 2);
284 assertTrue(Arrays.equals(new char[] { 'b' }, array));
285 assertEquals(Character.TYPE, array.getClass().getComponentType());
286 array = ArrayUtils.removeAll(new char[] { 'a', 'b', 'c', 'd', 'e' }, 1, 3);
287 assertTrue(Arrays.equals(new char[] { 'a', 'c', 'e' }, array));
288 assertEquals(Character.TYPE, array.getClass().getComponentType());
289 array = ArrayUtils.removeAll(new char[] { 'a', 'b', 'c', 'd', 'e' }, 0, 2, 4);
290 assertTrue(Arrays.equals(new char[] { 'b', 'd' }, array));
291 assertEquals(Character.TYPE, array.getClass().getComponentType());
292 array = ArrayUtils.removeAll(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }, 1, 3, 5);
293 assertTrue(Arrays.equals(new char[] { 'a', 'c', 'e', 'g' }, array));
294 assertEquals(Character.TYPE, array.getClass().getComponentType());
295 array = ArrayUtils.removeAll(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }, 0, 2, 4, 6);
296 assertTrue(Arrays.equals(new char[] { 'b', 'd', 'f' }, array));
297 assertEquals(Character.TYPE, array.getClass().getComponentType());
298 }
299
300 @Test
301 public void testRemoveAllCharArrayRemoveNone() {
302 char[] array1 = new char[] { 'a', 'b' };
303 char[] array2 = ArrayUtils.removeAll(array1);
304 assertNotSame(array1, array2);
305 assertArrayEquals(array1, array2);
306 assertEquals(char.class, array2.getClass().getComponentType());
307 }
308
309 @Test(expected = IndexOutOfBoundsException.class)
310 public void testRemoveAllCharArrayNegativeIndex() {
311 ArrayUtils.removeAll(new char[] { 'a', 'b' }, -1);
312 }
313
314 @Test(expected = IndexOutOfBoundsException.class)
315 public void testRemoveAllCharArrayOutOfBoundsIndex() {
316 ArrayUtils.removeAll(new char[] { 'a', 'b' }, 2);
317 }
318
319 @Test(expected = IndexOutOfBoundsException.class)
320 public void testRemoveAllNullCharArray() {
321 ArrayUtils.removeAll((char[]) null, 0);
322 }
323
324 @Test
325 public void testRemoveAllDoubleArray() {
326 double[] array;
327 array = ArrayUtils.removeAll(new double[] { 1 }, 0);
328 assertTrue(Arrays.equals(ArrayUtils.EMPTY_DOUBLE_ARRAY, array));
329 assertEquals(Double.TYPE, array.getClass().getComponentType());
330 array = ArrayUtils.removeAll(new double[] { 1, 2 }, 0);
331 assertTrue(Arrays.equals(new double[] { 2 }, array));
332 assertEquals(Double.TYPE, array.getClass().getComponentType());
333 array = ArrayUtils.removeAll(new double[] { 1, 2 }, 1);
334 assertTrue(Arrays.equals(new double[] { 1 }, array));
335 assertEquals(Double.TYPE, array.getClass().getComponentType());
336 array = ArrayUtils.removeAll(new double[] { 1, 2, 1 }, 1);
337 assertTrue(Arrays.equals(new double[] { 1, 1 }, array));
338 assertEquals(Double.TYPE, array.getClass().getComponentType());
339
340 array = ArrayUtils.removeAll(new double[] { 1, 2 }, 0, 1);
341 assertTrue(Arrays.equals(ArrayUtils.EMPTY_DOUBLE_ARRAY, array));
342 assertEquals(Double.TYPE, array.getClass().getComponentType());
343 array = ArrayUtils.removeAll(new double[] { 1, 2, 3 }, 0, 1);
344 assertTrue(Arrays.equals(new double[] { 3 }, array));
345 assertEquals(Double.TYPE, array.getClass().getComponentType());
346 array = ArrayUtils.removeAll(new double[] { 1, 2, 3 }, 1, 2);
347 assertTrue(Arrays.equals(new double[] { 1 }, array));
348 assertEquals(Double.TYPE, array.getClass().getComponentType());
349 array = ArrayUtils.removeAll(new double[] { 1, 2, 3 }, 0, 2);
350 assertTrue(Arrays.equals(new double[] { 2 }, array));
351 assertEquals(Double.TYPE, array.getClass().getComponentType());
352 array = ArrayUtils.removeAll(new double[] { 1, 2, 3, 4, 5 }, 1, 3);
353 assertTrue(Arrays.equals(new double[] { 1, 3, 5 }, array));
354 assertEquals(Double.TYPE, array.getClass().getComponentType());
355 array = ArrayUtils.removeAll(new double[] { 1, 2, 3, 4, 5 }, 0, 2, 4);
356 assertTrue(Arrays.equals(new double[] { 2, 4 }, array));
357 assertEquals(Double.TYPE, array.getClass().getComponentType());
358 array = ArrayUtils.removeAll(new double[] { 1, 2, 3, 4, 5, 6, 7 }, 1, 3, 5);
359 assertTrue(Arrays.equals(new double[] { 1, 3, 5, 7 }, array));
360 assertEquals(Double.TYPE, array.getClass().getComponentType());
361 array = ArrayUtils.removeAll(new double[] { 1, 2, 3, 4, 5, 6, 7 }, 0, 2, 4, 6);
362 assertTrue(Arrays.equals(new double[] { 2, 4, 6 }, array));
363 assertEquals(Double.TYPE, array.getClass().getComponentType());
364 }
365
366 @Test
367 public void testRemoveAllDoubleArrayRemoveNone() {
368 double[] array1 = new double[] { 1, 2 };
369 double[] array2 = ArrayUtils.removeAll(array1);
370 assertNotSame(array1, array2);
371 assertTrue(Arrays.equals(array1, array2));
372 assertEquals(double.class, array2.getClass().getComponentType());
373 }
374
375 @Test(expected = IndexOutOfBoundsException.class)
376 public void testRemoveAllDoubleArrayNegativeIndex() {
377 ArrayUtils.removeAll(new double[] { 1, 2 }, -1);
378 }
379
380 @Test(expected = IndexOutOfBoundsException.class)
381 public void testRemoveAllDoubleArrayOutOfBoundsIndex() {
382 ArrayUtils.removeAll(new double[] { 1, 2 }, 2);
383 }
384
385 @Test(expected = IndexOutOfBoundsException.class)
386 public void testRemoveAllNullDoubleArray() {
387 ArrayUtils.removeAll((double[]) null, 0);
388 }
389
390 @Test
391 public void testRemoveAllFloatArray() {
392 float[] array;
393 array = ArrayUtils.removeAll(new float[] { 1 }, 0);
394 assertTrue(Arrays.equals(ArrayUtils.EMPTY_FLOAT_ARRAY, array));
395 assertEquals(Float.TYPE, array.getClass().getComponentType());
396 array = ArrayUtils.removeAll(new float[] { 1, 2 }, 0);
397 assertTrue(Arrays.equals(new float[] { 2 }, array));
398 assertEquals(Float.TYPE, array.getClass().getComponentType());
399 array = ArrayUtils.removeAll(new float[] { 1, 2 }, 1);
400 assertTrue(Arrays.equals(new float[] { 1 }, array));
401 assertEquals(Float.TYPE, array.getClass().getComponentType());
402 array = ArrayUtils.removeAll(new float[] { 1, 2, 1 }, 1);
403 assertTrue(Arrays.equals(new float[] { 1, 1 }, array));
404 assertEquals(Float.TYPE, array.getClass().getComponentType());
405
406 array = ArrayUtils.removeAll(new float[] { 1, 2 }, 0, 1);
407 assertTrue(Arrays.equals(ArrayUtils.EMPTY_FLOAT_ARRAY, array));
408 assertEquals(Float.TYPE, array.getClass().getComponentType());
409 array = ArrayUtils.removeAll(new float[] { 1, 2, 3 }, 0, 1);
410 assertTrue(Arrays.equals(new float[] { 3 }, array));
411 assertEquals(Float.TYPE, array.getClass().getComponentType());
412 array = ArrayUtils.removeAll(new float[] { 1, 2, 3 }, 1, 2);
413 assertTrue(Arrays.equals(new float[] { 1 }, array));
414 assertEquals(Float.TYPE, array.getClass().getComponentType());
415 array = ArrayUtils.removeAll(new float[] { 1, 2, 3 }, 0, 2);
416 assertTrue(Arrays.equals(new float[] { 2 }, array));
417 assertEquals(Float.TYPE, array.getClass().getComponentType());
418 array = ArrayUtils.removeAll(new float[] { 1, 2, 3, 4, 5 }, 1, 3);
419 assertTrue(Arrays.equals(new float[] { 1, 3, 5 }, array));
420 assertEquals(Float.TYPE, array.getClass().getComponentType());
421 array = ArrayUtils.removeAll(new float[] { 1, 2, 3, 4, 5 }, 0, 2, 4);
422 assertTrue(Arrays.equals(new float[] { 2, 4 }, array));
423 assertEquals(Float.TYPE, array.getClass().getComponentType());
424 array = ArrayUtils.removeAll(new float[] { 1, 2, 3, 4, 5, 6, 7 }, 1, 3, 5);
425 assertTrue(Arrays.equals(new float[] { 1, 3, 5, 7 }, array));
426 assertEquals(Float.TYPE, array.getClass().getComponentType());
427 array = ArrayUtils.removeAll(new float[] { 1, 2, 3, 4, 5, 6, 7 }, 0, 2, 4, 6);
428 assertTrue(Arrays.equals(new float[] { 2, 4, 6 }, array));
429 assertEquals(Float.TYPE, array.getClass().getComponentType());
430 }
431
432 @Test
433 public void testRemoveAllFloatArrayRemoveNone() {
434 float[] array1 = new float[] { 1, 2 };
435 float[] array2 = ArrayUtils.removeAll(array1);
436 assertNotSame(array1, array2);
437 assertTrue(Arrays.equals(array1, array2));
438 assertEquals(float.class, array2.getClass().getComponentType());
439 }
440
441 @Test(expected = IndexOutOfBoundsException.class)
442 public void testRemoveAllFloatArrayNegativeIndex() {
443 ArrayUtils.removeAll(new float[] { 1, 2 }, -1);
444 }
445
446 @Test(expected = IndexOutOfBoundsException.class)
447 public void testRemoveAllFloatArrayOutOfBoundsIndex() {
448 ArrayUtils.removeAll(new float[] { 1, 2 }, 2);
449 }
450
451 @Test(expected = IndexOutOfBoundsException.class)
452 public void testRemoveAllNullFloatArray() {
453 ArrayUtils.removeAll((float[]) null, 0);
454 }
455
456 @Test
457 public void testRemoveAllIntArray() {
458 int[] array;
459 array = ArrayUtils.removeAll(new int[] { 1 }, 0);
460 assertTrue(Arrays.equals(ArrayUtils.EMPTY_INT_ARRAY, array));
461 assertEquals(Integer.TYPE, array.getClass().getComponentType());
462 array = ArrayUtils.removeAll(new int[] { 1, 2 }, 0);
463 assertTrue(Arrays.equals(new int[] { 2 }, array));
464 assertEquals(Integer.TYPE, array.getClass().getComponentType());
465 array = ArrayUtils.removeAll(new int[] { 1, 2 }, 1);
466 assertTrue(Arrays.equals(new int[] { 1 }, array));
467 assertEquals(Integer.TYPE, array.getClass().getComponentType());
468 array = ArrayUtils.removeAll(new int[] { 1, 2, 1 }, 1);
469 assertTrue(Arrays.equals(new int[] { 1, 1 }, array));
470 assertEquals(Integer.TYPE, array.getClass().getComponentType());
471
472 array = ArrayUtils.removeAll(new int[] { 1, 2 }, 0, 1);
473 assertTrue(Arrays.equals(ArrayUtils.EMPTY_INT_ARRAY, array));
474 assertEquals(Integer.TYPE, array.getClass().getComponentType());
475 array = ArrayUtils.removeAll(new int[] { 1, 2, 3 }, 0, 1);
476 assertTrue(Arrays.equals(new int[] { 3 }, array));
477 assertEquals(Integer.TYPE, array.getClass().getComponentType());
478 array = ArrayUtils.removeAll(new int[] { 1, 2, 3 }, 1, 2);
479 assertTrue(Arrays.equals(new int[] { 1 }, array));
480 assertEquals(Integer.TYPE, array.getClass().getComponentType());
481 array = ArrayUtils.removeAll(new int[] { 1, 2, 3 }, 0, 2);
482 assertTrue(Arrays.equals(new int[] { 2 }, array));
483 assertEquals(Integer.TYPE, array.getClass().getComponentType());
484 array = ArrayUtils.removeAll(new int[] { 1, 2, 3, 4, 5 }, 1, 3);
485 assertTrue(Arrays.equals(new int[] { 1, 3, 5 }, array));
486 assertEquals(Integer.TYPE, array.getClass().getComponentType());
487 array = ArrayUtils.removeAll(new int[] { 1, 2, 3, 4, 5 }, 0, 2, 4);
488 assertTrue(Arrays.equals(new int[] { 2, 4 }, array));
489 assertEquals(Integer.TYPE, array.getClass().getComponentType());
490 array = ArrayUtils.removeAll(new int[] { 1, 2, 3, 4, 5, 6, 7 }, 1, 3, 5);
491 assertTrue(Arrays.equals(new int[] { 1, 3, 5, 7 }, array));
492 assertEquals(Integer.TYPE, array.getClass().getComponentType());
493 array = ArrayUtils.removeAll(new int[] { 1, 2, 3, 4, 5, 6, 7 }, 0, 2, 4, 6);
494 assertTrue(Arrays.equals(new int[] { 2, 4, 6 }, array));
495 assertEquals(Integer.TYPE, array.getClass().getComponentType());
496 }
497
498 @Test
499 public void testRemoveAllIntArrayRemoveNone() {
500 int[] array1 = new int[] { 1, 2 };
501 int[] array2 = ArrayUtils.removeAll(array1);
502 assertNotSame(array1, array2);
503 assertArrayEquals(array1, array2);
504 assertEquals(int.class, array2.getClass().getComponentType());
505 }
506
507 @Test(expected = IndexOutOfBoundsException.class)
508 public void testRemoveAllIntArrayNegativeIndex() {
509 ArrayUtils.removeAll(new int[] { 1, 2 }, -1);
510 }
511
512 @Test(expected = IndexOutOfBoundsException.class)
513 public void testRemoveAllIntArrayOutOfBoundsIndex() {
514 ArrayUtils.removeAll(new int[] { 1, 2 }, 2);
515 }
516
517 @Test(expected = IndexOutOfBoundsException.class)
518 public void testRemoveAllNullIntArray() {
519 ArrayUtils.removeAll((int[]) null, 0);
520 }
521
522 @Test
523 public void testRemoveAllLongArray() {
524 long[] array;
525 array = ArrayUtils.removeAll(new long[] { 1 }, 0);
526 assertTrue(Arrays.equals(ArrayUtils.EMPTY_LONG_ARRAY, array));
527 assertEquals(Long.TYPE, array.getClass().getComponentType());
528 array = ArrayUtils.removeAll(new long[] { 1, 2 }, 0);
529 assertTrue(Arrays.equals(new long[] { 2 }, array));
530 assertEquals(Long.TYPE, array.getClass().getComponentType());
531 array = ArrayUtils.removeAll(new long[] { 1, 2 }, 1);
532 assertTrue(Arrays.equals(new long[] { 1 }, array));
533 assertEquals(Long.TYPE, array.getClass().getComponentType());
534 array = ArrayUtils.removeAll(new long[] { 1, 2, 1 }, 1);
535 assertTrue(Arrays.equals(new long[] { 1, 1 }, array));
536 assertEquals(Long.TYPE, array.getClass().getComponentType());
537
538 array = ArrayUtils.removeAll(new long[] { 1, 2 }, 0, 1);
539 assertTrue(Arrays.equals(ArrayUtils.EMPTY_LONG_ARRAY, array));
540 assertEquals(Long.TYPE, array.getClass().getComponentType());
541 array = ArrayUtils.removeAll(new long[] { 1, 2, 3 }, 0, 1);
542 assertTrue(Arrays.equals(new long[] { 3 }, array));
543 assertEquals(Long.TYPE, array.getClass().getComponentType());
544 array = ArrayUtils.removeAll(new long[] { 1, 2, 3 }, 1, 2);
545 assertTrue(Arrays.equals(new long[] { 1 }, array));
546 assertEquals(Long.TYPE, array.getClass().getComponentType());
547 array = ArrayUtils.removeAll(new long[] { 1, 2, 3 }, 0, 2);
548 assertTrue(Arrays.equals(new long[] { 2 }, array));
549 assertEquals(Long.TYPE, array.getClass().getComponentType());
550 array = ArrayUtils.removeAll(new long[] { 1, 2, 3, 4, 5 }, 1, 3);
551 assertTrue(Arrays.equals(new long[] { 1, 3, 5 }, array));
552 assertEquals(Long.TYPE, array.getClass().getComponentType());
553 array = ArrayUtils.removeAll(new long[] { 1, 2, 3, 4, 5 }, 0, 2, 4);
554 assertTrue(Arrays.equals(new long[] { 2, 4 }, array));
555 assertEquals(Long.TYPE, array.getClass().getComponentType());
556 array = ArrayUtils.removeAll(new long[] { 1, 2, 3, 4, 5, 6, 7 }, 1, 3, 5);
557 assertTrue(Arrays.equals(new long[] { 1, 3, 5, 7 }, array));
558 assertEquals(Long.TYPE, array.getClass().getComponentType());
559 array = ArrayUtils.removeAll(new long[] { 1, 2, 3, 4, 5, 6, 7 }, 0, 2, 4, 6);
560 assertTrue(Arrays.equals(new long[] { 2, 4, 6 }, array));
561 assertEquals(Long.TYPE, array.getClass().getComponentType());
562 }
563
564 @Test
565 public void testRemoveAllLongArrayRemoveNone() {
566 long[] array1 = new long[] { 1, 2 };
567 long[] array2 = ArrayUtils.removeAll(array1);
568 assertNotSame(array1, array2);
569 assertArrayEquals(array1, array2);
570 assertEquals(long.class, array2.getClass().getComponentType());
571 }
572
573 @Test(expected = IndexOutOfBoundsException.class)
574 public void testRemoveAllLongArrayNegativeIndex() {
575 ArrayUtils.removeAll(new long[] { 1, 2 }, -1);
576 }
577
578 @Test(expected = IndexOutOfBoundsException.class)
579 public void testRemoveAllLongArrayOutOfBoundsIndex() {
580 ArrayUtils.removeAll(new long[] { 1, 2 }, 2);
581 }
582
583 @Test(expected = IndexOutOfBoundsException.class)
584 public void testRemoveAllNullLongArray() {
585 ArrayUtils.removeAll((long[]) null, 0);
586 }
587
588 @Test
589 public void testRemoveAllShortArray() {
590 short[] array;
591 array = ArrayUtils.removeAll(new short[] { 1 }, 0);
592 assertTrue(Arrays.equals(ArrayUtils.EMPTY_SHORT_ARRAY, array));
593 assertEquals(Short.TYPE, array.getClass().getComponentType());
594 array = ArrayUtils.removeAll(new short[] { 1, 2 }, 0);
595 assertTrue(Arrays.equals(new short[] { 2 }, array));
596 assertEquals(Short.TYPE, array.getClass().getComponentType());
597 array = ArrayUtils.removeAll(new short[] { 1, 2 }, 1);
598 assertTrue(Arrays.equals(new short[] { 1 }, array));
599 assertEquals(Short.TYPE, array.getClass().getComponentType());
600 array = ArrayUtils.removeAll(new short[] { 1, 2, 1 }, 1);
601 assertTrue(Arrays.equals(new short[] { 1, 1 }, array));
602 assertEquals(Short.TYPE, array.getClass().getComponentType());
603
604 array = ArrayUtils.removeAll(new short[] { 1, 2 }, 0, 1);
605 assertTrue(Arrays.equals(ArrayUtils.EMPTY_SHORT_ARRAY, array));
606 assertEquals(Short.TYPE, array.getClass().getComponentType());
607 array = ArrayUtils.removeAll(new short[] { 1, 2, 3 }, 0, 1);
608 assertTrue(Arrays.equals(new short[] { 3 }, array));
609 assertEquals(Short.TYPE, array.getClass().getComponentType());
610 array = ArrayUtils.removeAll(new short[] { 1, 2, 3 }, 1, 2);
611 assertTrue(Arrays.equals(new short[] { 1 }, array));
612 assertEquals(Short.TYPE, array.getClass().getComponentType());
613 array = ArrayUtils.removeAll(new short[] { 1, 2, 3 }, 0, 2);
614 assertTrue(Arrays.equals(new short[] { 2 }, array));
615 assertEquals(Short.TYPE, array.getClass().getComponentType());
616 array = ArrayUtils.removeAll(new short[] { 1, 2, 3, 4, 5 }, 1, 3);
617 assertTrue(Arrays.equals(new short[] { 1, 3, 5 }, array));
618 assertEquals(Short.TYPE, array.getClass().getComponentType());
619 array = ArrayUtils.removeAll(new short[] { 1, 2, 3, 4, 5 }, 0, 2, 4);
620 assertTrue(Arrays.equals(new short[] { 2, 4 }, array));
621 assertEquals(Short.TYPE, array.getClass().getComponentType());
622 array = ArrayUtils.removeAll(new short[] { 1, 2, 3, 4, 5, 6, 7 }, 1, 3, 5);
623 assertTrue(Arrays.equals(new short[] { 1, 3, 5, 7 }, array));
624 assertEquals(Short.TYPE, array.getClass().getComponentType());
625 array = ArrayUtils.removeAll(new short[] { 1, 2, 3, 4, 5, 6, 7 }, 0, 2, 4, 6);
626 assertTrue(Arrays.equals(new short[] { 2, 4, 6 }, array));
627 assertEquals(Short.TYPE, array.getClass().getComponentType());
628 }
629
630 @Test
631 public void testRemoveAllShortArrayRemoveNone() {
632 short[] array1 = new short[] { 1, 2 };
633 short[] array2 = ArrayUtils.removeAll(array1);
634 assertNotSame(array1, array2);
635 assertArrayEquals(array1, array2);
636 assertEquals(short.class, array2.getClass().getComponentType());
637 }
638
639 @Test(expected = IndexOutOfBoundsException.class)
640 public void testRemoveAllShortArrayNegativeIndex() {
641 ArrayUtils.removeAll(new short[] { 1, 2 }, -1, 0);
642 }
643
644 @Test(expected = IndexOutOfBoundsException.class)
645 public void testRemoveAllShortArrayOutOfBoundsIndex() {
646 ArrayUtils.removeAll(new short[] { 1, 2 }, 2, 0);
647 }
648
649 @Test(expected = IndexOutOfBoundsException.class)
650 public void testRemoveAllNullShortArray() {
651 ArrayUtils.removeAll((short[]) null, 0);
652 }
653
654 @Test
655 public void testRemoveElementsObjectArray() {
656 Object[] array;
657 array = ArrayUtils.removeElements((Object[]) null, "a");
658 assertNull(array);
659 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_OBJECT_ARRAY, "a");
660 assertTrue(Arrays.equals(ArrayUtils.EMPTY_OBJECT_ARRAY, array));
661 assertEquals(Object.class, array.getClass().getComponentType());
662 array = ArrayUtils.removeElements(new Object[] { "a" }, "a");
663 assertTrue(Arrays.equals(ArrayUtils.EMPTY_OBJECT_ARRAY, array));
664 assertEquals(Object.class, array.getClass().getComponentType());
665 array = ArrayUtils.removeElements(new Object[] { "a", "b" }, "a");
666 assertTrue(Arrays.equals(new Object[] { "b" }, array));
667 assertEquals(Object.class, array.getClass().getComponentType());
668 array = ArrayUtils.removeElements(new Object[] { "a", "b", "a" }, "a");
669 assertTrue(Arrays.equals(new Object[] { "b", "a" }, array));
670 assertEquals(Object.class, array.getClass().getComponentType());
671
672 array = ArrayUtils.removeElements((Object[]) null, "a", "b");
673 assertNull(array);
674 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_OBJECT_ARRAY, "a", "b");
675 assertTrue(Arrays.equals(ArrayUtils.EMPTY_OBJECT_ARRAY, array));
676 assertEquals(Object.class, array.getClass().getComponentType());
677 array = ArrayUtils.removeElements(new Object[] { "a" }, "a", "b");
678 assertTrue(Arrays.equals(ArrayUtils.EMPTY_OBJECT_ARRAY, array));
679 assertEquals(Object.class, array.getClass().getComponentType());
680 array = ArrayUtils.removeElements(new Object[] { "a", "b" }, "a", "c");
681 assertTrue(Arrays.equals(new Object[] { "b" }, array));
682 assertEquals(Object.class, array.getClass().getComponentType());
683 array = ArrayUtils.removeElements(new Object[] { "a", "b", "a" }, "a");
684 assertTrue(Arrays.equals(new Object[] { "b", "a" }, array));
685 assertEquals(Object.class, array.getClass().getComponentType());
686 array = ArrayUtils.removeElements(new Object[] { "a", "b", "a" }, "a", "b");
687 assertTrue(Arrays.equals(new Object[] { "a" }, array));
688 assertEquals(Object.class, array.getClass().getComponentType());
689 array = ArrayUtils.removeElements(new Object[] { "a", "b", "a" }, "a", "a");
690 assertTrue(Arrays.equals(new Object[] { "b" }, array));
691 assertEquals(Object.class, array.getClass().getComponentType());
692 array = ArrayUtils.removeElements(new Object[] { "a", "b", "a" }, "a", "a", "a", "a");
693 assertTrue(Arrays.equals(new Object[] { "b" }, array));
694 assertEquals(Object.class, array.getClass().getComponentType());
695 }
696
697 @Test
698 public void testRemoveElementBooleanArray() {
699 boolean[] array;
700 array = ArrayUtils.removeElements((boolean[]) null, true);
701 assertNull(array);
702 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_BOOLEAN_ARRAY, true);
703 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, array));
704 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
705 array = ArrayUtils.removeElements(new boolean[] { true }, true);
706 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, array));
707 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
708 array = ArrayUtils.removeElements(new boolean[] { true, false }, true);
709 assertTrue(Arrays.equals(new boolean[] { false }, array));
710 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
711 array = ArrayUtils.removeElements(new boolean[] { true, false, true }, true);
712 assertTrue(Arrays.equals(new boolean[] { false, true }, array));
713 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
714
715 array = ArrayUtils.removeElements((boolean[]) null, true, false);
716 assertNull(array);
717 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_BOOLEAN_ARRAY, true, false);
718 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, array));
719 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
720 array = ArrayUtils.removeElements(new boolean[] { true }, true, false);
721 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, array));
722 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
723 array = ArrayUtils.removeElements(new boolean[] { true, false }, true, false);
724 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, array));
725 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
726 array = ArrayUtils.removeElements(new boolean[] { true, false }, true, true);
727 assertTrue(Arrays.equals(new boolean[] { false }, array));
728 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
729 array = ArrayUtils.removeElements(new boolean[] { true, false, true }, true, false);
730 assertTrue(Arrays.equals(new boolean[] { true }, array));
731 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
732 array = ArrayUtils.removeElements(new boolean[] { true, false, true }, true, true);
733 assertTrue(Arrays.equals(new boolean[] { false }, array));
734 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
735 array = ArrayUtils.removeElements(new boolean[] { true, false, true }, true, true, true, true);
736 assertTrue(Arrays.equals(new boolean[] { false }, array));
737 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
738 }
739
740 @Test
741 public void testRemoveElementByteArray() {
742 byte[] array;
743 array = ArrayUtils.removeElements((byte[]) null, (byte) 1);
744 assertNull(array);
745 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_BYTE_ARRAY, (byte) 1);
746 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BYTE_ARRAY, array));
747 assertEquals(Byte.TYPE, array.getClass().getComponentType());
748 array = ArrayUtils.removeElements(new byte[] { 1 }, (byte) 1);
749 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BYTE_ARRAY, array));
750 assertEquals(Byte.TYPE, array.getClass().getComponentType());
751 array = ArrayUtils.removeElements(new byte[] { 1, 2 }, (byte) 1);
752 assertTrue(Arrays.equals(new byte[] { 2 }, array));
753 assertEquals(Byte.TYPE, array.getClass().getComponentType());
754 array = ArrayUtils.removeElements(new byte[] { 1, 2, 1 }, (byte) 1);
755 assertTrue(Arrays.equals(new byte[] { 2, 1 }, array));
756 assertEquals(Byte.TYPE, array.getClass().getComponentType());
757
758 array = ArrayUtils.removeElements((byte[]) null, (byte) 1, (byte) 2);
759 assertNull(array);
760 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_BYTE_ARRAY, (byte) 1, (byte) 2);
761 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BYTE_ARRAY, array));
762 assertEquals(Byte.TYPE, array.getClass().getComponentType());
763 array = ArrayUtils.removeElements(new byte[] { 1 }, (byte) 1, (byte) 2);
764 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BYTE_ARRAY, array));
765 assertEquals(Byte.TYPE, array.getClass().getComponentType());
766 array = ArrayUtils.removeElements(new byte[] { 1, 2 }, (byte) 1, (byte) 2);
767 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BYTE_ARRAY, array));
768 assertEquals(Byte.TYPE, array.getClass().getComponentType());
769 array = ArrayUtils.removeElements(new byte[] { 1, 2 }, (byte) 1, (byte) 1);
770 assertTrue(Arrays.equals(new byte[] { 2 }, array));
771 assertEquals(Byte.TYPE, array.getClass().getComponentType());
772 array = ArrayUtils.removeElements(new byte[] { 1, 2, 1 }, (byte) 1, (byte) 2);
773 assertTrue(Arrays.equals(new byte[] { 1 }, array));
774 assertEquals(Byte.TYPE, array.getClass().getComponentType());
775 array = ArrayUtils.removeElements(new byte[] { 1, 2, 1 }, (byte) 1, (byte) 1);
776 assertTrue(Arrays.equals(new byte[] { 2 }, array));
777 assertEquals(Byte.TYPE, array.getClass().getComponentType());
778 array = ArrayUtils.removeElements(new byte[] { 1, 2, 1 }, (byte) 1, (byte) 1, (byte) 1, (byte) 1);
779 assertTrue(Arrays.equals(new byte[] { 2 }, array));
780 assertEquals(Byte.TYPE, array.getClass().getComponentType());
781 }
782
783 @Test
784 public void testRemoveElementCharArray() {
785 char[] array;
786 array = ArrayUtils.removeElements((char[]) null, 'a');
787 assertNull(array);
788 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_CHAR_ARRAY, 'a');
789 assertTrue(Arrays.equals(ArrayUtils.EMPTY_CHAR_ARRAY, array));
790 assertEquals(Character.TYPE, array.getClass().getComponentType());
791 array = ArrayUtils.removeElements(new char[] { 'a' }, 'a');
792 assertTrue(Arrays.equals(ArrayUtils.EMPTY_CHAR_ARRAY, array));
793 assertEquals(Character.TYPE, array.getClass().getComponentType());
794 array = ArrayUtils.removeElements(new char[] { 'a', 'b' }, 'a');
795 assertTrue(Arrays.equals(new char[] { 'b' }, array));
796 assertEquals(Character.TYPE, array.getClass().getComponentType());
797 array = ArrayUtils.removeElements(new char[] { 'a', 'b', 'a' }, 'a');
798 assertTrue(Arrays.equals(new char[] { 'b', 'a' }, array));
799 assertEquals(Character.TYPE, array.getClass().getComponentType());
800
801 array = ArrayUtils.removeElements((char[]) null, 'a', 'b');
802 assertNull(array);
803 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_CHAR_ARRAY, 'a', 'b');
804 assertTrue(Arrays.equals(ArrayUtils.EMPTY_CHAR_ARRAY, array));
805 assertEquals(Character.TYPE, array.getClass().getComponentType());
806 array = ArrayUtils.removeElements(new char[] { 'a' }, 'a', 'b');
807 assertTrue(Arrays.equals(ArrayUtils.EMPTY_CHAR_ARRAY, array));
808 assertEquals(Character.TYPE, array.getClass().getComponentType());
809 array = ArrayUtils.removeElements(new char[] { 'a', 'b' }, 'a', 'b');
810 assertTrue(Arrays.equals(ArrayUtils.EMPTY_CHAR_ARRAY, array));
811 assertEquals(Character.TYPE, array.getClass().getComponentType());
812 array = ArrayUtils.removeElements(new char[] { 'a', 'b' }, 'a', 'a');
813 assertTrue(Arrays.equals(new char[] { 'b' }, array));
814 assertEquals(Character.TYPE, array.getClass().getComponentType());
815 array = ArrayUtils.removeElements(new char[] { 'a', 'b', 'a' }, 'a', 'b');
816 assertTrue(Arrays.equals(new char[] { 'a' }, array));
817 assertEquals(Character.TYPE, array.getClass().getComponentType());
818 array = ArrayUtils.removeElements(new char[] { 'a', 'b', 'a' }, 'a', 'a');
819 assertTrue(Arrays.equals(new char[] { 'b' }, array));
820 assertEquals(Character.TYPE, array.getClass().getComponentType());
821 array = ArrayUtils.removeElements(new char[] { 'a', 'b', 'a' }, 'a', 'a', 'a', 'a');
822 assertTrue(Arrays.equals(new char[] { 'b' }, array));
823 assertEquals(Character.TYPE, array.getClass().getComponentType());
824 }
825
826 @Test
827 @SuppressWarnings("cast")
828 public void testRemoveElementDoubleArray() {
829 double[] array;
830 array = ArrayUtils.removeElements((double[]) null, (double) 1);
831 assertNull(array);
832 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_DOUBLE_ARRAY, (double) 1);
833 assertTrue(Arrays.equals(ArrayUtils.EMPTY_DOUBLE_ARRAY, array));
834 assertEquals(Double.TYPE, array.getClass().getComponentType());
835 array = ArrayUtils.removeElements(new double[] { 1 }, (double) 1);
836 assertTrue(Arrays.equals(ArrayUtils.EMPTY_DOUBLE_ARRAY, array));
837 assertEquals(Double.TYPE, array.getClass().getComponentType());
838 array = ArrayUtils.removeElements(new double[] { 1, 2 }, (double) 1);
839 assertTrue(Arrays.equals(new double[] { 2 }, array));
840 assertEquals(Double.TYPE, array.getClass().getComponentType());
841 array = ArrayUtils.removeElements(new double[] { 1, 2, 1 }, (double) 1);
842 assertTrue(Arrays.equals(new double[] { 2, 1 }, array));
843 assertEquals(Double.TYPE, array.getClass().getComponentType());
844
845 array = ArrayUtils.removeElements((double[]) null, (double) 1, (double) 2);
846 assertNull(array);
847 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_DOUBLE_ARRAY, (double) 1, (double) 2);
848 assertTrue(Arrays.equals(ArrayUtils.EMPTY_DOUBLE_ARRAY, array));
849 assertEquals(Double.TYPE, array.getClass().getComponentType());
850 array = ArrayUtils.removeElements(new double[] { 1 }, (double) 1, (double) 2);
851 assertTrue(Arrays.equals(ArrayUtils.EMPTY_DOUBLE_ARRAY, array));
852 assertEquals(Double.TYPE, array.getClass().getComponentType());
853 array = ArrayUtils.removeElements(new double[] { 1, 2 }, (double) 1, (double) 2);
854 assertTrue(Arrays.equals(ArrayUtils.EMPTY_DOUBLE_ARRAY, array));
855 assertEquals(Double.TYPE, array.getClass().getComponentType());
856 array = ArrayUtils.removeElements(new double[] { 1, 2 }, (double) 1, (double) 1);
857 assertTrue(Arrays.equals(new double[] { 2 }, array));
858 assertEquals(Double.TYPE, array.getClass().getComponentType());
859 array = ArrayUtils.removeElements(new double[] { 1, 2, 1 }, (double) 1, (double) 2);
860 assertTrue(Arrays.equals(new double[] { 1 }, array));
861 assertEquals(Double.TYPE, array.getClass().getComponentType());
862 array = ArrayUtils.removeElements(new double[] { 1, 2, 1 }, (double) 1, (double) 1);
863 assertTrue(Arrays.equals(new double[] { 2 }, array));
864 assertEquals(Double.TYPE, array.getClass().getComponentType());
865 array = ArrayUtils.removeElements(new double[] { 1, 2, 1 }, (double) 1, (double) 1, (double) 1, (double) 1);
866 assertTrue(Arrays.equals(new double[] { 2 }, array));
867 assertEquals(Double.TYPE, array.getClass().getComponentType());
868 }
869
870 @Test
871 @SuppressWarnings("cast")
872 public void testRemoveElementFloatArray() {
873 float[] array;
874 array = ArrayUtils.removeElements((float[]) null, (float) 1);
875 assertNull(array);
876 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_FLOAT_ARRAY, (float) 1);
877 assertTrue(Arrays.equals(ArrayUtils.EMPTY_FLOAT_ARRAY, array));
878 assertEquals(Float.TYPE, array.getClass().getComponentType());
879 array = ArrayUtils.removeElements(new float[] { 1 }, (float) 1);
880 assertTrue(Arrays.equals(ArrayUtils.EMPTY_FLOAT_ARRAY, array));
881 assertEquals(Float.TYPE, array.getClass().getComponentType());
882 array = ArrayUtils.removeElements(new float[] { 1, 2 }, (float) 1);
883 assertTrue(Arrays.equals(new float[] { 2 }, array));
884 assertEquals(Float.TYPE, array.getClass().getComponentType());
885 array = ArrayUtils.removeElements(new float[] { 1, 2, 1 }, (float) 1);
886 assertTrue(Arrays.equals(new float[] { 2, 1 }, array));
887 assertEquals(Float.TYPE, array.getClass().getComponentType());
888
889 array = ArrayUtils.removeElements((float[]) null, (float) 1, (float) 1);
890 assertNull(array);
891 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_FLOAT_ARRAY, (float) 1, (float) 1);
892 assertTrue(Arrays.equals(ArrayUtils.EMPTY_FLOAT_ARRAY, array));
893 assertEquals(Float.TYPE, array.getClass().getComponentType());
894 array = ArrayUtils.removeElements(new float[] { 1 }, (float) 1, (float) 1);
895 assertTrue(Arrays.equals(ArrayUtils.EMPTY_FLOAT_ARRAY, array));
896 assertEquals(Float.TYPE, array.getClass().getComponentType());
897 array = ArrayUtils.removeElements(new float[] { 1, 2 }, (float) 1, (float) 2);
898 assertTrue(Arrays.equals(ArrayUtils.EMPTY_FLOAT_ARRAY, array));
899 assertEquals(Float.TYPE, array.getClass().getComponentType());
900 array = ArrayUtils.removeElements(new float[] { 1, 2 }, (float) 1, (float) 1);
901 assertTrue(Arrays.equals(new float[] { 2 }, array));
902 assertEquals(Float.TYPE, array.getClass().getComponentType());
903 array = ArrayUtils.removeElements(new float[] { 1, 2, 1 }, (float) 1, (float) 1);
904 assertTrue(Arrays.equals(new float[] { 2 }, array));
905 assertEquals(Float.TYPE, array.getClass().getComponentType());
906 array = ArrayUtils.removeElements(new float[] { 1, 2, 1 }, (float) 1, (float) 2);
907 assertTrue(Arrays.equals(new float[] { 1 }, array));
908 assertEquals(Float.TYPE, array.getClass().getComponentType());
909 array = ArrayUtils.removeElements(new float[] { 1, 2, 1 }, (float) 1, (float) 1, (float) 1, (float) 1);
910 assertTrue(Arrays.equals(new float[] { 2 }, array));
911 assertEquals(Float.TYPE, array.getClass().getComponentType());
912 }
913
914 @Test
915 public void testRemoveElementIntArray() {
916 int[] array;
917 array = ArrayUtils.removeElements((int[]) null, 1);
918 assertNull(array);
919 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_INT_ARRAY, 1);
920 assertTrue(Arrays.equals(ArrayUtils.EMPTY_INT_ARRAY, array));
921 assertEquals(Integer.TYPE, array.getClass().getComponentType());
922 array = ArrayUtils.removeElements(new int[] { 1 }, 1);
923 assertTrue(Arrays.equals(ArrayUtils.EMPTY_INT_ARRAY, array));
924 assertEquals(Integer.TYPE, array.getClass().getComponentType());
925 array = ArrayUtils.removeElements(new int[] { 1, 2 }, 1);
926 assertTrue(Arrays.equals(new int[] { 2 }, array));
927 assertEquals(Integer.TYPE, array.getClass().getComponentType());
928 array = ArrayUtils.removeElements(new int[] { 1, 2, 1 }, 1);
929 assertTrue(Arrays.equals(new int[] { 2, 1 }, array));
930 assertEquals(Integer.TYPE, array.getClass().getComponentType());
931
932 array = ArrayUtils.removeElements((int[]) null, 1);
933 assertNull(array);
934 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_INT_ARRAY, 1, 1);
935 assertTrue(Arrays.equals(ArrayUtils.EMPTY_INT_ARRAY, array));
936 assertEquals(Integer.TYPE, array.getClass().getComponentType());
937 array = ArrayUtils.removeElements(new int[] { 1 }, 1, 1);
938 assertTrue(Arrays.equals(ArrayUtils.EMPTY_INT_ARRAY, array));
939 assertEquals(Integer.TYPE, array.getClass().getComponentType());
940 array = ArrayUtils.removeElements(new int[] { 1, 2 }, 1, 2);
941 assertTrue(Arrays.equals(ArrayUtils.EMPTY_INT_ARRAY, array));
942 assertEquals(Integer.TYPE, array.getClass().getComponentType());
943 array = ArrayUtils.removeElements(new int[] { 1, 2 }, 1, 1);
944 assertTrue(Arrays.equals(new int[] { 2 }, array));
945 assertEquals(Integer.TYPE, array.getClass().getComponentType());
946 array = ArrayUtils.removeElements(new int[] { 1, 2, 1 }, 1, 2);
947 assertTrue(Arrays.equals(new int[] { 1 }, array));
948 assertEquals(Integer.TYPE, array.getClass().getComponentType());
949 array = ArrayUtils.removeElements(new int[] { 1, 2, 1 }, 1, 1);
950 assertTrue(Arrays.equals(new int[] { 2 }, array));
951 assertEquals(Integer.TYPE, array.getClass().getComponentType());
952 array = ArrayUtils.removeElements(new int[] { 1, 2, 1 }, 1, 1, 1, 1);
953 assertTrue(Arrays.equals(new int[] { 2 }, array));
954 assertEquals(Integer.TYPE, array.getClass().getComponentType());
955 }
956
957 @Test
958 @SuppressWarnings("cast")
959 public void testRemoveElementLongArray() {
960 long[] array;
961 array = ArrayUtils.removeElements((long[]) null, (long) 1);
962 assertNull(array);
963 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_LONG_ARRAY, (long) 1);
964 assertTrue(Arrays.equals(ArrayUtils.EMPTY_LONG_ARRAY, array));
965 assertEquals(Long.TYPE, array.getClass().getComponentType());
966 array = ArrayUtils.removeElements(new long[] { 1 }, (long) 1);
967 assertTrue(Arrays.equals(ArrayUtils.EMPTY_LONG_ARRAY, array));
968 assertEquals(Long.TYPE, array.getClass().getComponentType());
969 array = ArrayUtils.removeElements(new long[] { 1, 2 }, (long) 1);
970 assertTrue(Arrays.equals(new long[] { 2 }, array));
971 assertEquals(Long.TYPE, array.getClass().getComponentType());
972 array = ArrayUtils.removeElements(new long[] { 1, 2, 1 }, (long) 1);
973 assertTrue(Arrays.equals(new long[] { 2, 1 }, array));
974 assertEquals(Long.TYPE, array.getClass().getComponentType());
975
976 array = ArrayUtils.removeElements((long[]) null, (long) 1, (long) 1);
977 assertNull(array);
978 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_LONG_ARRAY, (long) 1, (long) 1);
979 assertTrue(Arrays.equals(ArrayUtils.EMPTY_LONG_ARRAY, array));
980 assertEquals(Long.TYPE, array.getClass().getComponentType());
981 array = ArrayUtils.removeElements(new long[] { 1 }, (long) 1, (long) 1);
982 assertTrue(Arrays.equals(ArrayUtils.EMPTY_LONG_ARRAY, array));
983 assertEquals(Long.TYPE, array.getClass().getComponentType());
984 array = ArrayUtils.removeElements(new long[] { 1, 2 }, (long) 1, (long) 2);
985 assertTrue(Arrays.equals(ArrayUtils.EMPTY_LONG_ARRAY, array));
986 assertEquals(Long.TYPE, array.getClass().getComponentType());
987 array = ArrayUtils.removeElements(new long[] { 1, 2 }, (long) 1, (long) 1);
988 assertTrue(Arrays.equals(new long[] { 2 }, array));
989 assertEquals(Long.TYPE, array.getClass().getComponentType());
990 array = ArrayUtils.removeElements(new long[] { 1, 2, 1 }, (long) 1, (long) 1);
991 assertTrue(Arrays.equals(new long[] { 2 }, array));
992 assertEquals(Long.TYPE, array.getClass().getComponentType());
993 array = ArrayUtils.removeElements(new long[] { 1, 2, 1 }, (long) 1, (long) 2);
994 assertTrue(Arrays.equals(new long[] { 1 }, array));
995 assertEquals(Long.TYPE, array.getClass().getComponentType());
996 array = ArrayUtils.removeElements(new long[] { 1, 2, 1 }, (long) 1, (long) 1, (long) 1, (long) 1);
997 assertTrue(Arrays.equals(new long[] { 2 }, array));
998 assertEquals(Long.TYPE, array.getClass().getComponentType());
999 }
1000
1001 @Test
1002 public void testRemoveElementShortArray() {
1003 short[] array;
1004 array = ArrayUtils.removeElements((short[]) null, (short) 1);
1005 assertNull(array);
1006 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_SHORT_ARRAY, (short) 1);
1007 assertTrue(Arrays.equals(ArrayUtils.EMPTY_SHORT_ARRAY, array));
1008 assertEquals(Short.TYPE, array.getClass().getComponentType());
1009 array = ArrayUtils.removeElements(new short[] { 1 }, (short) 1);
1010 assertTrue(Arrays.equals(ArrayUtils.EMPTY_SHORT_ARRAY, array));
1011 assertEquals(Short.TYPE, array.getClass().getComponentType());
1012 array = ArrayUtils.removeElements(new short[] { 1, 2 }, (short) 1);
1013 assertTrue(Arrays.equals(new short[] { 2 }, array));
1014 assertEquals(Short.TYPE, array.getClass().getComponentType());
1015 array = ArrayUtils.removeElements(new short[] { 1, 2, 1 }, (short) 1);
1016 assertTrue(Arrays.equals(new short[] { 2, 1 }, array));
1017 assertEquals(Short.TYPE, array.getClass().getComponentType());
1018
1019 array = ArrayUtils.removeElements((short[]) null, (short) 1, (short) 1);
1020 assertNull(array);
1021 array = ArrayUtils.removeElements(ArrayUtils.EMPTY_SHORT_ARRAY, (short) 1, (short) 1);
1022 assertTrue(Arrays.equals(ArrayUtils.EMPTY_SHORT_ARRAY, array));
1023 assertEquals(Short.TYPE, array.getClass().getComponentType());
1024 array = ArrayUtils.removeElements(new short[] { 1 }, (short) 1, (short) 1);
1025 assertTrue(Arrays.equals(ArrayUtils.EMPTY_SHORT_ARRAY, array));
1026 assertEquals(Short.TYPE, array.getClass().getComponentType());
1027 array = ArrayUtils.removeElements(new short[] { 1, 2 }, (short) 1, (short) 2);
1028 assertTrue(Arrays.equals(ArrayUtils.EMPTY_SHORT_ARRAY, array));
1029 assertEquals(Short.TYPE, array.getClass().getComponentType());
1030 array = ArrayUtils.removeElements(new short[] { 1, 2 }, (short) 1, (short) 1);
1031 assertTrue(Arrays.equals(new short[] { 2 }, array));
1032 assertEquals(Short.TYPE, array.getClass().getComponentType());
1033 array = ArrayUtils.removeElements(new short[] { 1, 2, 1 }, (short) 1, (short) 1);
1034 assertTrue(Arrays.equals(new short[] { 2 }, array));
1035 assertEquals(Short.TYPE, array.getClass().getComponentType());
1036 array = ArrayUtils.removeElements(new short[] { 1, 2, 1 }, (short) 1, (short) 2);
1037 assertTrue(Arrays.equals(new short[] { 1 }, array));
1038 assertEquals(Short.TYPE, array.getClass().getComponentType());
1039 array = ArrayUtils.removeElements(new short[] { 1, 2, 1 }, (short) 1, (short) 1, (short) 1, (short) 1);
1040 assertTrue(Arrays.equals(new short[] { 2 }, array));
1041 assertEquals(Short.TYPE, array.getClass().getComponentType());
1042 }
1043
1044 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3;
18
19 import java.util.Arrays;
20
21 import junit.framework.TestCase;
22
23 /**
24 * Tests ArrayUtils remove and removeElement methods.
25 *
26 * @version $Id: ArrayUtilsRemoveTest.java 1088899 2011-04-05 05:31:27Z bayard $
27 */
28 public class ArrayUtilsRemoveTest extends TestCase {
29
30 public void testRemoveObjectArray() {
31 Object[] array;
32 array = ArrayUtils.remove(new Object[] {"a"}, 0);
33 assertTrue(Arrays.equals(ArrayUtils.EMPTY_OBJECT_ARRAY, array));
34 assertEquals(Object.class, array.getClass().getComponentType());
35 array = ArrayUtils.remove(new Object[] {"a", "b"}, 0);
36 assertTrue(Arrays.equals(new Object[] {"b"}, array));
37 assertEquals(Object.class, array.getClass().getComponentType());
38 array = ArrayUtils.remove(new Object[] {"a", "b"}, 1);
39 assertTrue(Arrays.equals(new Object[] {"a"}, array));
40 assertEquals(Object.class, array.getClass().getComponentType());
41 array = ArrayUtils.remove(new Object[] {"a", "b", "c"}, 1);
42 assertTrue(Arrays.equals(new Object[] {"a", "c"}, array));
43 assertEquals(Object.class, array.getClass().getComponentType());
44 try {
45 ArrayUtils.remove(new Object[] {"a", "b"}, -1);
46 fail("IndexOutOfBoundsException expected");
47 } catch (IndexOutOfBoundsException e) {}
48 try {
49 ArrayUtils.remove(new Object[] {"a", "b"}, 2);
50 fail("IndexOutOfBoundsException expected");
51 } catch (IndexOutOfBoundsException e) {}
52 try {
53 ArrayUtils.remove((Object[]) null, 0);
54 fail("IndexOutOfBoundsException expected");
55 } catch (IndexOutOfBoundsException e) {}
56 }
57
58 public void testRemoveNumberArray(){
59 Number[] inarray = {Integer.valueOf(1),Long.valueOf(2),Byte.valueOf((byte) 3)};
60 assertEquals(3, inarray.length);
61 Number[] outarray;
62 outarray = ArrayUtils.remove(inarray, 1);
63 assertEquals(2, outarray.length);
64 assertEquals(Number.class, outarray.getClass().getComponentType());
65 outarray = ArrayUtils.remove(outarray, 1);
66 assertEquals(1, outarray.length);
67 assertEquals(Number.class, outarray.getClass().getComponentType());
68 outarray = ArrayUtils.remove(outarray, 0);
69 assertEquals(0, outarray.length);
70 assertEquals(Number.class, outarray.getClass().getComponentType());
71 }
72
73 public void testRemoveBooleanArray() {
74 boolean[] array;
75 array = ArrayUtils.remove(new boolean[] {true}, 0);
76 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, array));
77 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
78 array = ArrayUtils.remove(new boolean[] {true, false}, 0);
79 assertTrue(Arrays.equals(new boolean[] {false}, array));
80 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
81 array = ArrayUtils.remove(new boolean[] {true, false}, 1);
82 assertTrue(Arrays.equals(new boolean[] {true}, array));
83 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
84 array = ArrayUtils.remove(new boolean[] {true, false, true}, 1);
85 assertTrue(Arrays.equals(new boolean[] {true, true}, array));
86 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
87 try {
88 ArrayUtils.remove(new boolean[] {true, false}, -1);
89 fail("IndexOutOfBoundsException expected");
90 } catch (IndexOutOfBoundsException e) {}
91 try {
92 ArrayUtils.remove(new boolean[] {true, false}, 2);
93 fail("IndexOutOfBoundsException expected");
94 } catch (IndexOutOfBoundsException e) {}
95 try {
96 ArrayUtils.remove((boolean[]) null, 0);
97 fail("IndexOutOfBoundsException expected");
98 } catch (IndexOutOfBoundsException e) {}
99 }
100
101 public void testRemoveByteArray() {
102 byte[] array;
103 array = ArrayUtils.remove(new byte[] {1}, 0);
104 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BYTE_ARRAY, array));
105 assertEquals(Byte.TYPE, array.getClass().getComponentType());
106 array = ArrayUtils.remove(new byte[] {1, 2}, 0);
107 assertTrue(Arrays.equals(new byte[] {2}, array));
108 assertEquals(Byte.TYPE, array.getClass().getComponentType());
109 array = ArrayUtils.remove(new byte[] {1, 2}, 1);
110 assertTrue(Arrays.equals(new byte[] {1}, array));
111 assertEquals(Byte.TYPE, array.getClass().getComponentType());
112 array = ArrayUtils.remove(new byte[] {1, 2, 1}, 1);
113 assertTrue(Arrays.equals(new byte[] {1, 1}, array));
114 assertEquals(Byte.TYPE, array.getClass().getComponentType());
115 try {
116 ArrayUtils.remove(new byte[] {1, 2}, -1);
117 fail("IndexOutOfBoundsException expected");
118 } catch (IndexOutOfBoundsException e) {}
119 try {
120 ArrayUtils.remove(new byte[] {1, 2}, 2);
121 fail("IndexOutOfBoundsException expected");
122 } catch (IndexOutOfBoundsException e) {}
123 try {
124 ArrayUtils.remove((byte[]) null, 0);
125 fail("IndexOutOfBoundsException expected");
126 } catch (IndexOutOfBoundsException e) {}
127 }
128
129 public void testRemoveCharArray() {
130 char[] array;
131 array = ArrayUtils.remove(new char[] {'a'}, 0);
132 assertTrue(Arrays.equals(ArrayUtils.EMPTY_CHAR_ARRAY, array));
133 assertEquals(Character.TYPE, array.getClass().getComponentType());
134 array = ArrayUtils.remove(new char[] {'a', 'b'}, 0);
135 assertTrue(Arrays.equals(new char[] {'b'}, array));
136 assertEquals(Character.TYPE, array.getClass().getComponentType());
137 array = ArrayUtils.remove(new char[] {'a', 'b'}, 1);
138 assertTrue(Arrays.equals(new char[] {'a'}, array));
139 assertEquals(Character.TYPE, array.getClass().getComponentType());
140 array = ArrayUtils.remove(new char[] {'a', 'b', 'c'}, 1);
141 assertTrue(Arrays.equals(new char[] {'a', 'c'}, array));
142 assertEquals(Character.TYPE, array.getClass().getComponentType());
143 try {
144 ArrayUtils.remove(new char[] {'a', 'b'}, -1);
145 fail("IndexOutOfBoundsException expected");
146 } catch (IndexOutOfBoundsException e) {}
147 try {
148 ArrayUtils.remove(new char[] {'a', 'b'}, 2);
149 fail("IndexOutOfBoundsException expected");
150 } catch (IndexOutOfBoundsException e) {}
151 try {
152 ArrayUtils.remove((char[]) null, 0);
153 fail("IndexOutOfBoundsException expected");
154 } catch (IndexOutOfBoundsException e) {}
155 }
156
157 public void testRemoveDoubleArray() {
158 double[] array;
159 array = ArrayUtils.remove(new double[] {1}, 0);
160 assertTrue(Arrays.equals(ArrayUtils.EMPTY_DOUBLE_ARRAY, array));
161 assertEquals(Double.TYPE, array.getClass().getComponentType());
162 array = ArrayUtils.remove(new double[] {1, 2}, 0);
163 assertTrue(Arrays.equals(new double[] {2}, array));
164 assertEquals(Double.TYPE, array.getClass().getComponentType());
165 array = ArrayUtils.remove(new double[] {1, 2}, 1);
166 assertTrue(Arrays.equals(new double[] {1}, array));
167 assertEquals(Double.TYPE, array.getClass().getComponentType());
168 array = ArrayUtils.remove(new double[] {1, 2, 1}, 1);
169 assertTrue(Arrays.equals(new double[] {1, 1}, array));
170 assertEquals(Double.TYPE, array.getClass().getComponentType());
171 try {
172 ArrayUtils.remove(new double[] {1, 2}, -1);
173 fail("IndexOutOfBoundsException expected");
174 } catch (IndexOutOfBoundsException e) {}
175 try {
176 ArrayUtils.remove(new double[] {1, 2}, 2);
177 fail("IndexOutOfBoundsException expected");
178 } catch (IndexOutOfBoundsException e) {}
179 try {
180 ArrayUtils.remove((double[]) null, 0);
181 fail("IndexOutOfBoundsException expected");
182 } catch (IndexOutOfBoundsException e) {}
183 }
184
185 public void testRemoveFloatArray() {
186 float[] array;
187 array = ArrayUtils.remove(new float[] {1}, 0);
188 assertTrue(Arrays.equals(ArrayUtils.EMPTY_FLOAT_ARRAY, array));
189 assertEquals(Float.TYPE, array.getClass().getComponentType());
190 array = ArrayUtils.remove(new float[] {1, 2}, 0);
191 assertTrue(Arrays.equals(new float[] {2}, array));
192 assertEquals(Float.TYPE, array.getClass().getComponentType());
193 array = ArrayUtils.remove(new float[] {1, 2}, 1);
194 assertTrue(Arrays.equals(new float[] {1}, array));
195 assertEquals(Float.TYPE, array.getClass().getComponentType());
196 array = ArrayUtils.remove(new float[] {1, 2, 1}, 1);
197 assertTrue(Arrays.equals(new float[] {1, 1}, array));
198 assertEquals(Float.TYPE, array.getClass().getComponentType());
199 try {
200 ArrayUtils.remove(new float[] {1, 2}, -1);
201 fail("IndexOutOfBoundsException expected");
202 } catch (IndexOutOfBoundsException e) {}
203 try {
204 ArrayUtils.remove(new float[] {1, 2}, 2);
205 fail("IndexOutOfBoundsException expected");
206 } catch (IndexOutOfBoundsException e) {}
207 try {
208 ArrayUtils.remove((float[]) null, 0);
209 fail("IndexOutOfBoundsException expected");
210 } catch (IndexOutOfBoundsException e) {}
211 }
212
213 public void testRemoveIntArray() {
214 int[] array;
215 array = ArrayUtils.remove(new int[] {1}, 0);
216 assertTrue(Arrays.equals(ArrayUtils.EMPTY_INT_ARRAY, array));
217 assertEquals(Integer.TYPE, array.getClass().getComponentType());
218 array = ArrayUtils.remove(new int[] {1, 2}, 0);
219 assertTrue(Arrays.equals(new int[] {2}, array));
220 assertEquals(Integer.TYPE, array.getClass().getComponentType());
221 array = ArrayUtils.remove(new int[] {1, 2}, 1);
222 assertTrue(Arrays.equals(new int[] {1}, array));
223 assertEquals(Integer.TYPE, array.getClass().getComponentType());
224 array = ArrayUtils.remove(new int[] {1, 2, 1}, 1);
225 assertTrue(Arrays.equals(new int[] {1, 1}, array));
226 assertEquals(Integer.TYPE, array.getClass().getComponentType());
227 try {
228 ArrayUtils.remove(new int[] {1, 2}, -1);
229 fail("IndexOutOfBoundsException expected");
230 } catch (IndexOutOfBoundsException e) {}
231 try {
232 ArrayUtils.remove(new int[] {1, 2}, 2);
233 fail("IndexOutOfBoundsException expected");
234 } catch (IndexOutOfBoundsException e) {}
235 try {
236 ArrayUtils.remove((int[]) null, 0);
237 fail("IndexOutOfBoundsException expected");
238 } catch (IndexOutOfBoundsException e) {}
239 }
240
241 public void testRemoveLongArray() {
242 long[] array;
243 array = ArrayUtils.remove(new long[] {1}, 0);
244 assertTrue(Arrays.equals(ArrayUtils.EMPTY_LONG_ARRAY, array));
245 assertEquals(Long.TYPE, array.getClass().getComponentType());
246 array = ArrayUtils.remove(new long[] {1, 2}, 0);
247 assertTrue(Arrays.equals(new long[] {2}, array));
248 assertEquals(Long.TYPE, array.getClass().getComponentType());
249 array = ArrayUtils.remove(new long[] {1, 2}, 1);
250 assertTrue(Arrays.equals(new long[] {1}, array));
251 assertEquals(Long.TYPE, array.getClass().getComponentType());
252 array = ArrayUtils.remove(new long[] {1, 2, 1}, 1);
253 assertTrue(Arrays.equals(new long[] {1, 1}, array));
254 assertEquals(Long.TYPE, array.getClass().getComponentType());
255 try {
256 ArrayUtils.remove(new long[] {1, 2}, -1);
257 fail("IndexOutOfBoundsException expected");
258 } catch (IndexOutOfBoundsException e) {}
259 try {
260 ArrayUtils.remove(new long[] {1, 2}, 2);
261 fail("IndexOutOfBoundsException expected");
262 } catch (IndexOutOfBoundsException e) {}
263 try {
264 ArrayUtils.remove((long[]) null, 0);
265 fail("IndexOutOfBoundsException expected");
266 } catch (IndexOutOfBoundsException e) {}
267 }
268
269 public void testRemoveShortArray() {
270 short[] array;
271 array = ArrayUtils.remove(new short[] {1}, 0);
272 assertTrue(Arrays.equals(ArrayUtils.EMPTY_SHORT_ARRAY, array));
273 assertEquals(Short.TYPE, array.getClass().getComponentType());
274 array = ArrayUtils.remove(new short[] {1, 2}, 0);
275 assertTrue(Arrays.equals(new short[] {2}, array));
276 assertEquals(Short.TYPE, array.getClass().getComponentType());
277 array = ArrayUtils.remove(new short[] {1, 2}, 1);
278 assertTrue(Arrays.equals(new short[] {1}, array));
279 assertEquals(Short.TYPE, array.getClass().getComponentType());
280 array = ArrayUtils.remove(new short[] {1, 2, 1}, 1);
281 assertTrue(Arrays.equals(new short[] {1, 1}, array));
282 assertEquals(Short.TYPE, array.getClass().getComponentType());
283 try {
284 ArrayUtils.remove(new short[] {1, 2}, -1);
285 fail("IndexOutOfBoundsException expected");
286 } catch (IndexOutOfBoundsException e) {}
287 try {
288 ArrayUtils.remove(new short[] {1, 2}, 2);
289 fail("IndexOutOfBoundsException expected");
290 } catch (IndexOutOfBoundsException e) {}
291 try {
292 ArrayUtils.remove((short[]) null, 0);
293 fail("IndexOutOfBoundsException expected");
294 } catch (IndexOutOfBoundsException e) {}
295 }
296
297 public void testRemoveElementObjectArray() {
298 Object[] array;
299 array = ArrayUtils.removeElement((Object[]) null, "a");
300 assertNull(array);
301 array = ArrayUtils.removeElement(ArrayUtils.EMPTY_OBJECT_ARRAY, "a");
302 assertTrue(Arrays.equals(ArrayUtils.EMPTY_OBJECT_ARRAY, array));
303 assertEquals(Object.class, array.getClass().getComponentType());
304 array = ArrayUtils.removeElement(new Object[] {"a"}, "a");
305 assertTrue(Arrays.equals(ArrayUtils.EMPTY_OBJECT_ARRAY, array));
306 assertEquals(Object.class, array.getClass().getComponentType());
307 array = ArrayUtils.removeElement(new Object[] {"a", "b"}, "a");
308 assertTrue(Arrays.equals(new Object[] {"b"}, array));
309 assertEquals(Object.class, array.getClass().getComponentType());
310 array = ArrayUtils.removeElement(new Object[] {"a", "b", "a"}, "a");
311 assertTrue(Arrays.equals(new Object[] {"b", "a"}, array));
312 assertEquals(Object.class, array.getClass().getComponentType());
313 }
314
315 public void testRemoveElementBooleanArray() {
316 boolean[] array;
317 array = ArrayUtils.removeElement((boolean[]) null, true);
318 assertNull(array);
319 array = ArrayUtils.removeElement(ArrayUtils.EMPTY_BOOLEAN_ARRAY, true);
320 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, array));
321 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
322 array = ArrayUtils.removeElement(new boolean[] {true}, true);
323 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, array));
324 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
325 array = ArrayUtils.removeElement(new boolean[] {true, false}, true);
326 assertTrue(Arrays.equals(new boolean[] {false}, array));
327 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
328 array = ArrayUtils.removeElement(new boolean[] {true, false, true}, true);
329 assertTrue(Arrays.equals(new boolean[] {false, true}, array));
330 assertEquals(Boolean.TYPE, array.getClass().getComponentType());
331 }
332
333 public void testRemoveElementByteArray() {
334 byte[] array;
335 array = ArrayUtils.removeElement((byte[]) null, (byte) 1);
336 assertNull(array);
337 array = ArrayUtils.removeElement(ArrayUtils.EMPTY_BYTE_ARRAY, (byte) 1);
338 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BYTE_ARRAY, array));
339 assertEquals(Byte.TYPE, array.getClass().getComponentType());
340 array = ArrayUtils.removeElement(new byte[] {1}, (byte) 1);
341 assertTrue(Arrays.equals(ArrayUtils.EMPTY_BYTE_ARRAY, array));
342 assertEquals(Byte.TYPE, array.getClass().getComponentType());
343 array = ArrayUtils.removeElement(new byte[] {1, 2}, (byte) 1);
344 assertTrue(Arrays.equals(new byte[] {2}, array));
345 assertEquals(Byte.TYPE, array.getClass().getComponentType());
346 array = ArrayUtils.removeElement(new byte[] {1, 2, 1}, (byte) 1);
347 assertTrue(Arrays.equals(new byte[] {2, 1}, array));
348 assertEquals(Byte.TYPE, array.getClass().getComponentType());
349 }
350
351 public void testRemoveElementCharArray() {
352 char[] array;
353 array = ArrayUtils.removeElement((char[]) null, 'a');
354 assertNull(array);
355 array = ArrayUtils.removeElement(ArrayUtils.EMPTY_CHAR_ARRAY, 'a');
356 assertTrue(Arrays.equals(ArrayUtils.EMPTY_CHAR_ARRAY, array));
357 assertEquals(Character.TYPE, array.getClass().getComponentType());
358 array = ArrayUtils.removeElement(new char[] {'a'}, 'a');
359 assertTrue(Arrays.equals(ArrayUtils.EMPTY_CHAR_ARRAY, array));
360 assertEquals(Character.TYPE, array.getClass().getComponentType());
361 array = ArrayUtils.removeElement(new char[] {'a', 'b'}, 'a');
362 assertTrue(Arrays.equals(new char[] {'b'}, array));
363 assertEquals(Character.TYPE, array.getClass().getComponentType());
364 array = ArrayUtils.removeElement(new char[] {'a', 'b', 'a'}, 'a');
365 assertTrue(Arrays.equals(new char[] {'b', 'a'}, array));
366 assertEquals(Character.TYPE, array.getClass().getComponentType());
367 }
368
369 @SuppressWarnings("cast")
370 public void testRemoveElementDoubleArray() {
371 double[] array;
372 array = ArrayUtils.removeElement((double[]) null, (double) 1);
373 assertNull(array);
374 array = ArrayUtils.removeElement(ArrayUtils.EMPTY_DOUBLE_ARRAY, (double) 1);
375 assertTrue(Arrays.equals(ArrayUtils.EMPTY_DOUBLE_ARRAY, array));
376 assertEquals(Double.TYPE, array.getClass().getComponentType());
377 array = ArrayUtils.removeElement(new double[] {1}, (double) 1);
378 assertTrue(Arrays.equals(ArrayUtils.EMPTY_DOUBLE_ARRAY, array));
379 assertEquals(Double.TYPE, array.getClass().getComponentType());
380 array = ArrayUtils.removeElement(new double[] {1, 2}, (double) 1);
381 assertTrue(Arrays.equals(new double[] {2}, array));
382 assertEquals(Double.TYPE, array.getClass().getComponentType());
383 array = ArrayUtils.removeElement(new double[] {1, 2, 1}, (double) 1);
384 assertTrue(Arrays.equals(new double[] {2, 1}, array));
385 assertEquals(Double.TYPE, array.getClass().getComponentType());
386 }
387
388 @SuppressWarnings("cast")
389 public void testRemoveElementFloatArray() {
390 float[] array;
391 array = ArrayUtils.removeElement((float[]) null, (float) 1);
392 assertNull(array);
393 array = ArrayUtils.removeElement(ArrayUtils.EMPTY_FLOAT_ARRAY, (float) 1);
394 assertTrue(Arrays.equals(ArrayUtils.EMPTY_FLOAT_ARRAY, array));
395 assertEquals(Float.TYPE, array.getClass().getComponentType());
396 array = ArrayUtils.removeElement(new float[] {1}, (float) 1);
397 assertTrue(Arrays.equals(ArrayUtils.EMPTY_FLOAT_ARRAY, array));
398 assertEquals(Float.TYPE, array.getClass().getComponentType());
399 array = ArrayUtils.removeElement(new float[] {1, 2}, (float) 1);
400 assertTrue(Arrays.equals(new float[] {2}, array));
401 assertEquals(Float.TYPE, array.getClass().getComponentType());
402 array = ArrayUtils.removeElement(new float[] {1, 2, 1}, (float) 1);
403 assertTrue(Arrays.equals(new float[] {2, 1}, array));
404 assertEquals(Float.TYPE, array.getClass().getComponentType());
405 }
406
407 public void testRemoveElementIntArray() {
408 int[] array;
409 array = ArrayUtils.removeElement((int[]) null, 1);
410 assertNull(array);
411 array = ArrayUtils.removeElement(ArrayUtils.EMPTY_INT_ARRAY, 1);
412 assertTrue(Arrays.equals(ArrayUtils.EMPTY_INT_ARRAY, array));
413 assertEquals(Integer.TYPE, array.getClass().getComponentType());
414 array = ArrayUtils.removeElement(new int[] {1}, 1);
415 assertTrue(Arrays.equals(ArrayUtils.EMPTY_INT_ARRAY, array));
416 assertEquals(Integer.TYPE, array.getClass().getComponentType());
417 array = ArrayUtils.removeElement(new int[] {1, 2}, 1);
418 assertTrue(Arrays.equals(new int[] {2}, array));
419 assertEquals(Integer.TYPE, array.getClass().getComponentType());
420 array = ArrayUtils.removeElement(new int[] {1, 2, 1}, 1);
421 assertTrue(Arrays.equals(new int[] {2, 1}, array));
422 assertEquals(Integer.TYPE, array.getClass().getComponentType());
423 }
424
425 @SuppressWarnings("cast")
426 public void testRemoveElementLongArray() {
427 long[] array;
428 array = ArrayUtils.removeElement((long[]) null, (long) 1);
429 assertNull(array);
430 array = ArrayUtils.removeElement(ArrayUtils.EMPTY_LONG_ARRAY, (long) 1);
431 assertTrue(Arrays.equals(ArrayUtils.EMPTY_LONG_ARRAY, array));
432 assertEquals(Long.TYPE, array.getClass().getComponentType());
433 array = ArrayUtils.removeElement(new long[] {1}, (long) 1);
434 assertTrue(Arrays.equals(ArrayUtils.EMPTY_LONG_ARRAY, array));
435 assertEquals(Long.TYPE, array.getClass().getComponentType());
436 array = ArrayUtils.removeElement(new long[] {1, 2}, (long) 1);
437 assertTrue(Arrays.equals(new long[] {2}, array));
438 assertEquals(Long.TYPE, array.getClass().getComponentType());
439 array = ArrayUtils.removeElement(new long[] {1, 2, 1}, (long) 1);
440 assertTrue(Arrays.equals(new long[] {2, 1}, array));
441 assertEquals(Long.TYPE, array.getClass().getComponentType());
442 }
443
444 public void testRemoveElementShortArray() {
445 short[] array;
446 array = ArrayUtils.removeElement((short[]) null, (short) 1);
447 assertNull(array);
448 array = ArrayUtils.removeElement(ArrayUtils.EMPTY_SHORT_ARRAY, (short) 1);
449 assertTrue(Arrays.equals(ArrayUtils.EMPTY_SHORT_ARRAY, array));
450 assertEquals(Short.TYPE, array.getClass().getComponentType());
451 array = ArrayUtils.removeElement(new short[] {1}, (short) 1);
452 assertTrue(Arrays.equals(ArrayUtils.EMPTY_SHORT_ARRAY, array));
453 assertEquals(Short.TYPE, array.getClass().getComponentType());
454 array = ArrayUtils.removeElement(new short[] {1, 2}, (short) 1);
455 assertTrue(Arrays.equals(new short[] {2}, array));
456 assertEquals(Short.TYPE, array.getClass().getComponentType());
457 array = ArrayUtils.removeElement(new short[] {1, 2, 1}, (short) 1);
458 assertTrue(Arrays.equals(new short[] {2, 1}, array));
459 assertEquals(Short.TYPE, array.getClass().getComponentType());
460 }
461
462 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.Modifier;
20 import java.util.Arrays;
21 import java.util.Date;
22 import java.util.Map;
23
24 import junit.framework.TestCase;
25
26 /**
27 * Unit tests {@link org.apache.commons.lang3.ArrayUtils}.
28 *
29 * @version $Id: ArrayUtilsTest.java 1153490 2011-08-03 13:53:35Z ggregory $
30 */
31 public class ArrayUtilsTest extends TestCase {
32
33 public ArrayUtilsTest(String name) {
34 super(name);
35 }
36
37 //-----------------------------------------------------------------------
38 public void testConstructor() {
39 assertNotNull(new ArrayUtils());
40 Constructor<?>[] cons = ArrayUtils.class.getDeclaredConstructors();
41 assertEquals(1, cons.length);
42 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
43 assertEquals(true, Modifier.isPublic(ArrayUtils.class.getModifiers()));
44 assertEquals(false, Modifier.isFinal(ArrayUtils.class.getModifiers()));
45 }
46
47 //-----------------------------------------------------------------------
48 public void testToString() {
49 assertEquals("{}", ArrayUtils.toString(null));
50 assertEquals("{}", ArrayUtils.toString(new Object[0]));
51 assertEquals("{}", ArrayUtils.toString(new String[0]));
52 assertEquals("{<null>}", ArrayUtils.toString(new String[] {null}));
53 assertEquals("{pink,blue}", ArrayUtils.toString(new String[] {"pink","blue"}));
54
55 assertEquals("<empty>", ArrayUtils.toString(null, "<empty>"));
56 assertEquals("{}", ArrayUtils.toString(new Object[0], "<empty>"));
57 assertEquals("{}", ArrayUtils.toString(new String[0], "<empty>"));
58 assertEquals("{<null>}", ArrayUtils.toString(new String[] {null}, "<empty>"));
59 assertEquals("{pink,blue}", ArrayUtils.toString(new String[] {"pink","blue"}, "<empty>"));
60 }
61
62 //-----------------------------------------------------------------------
63 public void testHashCode() {
64 long[][] array1 = new long[][] {{2,5}, {4,5}};
65 long[][] array2 = new long[][] {{2,5}, {4,6}};
66 assertEquals(true, ArrayUtils.hashCode(array1) == ArrayUtils.hashCode(array1));
67 assertEquals(false, ArrayUtils.hashCode(array1) == ArrayUtils.hashCode(array2));
68
69 Object[] array3 = new Object[] {new String(new char[] {'A', 'B'})};
70 Object[] array4 = new Object[] {"AB"};
71 assertEquals(true, ArrayUtils.hashCode(array3) == ArrayUtils.hashCode(array3));
72 assertEquals(true, ArrayUtils.hashCode(array3) == ArrayUtils.hashCode(array4));
73
74 Object[] arrayA = new Object[] {new boolean[] {true, false}, new int[] {6, 7}};
75 Object[] arrayB = new Object[] {new boolean[] {true, false}, new int[] {6, 7}};
76 assertEquals(true, ArrayUtils.hashCode(arrayB) == ArrayUtils.hashCode(arrayA));
77 }
78
79 //-----------------------------------------------------------------------
80 private void assertIsEquals(Object array1, Object array2, Object array3) {
81 assertEquals(true, ArrayUtils.isEquals(array1, array1));
82 assertEquals(true, ArrayUtils.isEquals(array2, array2));
83 assertEquals(true, ArrayUtils.isEquals(array3, array3));
84 assertEquals(false, ArrayUtils.isEquals(array1, array2));
85 assertEquals(false, ArrayUtils.isEquals(array2, array1));
86 assertEquals(false, ArrayUtils.isEquals(array1, array3));
87 assertEquals(false, ArrayUtils.isEquals(array3, array1));
88 assertEquals(false, ArrayUtils.isEquals(array1, array2));
89 assertEquals(false, ArrayUtils.isEquals(array2, array1));
90 }
91
92 public void testIsEquals() {
93 long[][] larray1 = new long[][]{{2, 5}, {4, 5}};
94 long[][] larray2 = new long[][]{{2, 5}, {4, 6}};
95 long[] larray3 = new long[]{2, 5};
96 this.assertIsEquals(larray1, larray2, larray3);
97
98 int[][] iarray1 = new int[][]{{2, 5}, {4, 5}};
99 int[][] iarray2 = new int[][]{{2, 5}, {4, 6}};
100 int[] iarray3 = new int[]{2, 5};
101 this.assertIsEquals(iarray1, iarray2, iarray3);
102
103 short[][] sarray1 = new short[][]{{2, 5}, {4, 5}};
104 short[][] sarray2 = new short[][]{{2, 5}, {4, 6}};
105 short[] sarray3 = new short[]{2, 5};
106 this.assertIsEquals(sarray1, sarray2, sarray3);
107
108 float[][] farray1 = new float[][]{{2, 5}, {4, 5}};
109 float[][] farray2 = new float[][]{{2, 5}, {4, 6}};
110 float[] farray3 = new float[]{2, 5};
111 this.assertIsEquals(farray1, farray2, farray3);
112
113 double[][] darray1 = new double[][]{{2, 5}, {4, 5}};
114 double[][] darray2 = new double[][]{{2, 5}, {4, 6}};
115 double[] darray3 = new double[]{2, 5};
116 this.assertIsEquals(darray1, darray2, darray3);
117
118 byte[][] byteArray1 = new byte[][]{{2, 5}, {4, 5}};
119 byte[][] byteArray2 = new byte[][]{{2, 5}, {4, 6}};
120 byte[] byteArray3 = new byte[]{2, 5};
121 this.assertIsEquals(byteArray1, byteArray2, byteArray3);
122
123 char[][] charArray1 = new char[][]{{2, 5}, {4, 5}};
124 char[][] charArray2 = new char[][]{{2, 5}, {4, 6}};
125 char[] charArray3 = new char[]{2, 5};
126 this.assertIsEquals(charArray1, charArray2, charArray3);
127
128 boolean[][] barray1 = new boolean[][]{{true, false}, {true, true}};
129 boolean[][] barray2 = new boolean[][]{{true, false}, {true, false}};
130 boolean[] barray3 = new boolean[]{false, true};
131 this.assertIsEquals(barray1, barray2, barray3);
132
133 Object[] array3 = new Object[]{new String(new char[]{'A', 'B'})};
134 Object[] array4 = new Object[]{"AB"};
135 assertEquals(true, ArrayUtils.isEquals(array3, array3));
136 assertEquals(true, ArrayUtils.isEquals(array3, array4));
137
138 assertEquals(true, ArrayUtils.isEquals(null, null));
139 assertEquals(false, ArrayUtils.isEquals(null, array4));
140 }
141
142 //-----------------------------------------------------------------------
143 /**
144 * Tests generic array creation with parameters of same type.
145 */
146 public void testArrayCreation()
147 {
148 final String[] array = ArrayUtils.toArray("foo", "bar");
149 assertEquals(2, array.length);
150 assertEquals("foo", array[0]);
151 assertEquals("bar", array[1]);
152 }
153
154 /**
155 * Tests generic array creation with general return type.
156 */
157 public void testArrayCreationWithGeneralReturnType()
158 {
159 final Object obj = ArrayUtils.toArray("foo", "bar");
160 assertTrue(obj instanceof String[]);
161 }
162
163 /**
164 * Tests generic array creation with parameters of common base type.
165 */
166 public void testArrayCreationWithDifferentTypes()
167 {
168 final Number[] array = ArrayUtils.<Number>toArray(Integer.valueOf(42), Double.valueOf(Math.PI));
169 assertEquals(2, array.length);
170 assertEquals(Integer.valueOf(42), array[0]);
171 assertEquals(Double.valueOf(Math.PI), array[1]);
172 }
173
174 /**
175 * Tests generic array creation with generic type.
176 */
177 public void testIndirectArrayCreation()
178 {
179 final String[] array = toArrayPropagatingType("foo", "bar");
180 assertEquals(2, array.length);
181 assertEquals("foo", array[0]);
182 assertEquals("bar", array[1]);
183 }
184
185 /**
186 * Tests generic empty array creation with generic type.
187 */
188 public void testEmptyArrayCreation()
189 {
190 final String[] array = ArrayUtils.<String>toArray();
191 assertEquals(0, array.length);
192 }
193
194 /**
195 * Tests indirect generic empty array creation with generic type.
196 */
197 public void testIndirectEmptyArrayCreation()
198 {
199 final String[] array = ArrayUtilsTest.<String>toArrayPropagatingType();
200 assertEquals(0, array.length);
201 }
202
203 private static <T> T[] toArrayPropagatingType(final T... items)
204 {
205 return ArrayUtils.toArray(items);
206 }
207
208 //-----------------------------------------------------------------------
209 public void testToMap() {
210 Map<?, ?> map = ArrayUtils.toMap(new String[][] {{"foo", "bar"}, {"hello", "world"}});
211
212 assertEquals("bar", map.get("foo"));
213 assertEquals("world", map.get("hello"));
214
215 assertEquals(null, ArrayUtils.toMap(null));
216 try {
217 ArrayUtils.toMap(new String[][] {{"foo", "bar"}, {"short"}});
218 fail("exception expected");
219 } catch (IllegalArgumentException ex) {}
220 try {
221 ArrayUtils.toMap(new Object[] {new Object[] {"foo", "bar"}, "illegal type"});
222 fail("exception expected");
223 } catch (IllegalArgumentException ex) {}
224 try {
225 ArrayUtils.toMap(new Object[] {new Object[] {"foo", "bar"}, null});
226 fail("exception expected");
227 } catch (IllegalArgumentException ex) {}
228
229 map = ArrayUtils.toMap(new Object[] {new Map.Entry<Object, Object>() {
230 public Object getKey() {
231 return "foo";
232 }
233 public Object getValue() {
234 return "bar";
235 }
236 public Object setValue(Object value) {
237 throw new UnsupportedOperationException();
238 }
239 @Override
240 public boolean equals(Object o) {
241 throw new UnsupportedOperationException();
242 }
243 @Override
244 public int hashCode() {
245 throw new UnsupportedOperationException();
246 }
247 }});
248 assertEquals("bar", map.get("foo"));
249 }
250
251 //-----------------------------------------------------------------------
252 public void testClone() {
253 assertEquals(null, ArrayUtils.clone((Object[]) null));
254 Object[] original1 = new Object[0];
255 Object[] cloned1 = ArrayUtils.clone(original1);
256 assertTrue(Arrays.equals(original1, cloned1));
257 assertTrue(original1 != cloned1);
258
259 StringBuffer buf = new StringBuffer("pick");
260 original1 = new Object[] {buf, "a", new String[] {"stick"}};
261 cloned1 = ArrayUtils.clone(original1);
262 assertTrue(Arrays.equals(original1, cloned1));
263 assertTrue(original1 != cloned1);
264 assertSame(original1[0], cloned1[0]);
265 assertSame(original1[1], cloned1[1]);
266 assertSame(original1[2], cloned1[2]);
267 }
268
269 public void testCloneBoolean() {
270 assertEquals(null, ArrayUtils.clone((boolean[]) null));
271 boolean[] original = new boolean[] {true, false};
272 boolean[] cloned = ArrayUtils.clone(original);
273 assertTrue(Arrays.equals(original, cloned));
274 assertTrue(original != cloned);
275 }
276
277 public void testCloneLong() {
278 assertEquals(null, ArrayUtils.clone((long[]) null));
279 long[] original = new long[] {0L, 1L};
280 long[] cloned = ArrayUtils.clone(original);
281 assertTrue(Arrays.equals(original, cloned));
282 assertTrue(original != cloned);
283 }
284
285 public void testCloneInt() {
286 assertEquals(null, ArrayUtils.clone((int[]) null));
287 int[] original = new int[] {5, 8};
288 int[] cloned = ArrayUtils.clone(original);
289 assertTrue(Arrays.equals(original, cloned));
290 assertTrue(original != cloned);
291 }
292
293 public void testCloneShort() {
294 assertEquals(null, ArrayUtils.clone((short[]) null));
295 short[] original = new short[] {1, 4};
296 short[] cloned = ArrayUtils.clone(original);
297 assertTrue(Arrays.equals(original, cloned));
298 assertTrue(original != cloned);
299 }
300
301 public void testCloneChar() {
302 assertEquals(null, ArrayUtils.clone((char[]) null));
303 char[] original = new char[] {'a', '4'};
304 char[] cloned = ArrayUtils.clone(original);
305 assertTrue(Arrays.equals(original, cloned));
306 assertTrue(original != cloned);
307 }
308
309 public void testCloneByte() {
310 assertEquals(null, ArrayUtils.clone((byte[]) null));
311 byte[] original = new byte[] {1, 6};
312 byte[] cloned = ArrayUtils.clone(original);
313 assertTrue(Arrays.equals(original, cloned));
314 assertTrue(original != cloned);
315 }
316
317 public void testCloneDouble() {
318 assertEquals(null, ArrayUtils.clone((double[]) null));
319 double[] original = new double[] {2.4d, 5.7d};
320 double[] cloned = ArrayUtils.clone(original);
321 assertTrue(Arrays.equals(original, cloned));
322 assertTrue(original != cloned);
323 }
324
325 public void testCloneFloat() {
326 assertEquals(null, ArrayUtils.clone((float[]) null));
327 float[] original = new float[] {2.6f, 6.4f};
328 float[] cloned = ArrayUtils.clone(original);
329 assertTrue(Arrays.equals(original, cloned));
330 assertTrue(original != cloned);
331 }
332
333 //-----------------------------------------------------------------------
334
335 public void testNullToEmptyBoolean() {
336 // Test null handling
337 assertEquals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, ArrayUtils.nullToEmpty((boolean[]) null));
338 // Test valid array handling
339 boolean[] original = new boolean[] {true, false};
340 assertEquals(original, ArrayUtils.nullToEmpty(original));
341 // Test empty array handling
342 boolean[] empty = new boolean[]{};
343 boolean[] result = ArrayUtils.nullToEmpty(empty);
344 assertEquals(ArrayUtils.EMPTY_BOOLEAN_ARRAY, result);
345 assertTrue(empty != result);
346 }
347
348 public void testNullToEmptyLong() {
349 // Test null handling
350 assertEquals(ArrayUtils.EMPTY_LONG_ARRAY, ArrayUtils.nullToEmpty((long[]) null));
351 // Test valid array handling
352 long[] original = new long[] {1L, 2L};
353 assertEquals(original, ArrayUtils.nullToEmpty(original));
354 // Test empty array handling
355 long[] empty = new long[]{};
356 long[] result = ArrayUtils.nullToEmpty(empty);
357 assertEquals(ArrayUtils.EMPTY_LONG_ARRAY, result);
358 assertTrue(empty != result);
359 }
360
361 public void testNullToEmptyInt() {
362 // Test null handling
363 assertEquals(ArrayUtils.EMPTY_INT_ARRAY, ArrayUtils.nullToEmpty((int[]) null));
364 // Test valid array handling
365 int[] original = new int[] {1, 2};
366 assertEquals(original, ArrayUtils.nullToEmpty(original));
367 // Test empty array handling
368 int[] empty = new int[]{};
369 int[] result = ArrayUtils.nullToEmpty(empty);
370 assertEquals(ArrayUtils.EMPTY_INT_ARRAY, result);
371 assertTrue(empty != result);
372 }
373
374 public void testNullToEmptyShort() {
375 // Test null handling
376 assertEquals(ArrayUtils.EMPTY_SHORT_ARRAY, ArrayUtils.nullToEmpty((short[]) null));
377 // Test valid array handling
378 short[] original = new short[] {1, 2};
379 assertEquals(original, ArrayUtils.nullToEmpty(original));
380 // Test empty array handling
381 short[] empty = new short[]{};
382 short[] result = ArrayUtils.nullToEmpty(empty);
383 assertEquals(ArrayUtils.EMPTY_SHORT_ARRAY, result);
384 assertTrue(empty != result);
385 }
386
387 public void testNullToEmptyChar() {
388 // Test null handling
389 assertEquals(ArrayUtils.EMPTY_CHAR_ARRAY, ArrayUtils.nullToEmpty((char[]) null));
390 // Test valid array handling
391 char[] original = new char[] {'a', 'b'};
392 assertEquals(original, ArrayUtils.nullToEmpty(original));
393 // Test empty array handling
394 char[] empty = new char[]{};
395 char[] result = ArrayUtils.nullToEmpty(empty);
396 assertEquals(ArrayUtils.EMPTY_CHAR_ARRAY, result);
397 assertTrue(empty != result);
398 }
399
400 public void testNullToEmptyByte() {
401 // Test null handling
402 assertEquals(ArrayUtils.EMPTY_BYTE_ARRAY, ArrayUtils.nullToEmpty((byte[]) null));
403 // Test valid array handling
404 byte[] original = new byte[] {0x0F, 0x0E};
405 assertEquals(original, ArrayUtils.nullToEmpty(original));
406 // Test empty array handling
407 byte[] empty = new byte[]{};
408 byte[] result = ArrayUtils.nullToEmpty(empty);
409 assertEquals(ArrayUtils.EMPTY_BYTE_ARRAY, result);
410 assertTrue(empty != result);
411 }
412
413 public void testNullToEmptyDouble() {
414 // Test null handling
415 assertEquals(ArrayUtils.EMPTY_DOUBLE_ARRAY, ArrayUtils.nullToEmpty((double[]) null));
416 // Test valid array handling
417 double[] original = new double[] {1L, 2L};
418 assertEquals(original, ArrayUtils.nullToEmpty(original));
419 // Test empty array handling
420 double[] empty = new double[]{};
421 double[] result = ArrayUtils.nullToEmpty(empty);
422 assertEquals(ArrayUtils.EMPTY_DOUBLE_ARRAY, result);
423 assertTrue(empty != result);
424 }
425
426 public void testNullToEmptyFloat() {
427 // Test null handling
428 assertEquals(ArrayUtils.EMPTY_FLOAT_ARRAY, ArrayUtils.nullToEmpty((float[]) null));
429 // Test valid array handling
430 float[] original = new float[] {2.6f, 3.8f};
431 assertEquals(original, ArrayUtils.nullToEmpty(original));
432 // Test empty array handling
433 float[] empty = new float[]{};
434 float[] result = ArrayUtils.nullToEmpty(empty);
435 assertEquals(ArrayUtils.EMPTY_FLOAT_ARRAY, result);
436 assertTrue(empty != result);
437 }
438
439 public void testNullToEmptyObject() {
440 // Test null handling
441 assertEquals(ArrayUtils.EMPTY_OBJECT_ARRAY, ArrayUtils.nullToEmpty((Object[]) null));
442 // Test valid array handling
443 Object[] original = new Object[] {true, false};
444 assertEquals(original, ArrayUtils.nullToEmpty(original));
445 // Test empty array handling
446 Object[] empty = new Object[]{};
447 Object[] result = ArrayUtils.nullToEmpty(empty);
448 assertEquals(ArrayUtils.EMPTY_OBJECT_ARRAY, result);
449 assertTrue(empty != result);
450 }
451
452 public void testNullToEmptyString() {
453 // Test null handling
454 assertEquals(ArrayUtils.EMPTY_STRING_ARRAY, ArrayUtils.nullToEmpty((String[]) null));
455 // Test valid array handling
456 String[] original = new String[] {"abc", "def"};
457 assertEquals(original, ArrayUtils.nullToEmpty(original));
458 // Test empty array handling
459 String[] empty = new String[]{};
460 String[] result = ArrayUtils.nullToEmpty(empty);
461 assertEquals(ArrayUtils.EMPTY_STRING_ARRAY, result);
462 assertTrue(empty != result);
463 }
464
465 public void testNullToEmptyBooleanObject() {
466 // Test null handling
467 assertEquals(ArrayUtils.EMPTY_BOOLEAN_OBJECT_ARRAY, ArrayUtils.nullToEmpty((Boolean[]) null));
468 // Test valid array handling
469 Boolean[] original = new Boolean[] {Boolean.TRUE, Boolean.FALSE};
470 assertEquals(original, ArrayUtils.nullToEmpty(original));
471 // Test empty array handling
472 Boolean[] empty = new Boolean[]{};
473 Boolean[] result = ArrayUtils.nullToEmpty(empty);
474 assertEquals(ArrayUtils.EMPTY_BOOLEAN_OBJECT_ARRAY, result);
475 assertTrue(empty != result);
476 }
477
478 public void testNullToEmptyLongObject() {
479 // Test null handling
480 assertEquals(ArrayUtils.EMPTY_LONG_OBJECT_ARRAY, ArrayUtils.nullToEmpty((Long[]) null));
481 // Test valid array handling
482 Long[] original = new Long[] {1L, 2L};
483 assertEquals(original, ArrayUtils.nullToEmpty(original));
484 // Test empty array handling
485 Long[] empty = new Long[]{};
486 Long[] result = ArrayUtils.nullToEmpty(empty);
487 assertEquals(ArrayUtils.EMPTY_LONG_OBJECT_ARRAY, result);
488 assertTrue(empty != result);
489 }
490
491 public void testNullToEmptyIntObject() {
492 // Test null handling
493 assertEquals(ArrayUtils.EMPTY_INTEGER_OBJECT_ARRAY, ArrayUtils.nullToEmpty((Integer[]) null));
494 // Test valid array handling
495 Integer[] original = new Integer[] {1, 2};
496 assertEquals(original, ArrayUtils.nullToEmpty(original));
497 // Test empty array handling
498 Integer[] empty = new Integer[]{};
499 Integer[] result = ArrayUtils.nullToEmpty(empty);
500 assertEquals(ArrayUtils.EMPTY_INTEGER_OBJECT_ARRAY, result);
501 assertTrue(empty != result);
502 }
503
504 public void testNullToEmptyShortObject() {
505 // Test null handling
506 assertEquals(ArrayUtils.EMPTY_SHORT_OBJECT_ARRAY, ArrayUtils.nullToEmpty((Short[]) null));
507 // Test valid array handling
508 Short[] original = new Short[] {1, 2};
509 assertEquals(original, ArrayUtils.nullToEmpty(original));
510 // Test empty array handling
511 Short[] empty = new Short[]{};
512 Short[] result = ArrayUtils.nullToEmpty(empty);
513 assertEquals(ArrayUtils.EMPTY_SHORT_OBJECT_ARRAY, result);
514 assertTrue(empty != result);
515 }
516
517 public void testNullToEmptyCharObject() {
518 // Test null handling
519 assertEquals(ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, ArrayUtils.nullToEmpty((Character[]) null));
520 // Test valid array handling
521 Character[] original = new Character[] {'a', 'b'};
522 assertEquals(original, ArrayUtils.nullToEmpty(original));
523 // Test empty array handling
524 Character[] empty = new Character[]{};
525 Character[] result = ArrayUtils.nullToEmpty(empty);
526 assertEquals(ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, result);
527 assertTrue(empty != result);
528 }
529
530 public void testNullToEmptyByteObject() {
531 // Test null handling
532 assertEquals(ArrayUtils.EMPTY_BYTE_OBJECT_ARRAY, ArrayUtils.nullToEmpty((Byte[]) null));
533 // Test valid array handling
534 Byte[] original = new Byte[] {0x0F, 0x0E};
535 assertEquals(original, ArrayUtils.nullToEmpty(original));
536 // Test empty array handling
537 Byte[] empty = new Byte[]{};
538 Byte[] result = ArrayUtils.nullToEmpty(empty);
539 assertEquals(ArrayUtils.EMPTY_BYTE_OBJECT_ARRAY, result);
540 assertTrue(empty != result);
541 }
542
543 public void testNullToEmptyDoubleObject() {
544 // Test null handling
545 assertEquals(ArrayUtils.EMPTY_DOUBLE_OBJECT_ARRAY, ArrayUtils.nullToEmpty((Double[]) null));
546 // Test valid array handling
547 Double[] original = new Double[] {1D, 2D};
548 assertEquals(original, ArrayUtils.nullToEmpty(original));
549 // Test empty array handling
550 Double[] empty = new Double[]{};
551 Double[] result = ArrayUtils.nullToEmpty(empty);
552 assertEquals(ArrayUtils.EMPTY_DOUBLE_OBJECT_ARRAY, result);
553 assertTrue(empty != result);
554 }
555
556 public void testNullToEmptyFloatObject() {
557 // Test null handling
558 assertEquals(ArrayUtils.EMPTY_FLOAT_OBJECT_ARRAY, ArrayUtils.nullToEmpty((Float[]) null));
559 // Test valid array handling
560 Float[] original = new Float[] {2.6f, 3.8f};
561 assertEquals(original, ArrayUtils.nullToEmpty(original));
562 // Test empty array handling
563 Float[] empty = new Float[]{};
564 Float[] result = ArrayUtils.nullToEmpty(empty);
565 assertEquals(ArrayUtils.EMPTY_FLOAT_OBJECT_ARRAY, result);
566 assertTrue(empty != result);
567 }
568
569 //-----------------------------------------------------------------------
570
571 public void testSubarrayObject() {
572 Object[] nullArray = null;
573 Object[] objectArray = { "a", "b", "c", "d", "e", "f"};
574
575 assertEquals("0 start, mid end", "abcd",
576 StringUtils.join(ArrayUtils.subarray(objectArray, 0, 4)));
577 assertEquals("0 start, length end", "abcdef",
578 StringUtils.join(ArrayUtils.subarray(objectArray, 0, objectArray.length)));
579 assertEquals("mid start, mid end", "bcd",
580 StringUtils.join(ArrayUtils.subarray(objectArray, 1, 4)));
581 assertEquals("mid start, length end", "bcdef",
582 StringUtils.join(ArrayUtils.subarray(objectArray, 1, objectArray.length)));
583
584 assertNull("null input", ArrayUtils.subarray(nullArray, 0, 3));
585 assertEquals("empty array", "",
586 StringUtils.join(ArrayUtils.subarray(ArrayUtils.EMPTY_OBJECT_ARRAY, 1, 2)));
587 assertEquals("start > end", "",
588 StringUtils.join(ArrayUtils.subarray(objectArray, 4, 2)));
589 assertEquals("start == end", "",
590 StringUtils.join(ArrayUtils.subarray(objectArray, 3, 3)));
591 assertEquals("start undershoot, normal end", "abcd",
592 StringUtils.join(ArrayUtils.subarray(objectArray, -2, 4)));
593 assertEquals("start overshoot, any end", "",
594 StringUtils.join(ArrayUtils.subarray(objectArray, 33, 4)));
595 assertEquals("normal start, end overshoot", "cdef",
596 StringUtils.join(ArrayUtils.subarray(objectArray, 2, 33)));
597 assertEquals("start undershoot, end overshoot", "abcdef",
598 StringUtils.join(ArrayUtils.subarray(objectArray, -2, 12)));
599
600 // array type tests
601 Date[] dateArray = { new java.sql.Date(new Date().getTime()),
602 new Date(), new Date(), new Date(), new Date() };
603
604 assertSame("Object type", Object.class,
605 ArrayUtils.subarray(objectArray, 2, 4).getClass().getComponentType());
606 assertSame("java.util.Date type", java.util.Date.class,
607 ArrayUtils.subarray(dateArray, 1, 4).getClass().getComponentType());
608 assertNotSame("java.sql.Date type", java.sql.Date.class,
609 ArrayUtils.subarray(dateArray, 1, 4).getClass().getComponentType());
610 try {
611 @SuppressWarnings("unused")
612 java.sql.Date[] dummy = (java.sql.Date[])ArrayUtils.subarray(dateArray, 1,3);
613 fail("Invalid downcast");
614 } catch (ClassCastException e) {}
615 }
616
617 public void testSubarrayLong() {
618 long[] nullArray = null;
619 long[] array = { 999910, 999911, 999912, 999913, 999914, 999915 };
620 long[] leftSubarray = { 999910, 999911, 999912, 999913 };
621 long[] midSubarray = { 999911, 999912, 999913, 999914 };
622 long[] rightSubarray = { 999912, 999913, 999914, 999915 };
623
624 assertTrue("0 start, mid end",
625 ArrayUtils.isEquals(leftSubarray,
626 ArrayUtils.subarray(array, 0, 4)));
627
628 assertTrue("0 start, length end",
629 ArrayUtils.isEquals(array,
630 ArrayUtils.subarray(array, 0, array.length)));
631
632 assertTrue("mid start, mid end",
633 ArrayUtils.isEquals(midSubarray,
634 ArrayUtils.subarray(array, 1, 5)));
635
636 assertTrue("mid start, length end",
637 ArrayUtils.isEquals(rightSubarray,
638 ArrayUtils.subarray(array, 2, array.length)));
639
640
641 assertNull("null input", ArrayUtils.subarray(nullArray, 0, 3));
642
643 assertEquals("empty array", ArrayUtils.EMPTY_LONG_ARRAY,
644 ArrayUtils.subarray(ArrayUtils.EMPTY_LONG_ARRAY, 1, 2));
645
646 assertEquals("start > end", ArrayUtils.EMPTY_LONG_ARRAY,
647 ArrayUtils.subarray(array, 4, 2));
648
649 assertEquals("start == end", ArrayUtils.EMPTY_LONG_ARRAY,
650 ArrayUtils.subarray(array, 3, 3));
651
652 assertTrue("start undershoot, normal end",
653 ArrayUtils.isEquals(leftSubarray,
654 ArrayUtils.subarray(array, -2, 4)));
655
656 assertEquals("start overshoot, any end",
657 ArrayUtils.EMPTY_LONG_ARRAY,
658 ArrayUtils.subarray(array, 33, 4));
659
660 assertTrue("normal start, end overshoot",
661 ArrayUtils.isEquals(rightSubarray,
662 ArrayUtils.subarray(array, 2, 33)));
663
664 assertTrue("start undershoot, end overshoot",
665 ArrayUtils.isEquals(array,
666 ArrayUtils.subarray(array, -2, 12)));
667
668 // empty-return tests
669
670 assertSame("empty array, object test",
671 ArrayUtils.EMPTY_LONG_ARRAY,
672 ArrayUtils.subarray(ArrayUtils.EMPTY_LONG_ARRAY, 1, 2));
673
674 assertSame("start > end, object test",
675 ArrayUtils.EMPTY_LONG_ARRAY,
676 ArrayUtils.subarray(array, 4, 1));
677
678 assertSame("start == end, object test",
679 ArrayUtils.EMPTY_LONG_ARRAY,
680 ArrayUtils.subarray(array, 3, 3));
681
682 assertSame("start overshoot, any end, object test",
683 ArrayUtils.EMPTY_LONG_ARRAY,
684 ArrayUtils.subarray(array, 8733, 4));
685
686 // array type tests
687
688 assertSame("long type", long.class,
689 ArrayUtils.subarray(array, 2, 4).getClass().getComponentType());
690
691 }
692
693 public void testSubarrayInt() {
694 int[] nullArray = null;
695 int[] array = { 10, 11, 12, 13, 14, 15 };
696 int[] leftSubarray = { 10, 11, 12, 13 };
697 int[] midSubarray = { 11, 12, 13, 14 };
698 int[] rightSubarray = { 12, 13, 14, 15 };
699
700
701 assertTrue("0 start, mid end",
702 ArrayUtils.isEquals(leftSubarray,
703 ArrayUtils.subarray(array, 0, 4)));
704
705 assertTrue("0 start, length end",
706 ArrayUtils.isEquals(array,
707 ArrayUtils.subarray(array, 0, array.length)));
708
709 assertTrue("mid start, mid end",
710 ArrayUtils.isEquals(midSubarray,
711 ArrayUtils.subarray(array, 1, 5)));
712
713 assertTrue("mid start, length end",
714 ArrayUtils.isEquals(rightSubarray,
715 ArrayUtils.subarray(array, 2, array.length)));
716
717
718 assertNull("null input", ArrayUtils.subarray(nullArray, 0, 3));
719
720 assertEquals("empty array", ArrayUtils.EMPTY_INT_ARRAY,
721 ArrayUtils.subarray(ArrayUtils.EMPTY_INT_ARRAY, 1, 2));
722
723 assertEquals("start > end", ArrayUtils.EMPTY_INT_ARRAY,
724 ArrayUtils.subarray(array, 4, 2));
725
726 assertEquals("start == end", ArrayUtils.EMPTY_INT_ARRAY,
727 ArrayUtils.subarray(array, 3, 3));
728
729 assertTrue("start undershoot, normal end",
730 ArrayUtils.isEquals(leftSubarray,
731 ArrayUtils.subarray(array, -2, 4)));
732
733 assertEquals("start overshoot, any end",
734 ArrayUtils.EMPTY_INT_ARRAY,
735 ArrayUtils.subarray(array, 33, 4));
736
737 assertTrue("normal start, end overshoot",
738 ArrayUtils.isEquals(rightSubarray,
739 ArrayUtils.subarray(array, 2, 33)));
740
741 assertTrue("start undershoot, end overshoot",
742 ArrayUtils.isEquals(array,
743 ArrayUtils.subarray(array, -2, 12)));
744
745 // empty-return tests
746
747 assertSame("empty array, object test",
748 ArrayUtils.EMPTY_INT_ARRAY,
749 ArrayUtils.subarray(ArrayUtils.EMPTY_INT_ARRAY, 1, 2));
750
751 assertSame("start > end, object test",
752 ArrayUtils.EMPTY_INT_ARRAY,
753 ArrayUtils.subarray(array, 4, 1));
754
755 assertSame("start == end, object test",
756 ArrayUtils.EMPTY_INT_ARRAY,
757 ArrayUtils.subarray(array, 3, 3));
758
759 assertSame("start overshoot, any end, object test",
760 ArrayUtils.EMPTY_INT_ARRAY,
761 ArrayUtils.subarray(array, 8733, 4));
762
763 // array type tests
764
765 assertSame("int type", int.class,
766 ArrayUtils.subarray(array, 2, 4).getClass().getComponentType());
767
768 }
769
770 public void testSubarrayShort() {
771 short[] nullArray = null;
772 short[] array = { 10, 11, 12, 13, 14, 15 };
773 short[] leftSubarray = { 10, 11, 12, 13 };
774 short[] midSubarray = { 11, 12, 13, 14 };
775 short[] rightSubarray = { 12, 13, 14, 15 };
776
777
778 assertTrue("0 start, mid end",
779 ArrayUtils.isEquals(leftSubarray,
780 ArrayUtils.subarray(array, 0, 4)));
781
782 assertTrue("0 start, length end",
783 ArrayUtils.isEquals(array,
784 ArrayUtils.subarray(array, 0, array.length)));
785
786 assertTrue("mid start, mid end",
787 ArrayUtils.isEquals(midSubarray,
788 ArrayUtils.subarray(array, 1, 5)));
789
790 assertTrue("mid start, length end",
791 ArrayUtils.isEquals(rightSubarray,
792 ArrayUtils.subarray(array, 2, array.length)));
793
794
795 assertNull("null input", ArrayUtils.subarray(nullArray, 0, 3));
796
797 assertEquals("empty array", ArrayUtils.EMPTY_SHORT_ARRAY,
798 ArrayUtils.subarray(ArrayUtils.EMPTY_SHORT_ARRAY, 1, 2));
799
800 assertEquals("start > end", ArrayUtils.EMPTY_SHORT_ARRAY,
801 ArrayUtils.subarray(array, 4, 2));
802
803 assertEquals("start == end", ArrayUtils.EMPTY_SHORT_ARRAY,
804 ArrayUtils.subarray(array, 3, 3));
805
806 assertTrue("start undershoot, normal end",
807 ArrayUtils.isEquals(leftSubarray,
808 ArrayUtils.subarray(array, -2, 4)));
809
810 assertEquals("start overshoot, any end",
811 ArrayUtils.EMPTY_SHORT_ARRAY,
812 ArrayUtils.subarray(array, 33, 4));
813
814 assertTrue("normal start, end overshoot",
815 ArrayUtils.isEquals(rightSubarray,
816 ArrayUtils.subarray(array, 2, 33)));
817
818 assertTrue("start undershoot, end overshoot",
819 ArrayUtils.isEquals(array,
820 ArrayUtils.subarray(array, -2, 12)));
821
822 // empty-return tests
823
824 assertSame("empty array, object test",
825 ArrayUtils.EMPTY_SHORT_ARRAY,
826 ArrayUtils.subarray(ArrayUtils.EMPTY_SHORT_ARRAY, 1, 2));
827
828 assertSame("start > end, object test",
829 ArrayUtils.EMPTY_SHORT_ARRAY,
830 ArrayUtils.subarray(array, 4, 1));
831
832 assertSame("start == end, object test",
833 ArrayUtils.EMPTY_SHORT_ARRAY,
834 ArrayUtils.subarray(array, 3, 3));
835
836 assertSame("start overshoot, any end, object test",
837 ArrayUtils.EMPTY_SHORT_ARRAY,
838 ArrayUtils.subarray(array, 8733, 4));
839
840 // array type tests
841
842 assertSame("short type", short.class,
843 ArrayUtils.subarray(array, 2, 4).getClass().getComponentType());
844
845 }
846
847 public void testSubarrChar() {
848 char[] nullArray = null;
849 char[] array = { 'a', 'b', 'c', 'd', 'e', 'f' };
850 char[] leftSubarray = { 'a', 'b', 'c', 'd', };
851 char[] midSubarray = { 'b', 'c', 'd', 'e', };
852 char[] rightSubarray = { 'c', 'd', 'e', 'f', };
853
854
855 assertTrue("0 start, mid end",
856 ArrayUtils.isEquals(leftSubarray,
857 ArrayUtils.subarray(array, 0, 4)));
858
859 assertTrue("0 start, length end",
860 ArrayUtils.isEquals(array,
861 ArrayUtils.subarray(array, 0, array.length)));
862
863 assertTrue("mid start, mid end",
864 ArrayUtils.isEquals(midSubarray,
865 ArrayUtils.subarray(array, 1, 5)));
866
867 assertTrue("mid start, length end",
868 ArrayUtils.isEquals(rightSubarray,
869 ArrayUtils.subarray(array, 2, array.length)));
870
871
872 assertNull("null input", ArrayUtils.subarray(nullArray, 0, 3));
873
874 assertEquals("empty array", ArrayUtils.EMPTY_CHAR_ARRAY,
875 ArrayUtils.subarray(ArrayUtils.EMPTY_CHAR_ARRAY, 1, 2));
876
877 assertEquals("start > end", ArrayUtils.EMPTY_CHAR_ARRAY,
878 ArrayUtils.subarray(array, 4, 2));
879
880 assertEquals("start == end", ArrayUtils.EMPTY_CHAR_ARRAY,
881 ArrayUtils.subarray(array, 3, 3));
882
883 assertTrue("start undershoot, normal end",
884 ArrayUtils.isEquals(leftSubarray,
885 ArrayUtils.subarray(array, -2, 4)));
886
887 assertEquals("start overshoot, any end",
888 ArrayUtils.EMPTY_CHAR_ARRAY,
889 ArrayUtils.subarray(array, 33, 4));
890
891 assertTrue("normal start, end overshoot",
892 ArrayUtils.isEquals(rightSubarray,
893 ArrayUtils.subarray(array, 2, 33)));
894
895 assertTrue("start undershoot, end overshoot",
896 ArrayUtils.isEquals(array,
897 ArrayUtils.subarray(array, -2, 12)));
898
899 // empty-return tests
900
901 assertSame("empty array, object test",
902 ArrayUtils.EMPTY_CHAR_ARRAY,
903 ArrayUtils.subarray(ArrayUtils.EMPTY_CHAR_ARRAY, 1, 2));
904
905 assertSame("start > end, object test",
906 ArrayUtils.EMPTY_CHAR_ARRAY,
907 ArrayUtils.subarray(array, 4, 1));
908
909 assertSame("start == end, object test",
910 ArrayUtils.EMPTY_CHAR_ARRAY,
911 ArrayUtils.subarray(array, 3, 3));
912
913 assertSame("start overshoot, any end, object test",
914 ArrayUtils.EMPTY_CHAR_ARRAY,
915 ArrayUtils.subarray(array, 8733, 4));
916
917 // array type tests
918
919 assertSame("char type", char.class,
920 ArrayUtils.subarray(array, 2, 4).getClass().getComponentType());
921
922 }
923
924 public void testSubarrayByte() {
925 byte[] nullArray = null;
926 byte[] array = { 10, 11, 12, 13, 14, 15 };
927 byte[] leftSubarray = { 10, 11, 12, 13 };
928 byte[] midSubarray = { 11, 12, 13, 14 };
929 byte[] rightSubarray = { 12, 13, 14, 15 };
930
931
932 assertTrue("0 start, mid end",
933 ArrayUtils.isEquals(leftSubarray,
934 ArrayUtils.subarray(array, 0, 4)));
935
936 assertTrue("0 start, length end",
937 ArrayUtils.isEquals(array,
938 ArrayUtils.subarray(array, 0, array.length)));
939
940 assertTrue("mid start, mid end",
941 ArrayUtils.isEquals(midSubarray,
942 ArrayUtils.subarray(array, 1, 5)));
943
944 assertTrue("mid start, length end",
945 ArrayUtils.isEquals(rightSubarray,
946 ArrayUtils.subarray(array, 2, array.length)));
947
948
949 assertNull("null input", ArrayUtils.subarray(nullArray, 0, 3));
950
951 assertEquals("empty array", ArrayUtils.EMPTY_BYTE_ARRAY,
952 ArrayUtils.subarray(ArrayUtils.EMPTY_BYTE_ARRAY, 1, 2));
953
954 assertEquals("start > end", ArrayUtils.EMPTY_BYTE_ARRAY,
955 ArrayUtils.subarray(array, 4, 2));
956
957 assertEquals("start == end", ArrayUtils.EMPTY_BYTE_ARRAY,
958 ArrayUtils.subarray(array, 3, 3));
959
960 assertTrue("start undershoot, normal end",
961 ArrayUtils.isEquals(leftSubarray,
962 ArrayUtils.subarray(array, -2, 4)));
963
964 assertEquals("start overshoot, any end",
965 ArrayUtils.EMPTY_BYTE_ARRAY,
966 ArrayUtils.subarray(array, 33, 4));
967
968 assertTrue("normal start, end overshoot",
969 ArrayUtils.isEquals(rightSubarray,
970 ArrayUtils.subarray(array, 2, 33)));
971
972 assertTrue("start undershoot, end overshoot",
973 ArrayUtils.isEquals(array,
974 ArrayUtils.subarray(array, -2, 12)));
975
976 // empty-return tests
977
978 assertSame("empty array, object test",
979 ArrayUtils.EMPTY_BYTE_ARRAY,
980 ArrayUtils.subarray(ArrayUtils.EMPTY_BYTE_ARRAY, 1, 2));
981
982 assertSame("start > end, object test",
983 ArrayUtils.EMPTY_BYTE_ARRAY,
984 ArrayUtils.subarray(array, 4, 1));
985
986 assertSame("start == end, object test",
987 ArrayUtils.EMPTY_BYTE_ARRAY,
988 ArrayUtils.subarray(array, 3, 3));
989
990 assertSame("start overshoot, any end, object test",
991 ArrayUtils.EMPTY_BYTE_ARRAY,
992 ArrayUtils.subarray(array, 8733, 4));
993
994 // array type tests
995
996 assertSame("byte type", byte.class,
997 ArrayUtils.subarray(array, 2, 4).getClass().getComponentType());
998
999 }
1000
1001 public void testSubarrayDouble() {
1002 double[] nullArray = null;
1003 double[] array = { 10.123, 11.234, 12.345, 13.456, 14.567, 15.678 };
1004 double[] leftSubarray = { 10.123, 11.234, 12.345, 13.456, };
1005 double[] midSubarray = { 11.234, 12.345, 13.456, 14.567, };
1006 double[] rightSubarray = { 12.345, 13.456, 14.567, 15.678 };
1007
1008
1009 assertTrue("0 start, mid end",
1010 ArrayUtils.isEquals(leftSubarray,
1011 ArrayUtils.subarray(array, 0, 4)));
1012
1013 assertTrue("0 start, length end",
1014 ArrayUtils.isEquals(array,
1015 ArrayUtils.subarray(array, 0, array.length)));
1016
1017 assertTrue("mid start, mid end",
1018 ArrayUtils.isEquals(midSubarray,
1019 ArrayUtils.subarray(array, 1, 5)));
1020
1021 assertTrue("mid start, length end",
1022 ArrayUtils.isEquals(rightSubarray,
1023 ArrayUtils.subarray(array, 2, array.length)));
1024
1025
1026 assertNull("null input", ArrayUtils.subarray(nullArray, 0, 3));
1027
1028 assertEquals("empty array", ArrayUtils.EMPTY_DOUBLE_ARRAY,
1029 ArrayUtils.subarray(ArrayUtils.EMPTY_DOUBLE_ARRAY, 1, 2));
1030
1031 assertEquals("start > end", ArrayUtils.EMPTY_DOUBLE_ARRAY,
1032 ArrayUtils.subarray(array, 4, 2));
1033
1034 assertEquals("start == end", ArrayUtils.EMPTY_DOUBLE_ARRAY,
1035 ArrayUtils.subarray(array, 3, 3));
1036
1037 assertTrue("start undershoot, normal end",
1038 ArrayUtils.isEquals(leftSubarray,
1039 ArrayUtils.subarray(array, -2, 4)));
1040
1041 assertEquals("start overshoot, any end",
1042 ArrayUtils.EMPTY_DOUBLE_ARRAY,
1043 ArrayUtils.subarray(array, 33, 4));
1044
1045 assertTrue("normal start, end overshoot",
1046 ArrayUtils.isEquals(rightSubarray,
1047 ArrayUtils.subarray(array, 2, 33)));
1048
1049 assertTrue("start undershoot, end overshoot",
1050 ArrayUtils.isEquals(array,
1051 ArrayUtils.subarray(array, -2, 12)));
1052
1053 // empty-return tests
1054
1055 assertSame("empty array, object test",
1056 ArrayUtils.EMPTY_DOUBLE_ARRAY,
1057 ArrayUtils.subarray(ArrayUtils.EMPTY_DOUBLE_ARRAY, 1, 2));
1058
1059 assertSame("start > end, object test",
1060 ArrayUtils.EMPTY_DOUBLE_ARRAY,
1061 ArrayUtils.subarray(array, 4, 1));
1062
1063 assertSame("start == end, object test",
1064 ArrayUtils.EMPTY_DOUBLE_ARRAY,
1065 ArrayUtils.subarray(array, 3, 3));
1066
1067 assertSame("start overshoot, any end, object test",
1068 ArrayUtils.EMPTY_DOUBLE_ARRAY,
1069 ArrayUtils.subarray(array, 8733, 4));
1070
1071 // array type tests
1072
1073 assertSame("double type", double.class,
1074 ArrayUtils.subarray(array, 2, 4).getClass().getComponentType());
1075
1076 }
1077
1078 public void testSubarrayFloat() {
1079 float[] nullArray = null;
1080 float[] array = { 10, 11, 12, 13, 14, 15 };
1081 float[] leftSubarray = { 10, 11, 12, 13 };
1082 float[] midSubarray = { 11, 12, 13, 14 };
1083 float[] rightSubarray = { 12, 13, 14, 15 };
1084
1085
1086 assertTrue("0 start, mid end",
1087 ArrayUtils.isEquals(leftSubarray,
1088 ArrayUtils.subarray(array, 0, 4)));
1089
1090 assertTrue("0 start, length end",
1091 ArrayUtils.isEquals(array,
1092 ArrayUtils.subarray(array, 0, array.length)));
1093
1094 assertTrue("mid start, mid end",
1095 ArrayUtils.isEquals(midSubarray,
1096 ArrayUtils.subarray(array, 1, 5)));
1097
1098 assertTrue("mid start, length end",
1099 ArrayUtils.isEquals(rightSubarray,
1100 ArrayUtils.subarray(array, 2, array.length)));
1101
1102
1103 assertNull("null input", ArrayUtils.subarray(nullArray, 0, 3));
1104
1105 assertEquals("empty array", ArrayUtils.EMPTY_FLOAT_ARRAY,
1106 ArrayUtils.subarray(ArrayUtils.EMPTY_FLOAT_ARRAY, 1, 2));
1107
1108 assertEquals("start > end", ArrayUtils.EMPTY_FLOAT_ARRAY,
1109 ArrayUtils.subarray(array, 4, 2));
1110
1111 assertEquals("start == end", ArrayUtils.EMPTY_FLOAT_ARRAY,
1112 ArrayUtils.subarray(array, 3, 3));
1113
1114 assertTrue("start undershoot, normal end",
1115 ArrayUtils.isEquals(leftSubarray,
1116 ArrayUtils.subarray(array, -2, 4)));
1117
1118 assertEquals("start overshoot, any end",
1119 ArrayUtils.EMPTY_FLOAT_ARRAY,
1120 ArrayUtils.subarray(array, 33, 4));
1121
1122 assertTrue("normal start, end overshoot",
1123 ArrayUtils.isEquals(rightSubarray,
1124 ArrayUtils.subarray(array, 2, 33)));
1125
1126 assertTrue("start undershoot, end overshoot",
1127 ArrayUtils.isEquals(array,
1128 ArrayUtils.subarray(array, -2, 12)));
1129
1130 // empty-return tests
1131
1132 assertSame("empty array, object test",
1133 ArrayUtils.EMPTY_FLOAT_ARRAY,
1134 ArrayUtils.subarray(ArrayUtils.EMPTY_FLOAT_ARRAY, 1, 2));
1135
1136 assertSame("start > end, object test",
1137 ArrayUtils.EMPTY_FLOAT_ARRAY,
1138 ArrayUtils.subarray(array, 4, 1));
1139
1140 assertSame("start == end, object test",
1141 ArrayUtils.EMPTY_FLOAT_ARRAY,
1142 ArrayUtils.subarray(array, 3, 3));
1143
1144 assertSame("start overshoot, any end, object test",
1145 ArrayUtils.EMPTY_FLOAT_ARRAY,
1146 ArrayUtils.subarray(array, 8733, 4));
1147
1148 // array type tests
1149
1150 assertSame("float type", float.class,
1151 ArrayUtils.subarray(array, 2, 4).getClass().getComponentType());
1152
1153 }
1154
1155 public void testSubarrayBoolean() {
1156 boolean[] nullArray = null;
1157 boolean[] array = { true, true, false, true, false, true };
1158 boolean[] leftSubarray = { true, true, false, true };
1159 boolean[] midSubarray = { true, false, true, false };
1160 boolean[] rightSubarray = { false, true, false, true };
1161
1162
1163 assertTrue("0 start, mid end",
1164 ArrayUtils.isEquals(leftSubarray,
1165 ArrayUtils.subarray(array, 0, 4)));
1166
1167 assertTrue("0 start, length end",
1168 ArrayUtils.isEquals(array,
1169 ArrayUtils.subarray(array, 0, array.length)));
1170
1171 assertTrue("mid start, mid end",
1172 ArrayUtils.isEquals(midSubarray,
1173 ArrayUtils.subarray(array, 1, 5)));
1174
1175 assertTrue("mid start, length end",
1176 ArrayUtils.isEquals(rightSubarray,
1177 ArrayUtils.subarray(array, 2, array.length)));
1178
1179
1180 assertNull("null input", ArrayUtils.subarray(nullArray, 0, 3));
1181
1182 assertEquals("empty array", ArrayUtils.EMPTY_BOOLEAN_ARRAY,
1183 ArrayUtils.subarray(ArrayUtils.EMPTY_BOOLEAN_ARRAY, 1, 2));
1184
1185 assertEquals("start > end", ArrayUtils.EMPTY_BOOLEAN_ARRAY,
1186 ArrayUtils.subarray(array, 4, 2));
1187
1188 assertEquals("start == end", ArrayUtils.EMPTY_BOOLEAN_ARRAY,
1189 ArrayUtils.subarray(array, 3, 3));
1190
1191 assertTrue("start undershoot, normal end",
1192 ArrayUtils.isEquals(leftSubarray,
1193 ArrayUtils.subarray(array, -2, 4)));
1194
1195 assertEquals("start overshoot, any end",
1196 ArrayUtils.EMPTY_BOOLEAN_ARRAY,
1197 ArrayUtils.subarray(array, 33, 4));
1198
1199 assertTrue("normal start, end overshoot",
1200 ArrayUtils.isEquals(rightSubarray,
1201 ArrayUtils.subarray(array, 2, 33)));
1202
1203 assertTrue("start undershoot, end overshoot",
1204 ArrayUtils.isEquals(array,
1205 ArrayUtils.subarray(array, -2, 12)));
1206
1207 // empty-return tests
1208
1209 assertSame("empty array, object test",
1210 ArrayUtils.EMPTY_BOOLEAN_ARRAY,
1211 ArrayUtils.subarray(ArrayUtils.EMPTY_BOOLEAN_ARRAY, 1, 2));
1212
1213 assertSame("start > end, object test",
1214 ArrayUtils.EMPTY_BOOLEAN_ARRAY,
1215 ArrayUtils.subarray(array, 4, 1));
1216
1217 assertSame("start == end, object test",
1218 ArrayUtils.EMPTY_BOOLEAN_ARRAY,
1219 ArrayUtils.subarray(array, 3, 3));
1220
1221 assertSame("start overshoot, any end, object test",
1222 ArrayUtils.EMPTY_BOOLEAN_ARRAY,
1223 ArrayUtils.subarray(array, 8733, 4));
1224
1225 // array type tests
1226
1227 assertSame("boolean type", boolean.class,
1228 ArrayUtils.subarray(array, 2, 4).getClass().getComponentType());
1229
1230 }
1231
1232 //-----------------------------------------------------------------------
1233 public void testSameLength() {
1234 Object[] nullArray = null;
1235 Object[] emptyArray = new Object[0];
1236 Object[] oneArray = new Object[] {"pick"};
1237 Object[] twoArray = new Object[] {"pick", "stick"};
1238
1239 assertEquals(true, ArrayUtils.isSameLength(nullArray, nullArray));
1240 assertEquals(true, ArrayUtils.isSameLength(nullArray, emptyArray));
1241 assertEquals(false, ArrayUtils.isSameLength(nullArray, oneArray));
1242 assertEquals(false, ArrayUtils.isSameLength(nullArray, twoArray));
1243
1244 assertEquals(true, ArrayUtils.isSameLength(emptyArray, nullArray));
1245 assertEquals(true, ArrayUtils.isSameLength(emptyArray, emptyArray));
1246 assertEquals(false, ArrayUtils.isSameLength(emptyArray, oneArray));
1247 assertEquals(false, ArrayUtils.isSameLength(emptyArray, twoArray));
1248
1249 assertEquals(false, ArrayUtils.isSameLength(oneArray, nullArray));
1250 assertEquals(false, ArrayUtils.isSameLength(oneArray, emptyArray));
1251 assertEquals(true, ArrayUtils.isSameLength(oneArray, oneArray));
1252 assertEquals(false, ArrayUtils.isSameLength(oneArray, twoArray));
1253
1254 assertEquals(false, ArrayUtils.isSameLength(twoArray, nullArray));
1255 assertEquals(false, ArrayUtils.isSameLength(twoArray, emptyArray));
1256 assertEquals(false, ArrayUtils.isSameLength(twoArray, oneArray));
1257 assertEquals(true, ArrayUtils.isSameLength(twoArray, twoArray));
1258 }
1259
1260 public void testSameLengthBoolean() {
1261 boolean[] nullArray = null;
1262 boolean[] emptyArray = new boolean[0];
1263 boolean[] oneArray = new boolean[] {true};
1264 boolean[] twoArray = new boolean[] {true, false};
1265
1266 assertEquals(true, ArrayUtils.isSameLength(nullArray, nullArray));
1267 assertEquals(true, ArrayUtils.isSameLength(nullArray, emptyArray));
1268 assertEquals(false, ArrayUtils.isSameLength(nullArray, oneArray));
1269 assertEquals(false, ArrayUtils.isSameLength(nullArray, twoArray));
1270
1271 assertEquals(true, ArrayUtils.isSameLength(emptyArray, nullArray));
1272 assertEquals(true, ArrayUtils.isSameLength(emptyArray, emptyArray));
1273 assertEquals(false, ArrayUtils.isSameLength(emptyArray, oneArray));
1274 assertEquals(false, ArrayUtils.isSameLength(emptyArray, twoArray));
1275
1276 assertEquals(false, ArrayUtils.isSameLength(oneArray, nullArray));
1277 assertEquals(false, ArrayUtils.isSameLength(oneArray, emptyArray));
1278 assertEquals(true, ArrayUtils.isSameLength(oneArray, oneArray));
1279 assertEquals(false, ArrayUtils.isSameLength(oneArray, twoArray));
1280
1281 assertEquals(false, ArrayUtils.isSameLength(twoArray, nullArray));
1282 assertEquals(false, ArrayUtils.isSameLength(twoArray, emptyArray));
1283 assertEquals(false, ArrayUtils.isSameLength(twoArray, oneArray));
1284 assertEquals(true, ArrayUtils.isSameLength(twoArray, twoArray));
1285 }
1286
1287 public void testSameLengthLong() {
1288 long[] nullArray = null;
1289 long[] emptyArray = new long[0];
1290 long[] oneArray = new long[] {0L};
1291 long[] twoArray = new long[] {0L, 76L};
1292
1293 assertEquals(true, ArrayUtils.isSameLength(nullArray, nullArray));
1294 assertEquals(true, ArrayUtils.isSameLength(nullArray, emptyArray));
1295 assertEquals(false, ArrayUtils.isSameLength(nullArray, oneArray));
1296 assertEquals(false, ArrayUtils.isSameLength(nullArray, twoArray));
1297
1298 assertEquals(true, ArrayUtils.isSameLength(emptyArray, nullArray));
1299 assertEquals(true, ArrayUtils.isSameLength(emptyArray, emptyArray));
1300 assertEquals(false, ArrayUtils.isSameLength(emptyArray, oneArray));
1301 assertEquals(false, ArrayUtils.isSameLength(emptyArray, twoArray));
1302
1303 assertEquals(false, ArrayUtils.isSameLength(oneArray, nullArray));
1304 assertEquals(false, ArrayUtils.isSameLength(oneArray, emptyArray));
1305 assertEquals(true, ArrayUtils.isSameLength(oneArray, oneArray));
1306 assertEquals(false, ArrayUtils.isSameLength(oneArray, twoArray));
1307
1308 assertEquals(false, ArrayUtils.isSameLength(twoArray, nullArray));
1309 assertEquals(false, ArrayUtils.isSameLength(twoArray, emptyArray));
1310 assertEquals(false, ArrayUtils.isSameLength(twoArray, oneArray));
1311 assertEquals(true, ArrayUtils.isSameLength(twoArray, twoArray));
1312 }
1313
1314 public void testSameLengthInt() {
1315 int[] nullArray = null;
1316 int[] emptyArray = new int[0];
1317 int[] oneArray = new int[] {4};
1318 int[] twoArray = new int[] {5, 7};
1319
1320 assertEquals(true, ArrayUtils.isSameLength(nullArray, nullArray));
1321 assertEquals(true, ArrayUtils.isSameLength(nullArray, emptyArray));
1322 assertEquals(false, ArrayUtils.isSameLength(nullArray, oneArray));
1323 assertEquals(false, ArrayUtils.isSameLength(nullArray, twoArray));
1324
1325 assertEquals(true, ArrayUtils.isSameLength(emptyArray, nullArray));
1326 assertEquals(true, ArrayUtils.isSameLength(emptyArray, emptyArray));
1327 assertEquals(false, ArrayUtils.isSameLength(emptyArray, oneArray));
1328 assertEquals(false, ArrayUtils.isSameLength(emptyArray, twoArray));
1329
1330 assertEquals(false, ArrayUtils.isSameLength(oneArray, nullArray));
1331 assertEquals(false, ArrayUtils.isSameLength(oneArray, emptyArray));
1332 assertEquals(true, ArrayUtils.isSameLength(oneArray, oneArray));
1333 assertEquals(false, ArrayUtils.isSameLength(oneArray, twoArray));
1334
1335 assertEquals(false, ArrayUtils.isSameLength(twoArray, nullArray));
1336 assertEquals(false, ArrayUtils.isSameLength(twoArray, emptyArray));
1337 assertEquals(false, ArrayUtils.isSameLength(twoArray, oneArray));
1338 assertEquals(true, ArrayUtils.isSameLength(twoArray, twoArray));
1339 }
1340
1341 public void testSameLengthShort() {
1342 short[] nullArray = null;
1343 short[] emptyArray = new short[0];
1344 short[] oneArray = new short[] {4};
1345 short[] twoArray = new short[] {6, 8};
1346
1347 assertEquals(true, ArrayUtils.isSameLength(nullArray, nullArray));
1348 assertEquals(true, ArrayUtils.isSameLength(nullArray, emptyArray));
1349 assertEquals(false, ArrayUtils.isSameLength(nullArray, oneArray));
1350 assertEquals(false, ArrayUtils.isSameLength(nullArray, twoArray));
1351
1352 assertEquals(true, ArrayUtils.isSameLength(emptyArray, nullArray));
1353 assertEquals(true, ArrayUtils.isSameLength(emptyArray, emptyArray));
1354 assertEquals(false, ArrayUtils.isSameLength(emptyArray, oneArray));
1355 assertEquals(false, ArrayUtils.isSameLength(emptyArray, twoArray));
1356
1357 assertEquals(false, ArrayUtils.isSameLength(oneArray, nullArray));
1358 assertEquals(false, ArrayUtils.isSameLength(oneArray, emptyArray));
1359 assertEquals(true, ArrayUtils.isSameLength(oneArray, oneArray));
1360 assertEquals(false, ArrayUtils.isSameLength(oneArray, twoArray));
1361
1362 assertEquals(false, ArrayUtils.isSameLength(twoArray, nullArray));
1363 assertEquals(false, ArrayUtils.isSameLength(twoArray, emptyArray));
1364 assertEquals(false, ArrayUtils.isSameLength(twoArray, oneArray));
1365 assertEquals(true, ArrayUtils.isSameLength(twoArray, twoArray));
1366 }
1367
1368 public void testSameLengthChar() {
1369 char[] nullArray = null;
1370 char[] emptyArray = new char[0];
1371 char[] oneArray = new char[] {'f'};
1372 char[] twoArray = new char[] {'d', 't'};
1373
1374 assertEquals(true, ArrayUtils.isSameLength(nullArray, nullArray));
1375 assertEquals(true, ArrayUtils.isSameLength(nullArray, emptyArray));
1376 assertEquals(false, ArrayUtils.isSameLength(nullArray, oneArray));
1377 assertEquals(false, ArrayUtils.isSameLength(nullArray, twoArray));
1378
1379 assertEquals(true, ArrayUtils.isSameLength(emptyArray, nullArray));
1380 assertEquals(true, ArrayUtils.isSameLength(emptyArray, emptyArray));
1381 assertEquals(false, ArrayUtils.isSameLength(emptyArray, oneArray));
1382 assertEquals(false, ArrayUtils.isSameLength(emptyArray, twoArray));
1383
1384 assertEquals(false, ArrayUtils.isSameLength(oneArray, nullArray));
1385 assertEquals(false, ArrayUtils.isSameLength(oneArray, emptyArray));
1386 assertEquals(true, ArrayUtils.isSameLength(oneArray, oneArray));
1387 assertEquals(false, ArrayUtils.isSameLength(oneArray, twoArray));
1388
1389 assertEquals(false, ArrayUtils.isSameLength(twoArray, nullArray));
1390 assertEquals(false, ArrayUtils.isSameLength(twoArray, emptyArray));
1391 assertEquals(false, ArrayUtils.isSameLength(twoArray, oneArray));
1392 assertEquals(true, ArrayUtils.isSameLength(twoArray, twoArray));
1393 }
1394
1395 public void testSameLengthByte() {
1396 byte[] nullArray = null;
1397 byte[] emptyArray = new byte[0];
1398 byte[] oneArray = new byte[] {3};
1399 byte[] twoArray = new byte[] {4, 6};
1400
1401 assertEquals(true, ArrayUtils.isSameLength(nullArray, nullArray));
1402 assertEquals(true, ArrayUtils.isSameLength(nullArray, emptyArray));
1403 assertEquals(false, ArrayUtils.isSameLength(nullArray, oneArray));
1404 assertEquals(false, ArrayUtils.isSameLength(nullArray, twoArray));
1405
1406 assertEquals(true, ArrayUtils.isSameLength(emptyArray, nullArray));
1407 assertEquals(true, ArrayUtils.isSameLength(emptyArray, emptyArray));
1408 assertEquals(false, ArrayUtils.isSameLength(emptyArray, oneArray));
1409 assertEquals(false, ArrayUtils.isSameLength(emptyArray, twoArray));
1410
1411 assertEquals(false, ArrayUtils.isSameLength(oneArray, nullArray));
1412 assertEquals(false, ArrayUtils.isSameLength(oneArray, emptyArray));
1413 assertEquals(true, ArrayUtils.isSameLength(oneArray, oneArray));
1414 assertEquals(false, ArrayUtils.isSameLength(oneArray, twoArray));
1415
1416 assertEquals(false, ArrayUtils.isSameLength(twoArray, nullArray));
1417 assertEquals(false, ArrayUtils.isSameLength(twoArray, emptyArray));
1418 assertEquals(false, ArrayUtils.isSameLength(twoArray, oneArray));
1419 assertEquals(true, ArrayUtils.isSameLength(twoArray, twoArray));
1420 }
1421
1422 public void testSameLengthDouble() {
1423 double[] nullArray = null;
1424 double[] emptyArray = new double[0];
1425 double[] oneArray = new double[] {1.3d};
1426 double[] twoArray = new double[] {4.5d, 6.3d};
1427
1428 assertEquals(true, ArrayUtils.isSameLength(nullArray, nullArray));
1429 assertEquals(true, ArrayUtils.isSameLength(nullArray, emptyArray));
1430 assertEquals(false, ArrayUtils.isSameLength(nullArray, oneArray));
1431 assertEquals(false, ArrayUtils.isSameLength(nullArray, twoArray));
1432
1433 assertEquals(true, ArrayUtils.isSameLength(emptyArray, nullArray));
1434 assertEquals(true, ArrayUtils.isSameLength(emptyArray, emptyArray));
1435 assertEquals(false, ArrayUtils.isSameLength(emptyArray, oneArray));
1436 assertEquals(false, ArrayUtils.isSameLength(emptyArray, twoArray));
1437
1438 assertEquals(false, ArrayUtils.isSameLength(oneArray, nullArray));
1439 assertEquals(false, ArrayUtils.isSameLength(oneArray, emptyArray));
1440 assertEquals(true, ArrayUtils.isSameLength(oneArray, oneArray));
1441 assertEquals(false, ArrayUtils.isSameLength(oneArray, twoArray));
1442
1443 assertEquals(false, ArrayUtils.isSameLength(twoArray, nullArray));
1444 assertEquals(false, ArrayUtils.isSameLength(twoArray, emptyArray));
1445 assertEquals(false, ArrayUtils.isSameLength(twoArray, oneArray));
1446 assertEquals(true, ArrayUtils.isSameLength(twoArray, twoArray));
1447 }
1448
1449 public void testSameLengthFloat() {
1450 float[] nullArray = null;
1451 float[] emptyArray = new float[0];
1452 float[] oneArray = new float[] {2.5f};
1453 float[] twoArray = new float[] {6.4f, 5.8f};
1454
1455 assertEquals(true, ArrayUtils.isSameLength(nullArray, nullArray));
1456 assertEquals(true, ArrayUtils.isSameLength(nullArray, emptyArray));
1457 assertEquals(false, ArrayUtils.isSameLength(nullArray, oneArray));
1458 assertEquals(false, ArrayUtils.isSameLength(nullArray, twoArray));
1459
1460 assertEquals(true, ArrayUtils.isSameLength(emptyArray, nullArray));
1461 assertEquals(true, ArrayUtils.isSameLength(emptyArray, emptyArray));
1462 assertEquals(false, ArrayUtils.isSameLength(emptyArray, oneArray));
1463 assertEquals(false, ArrayUtils.isSameLength(emptyArray, twoArray));
1464
1465 assertEquals(false, ArrayUtils.isSameLength(oneArray, nullArray));
1466 assertEquals(false, ArrayUtils.isSameLength(oneArray, emptyArray));
1467 assertEquals(true, ArrayUtils.isSameLength(oneArray, oneArray));
1468 assertEquals(false, ArrayUtils.isSameLength(oneArray, twoArray));
1469
1470 assertEquals(false, ArrayUtils.isSameLength(twoArray, nullArray));
1471 assertEquals(false, ArrayUtils.isSameLength(twoArray, emptyArray));
1472 assertEquals(false, ArrayUtils.isSameLength(twoArray, oneArray));
1473 assertEquals(true, ArrayUtils.isSameLength(twoArray, twoArray));
1474 }
1475
1476 //-----------------------------------------------------------------------
1477 public void testSameType() {
1478 try {
1479 ArrayUtils.isSameType(null, null);
1480 fail();
1481 } catch (IllegalArgumentException ex) {}
1482 try {
1483 ArrayUtils.isSameType(null, new Object[0]);
1484 fail();
1485 } catch (IllegalArgumentException ex) {}
1486 try {
1487 ArrayUtils.isSameType(new Object[0], null);
1488 fail();
1489 } catch (IllegalArgumentException ex) {}
1490
1491 assertEquals(true, ArrayUtils.isSameType(new Object[0], new Object[0]));
1492 assertEquals(false, ArrayUtils.isSameType(new String[0], new Object[0]));
1493 assertEquals(true, ArrayUtils.isSameType(new String[0][0], new String[0][0]));
1494 assertEquals(false, ArrayUtils.isSameType(new String[0], new String[0][0]));
1495 assertEquals(false, ArrayUtils.isSameType(new String[0][0], new String[0]));
1496 }
1497
1498 //-----------------------------------------------------------------------
1499 public void testReverse() {
1500 StringBuffer str1 = new StringBuffer("pick");
1501 String str2 = "a";
1502 String[] str3 = new String[] {"stick"};
1503 String str4 = "up";
1504
1505 Object[] array = new Object[] {str1, str2, str3};
1506 ArrayUtils.reverse(array);
1507 assertEquals(array[0], str3);
1508 assertEquals(array[1], str2);
1509 assertEquals(array[2], str1);
1510
1511 array = new Object[] {str1, str2, str3, str4};
1512 ArrayUtils.reverse(array);
1513 assertEquals(array[0], str4);
1514 assertEquals(array[1], str3);
1515 assertEquals(array[2], str2);
1516 assertEquals(array[3], str1);
1517
1518 array = null;
1519 ArrayUtils.reverse(array);
1520 assertEquals(null, array);
1521 }
1522
1523 public void testReverseLong() {
1524 long[] array = new long[] {1L, 2L, 3L};
1525 ArrayUtils.reverse(array);
1526 assertEquals(array[0], 3L);
1527 assertEquals(array[1], 2L);
1528 assertEquals(array[2], 1L);
1529
1530 array = null;
1531 ArrayUtils.reverse(array);
1532 assertEquals(null, array);
1533 }
1534
1535 public void testReverseInt() {
1536 int[] array = new int[] {1, 2, 3};
1537 ArrayUtils.reverse(array);
1538 assertEquals(array[0], 3);
1539 assertEquals(array[1], 2);
1540 assertEquals(array[2], 1);
1541
1542 array = null;
1543 ArrayUtils.reverse(array);
1544 assertEquals(null, array);
1545 }
1546
1547 public void testReverseShort() {
1548 short[] array = new short[] {1, 2, 3};
1549 ArrayUtils.reverse(array);
1550 assertEquals(array[0], 3);
1551 assertEquals(array[1], 2);
1552 assertEquals(array[2], 1);
1553
1554 array = null;
1555 ArrayUtils.reverse(array);
1556 assertEquals(null, array);
1557 }
1558
1559 public void testReverseChar() {
1560 char[] array = new char[] {'a', 'f', 'C'};
1561 ArrayUtils.reverse(array);
1562 assertEquals(array[0], 'C');
1563 assertEquals(array[1], 'f');
1564 assertEquals(array[2], 'a');
1565
1566 array = null;
1567 ArrayUtils.reverse(array);
1568 assertEquals(null, array);
1569 }
1570
1571 public void testReverseByte() {
1572 byte[] array = new byte[] {2, 3, 4};
1573 ArrayUtils.reverse(array);
1574 assertEquals(array[0], 4);
1575 assertEquals(array[1], 3);
1576 assertEquals(array[2], 2);
1577
1578 array = null;
1579 ArrayUtils.reverse(array);
1580 assertEquals(null, array);
1581 }
1582
1583 public void testReverseDouble() {
1584 double[] array = new double[] {0.3d, 0.4d, 0.5d};
1585 ArrayUtils.reverse(array);
1586 assertEquals(array[0], 0.5d, 0.0d);
1587 assertEquals(array[1], 0.4d, 0.0d);
1588 assertEquals(array[2], 0.3d, 0.0d);
1589
1590 array = null;
1591 ArrayUtils.reverse(array);
1592 assertEquals(null, array);
1593 }
1594
1595 public void testReverseFloat() {
1596 float[] array = new float[] {0.3f, 0.4f, 0.5f};
1597 ArrayUtils.reverse(array);
1598 assertEquals(array[0], 0.5f, 0.0f);
1599 assertEquals(array[1], 0.4f, 0.0f);
1600 assertEquals(array[2], 0.3f, 0.0f);
1601
1602 array = null;
1603 ArrayUtils.reverse(array);
1604 assertEquals(null, array);
1605 }
1606
1607 public void testReverseBoolean() {
1608 boolean[] array = new boolean[] {false, false, true};
1609 ArrayUtils.reverse(array);
1610 assertEquals(array[0], true);
1611 assertEquals(array[1], false);
1612 assertEquals(array[2], false);
1613
1614 array = null;
1615 ArrayUtils.reverse(array);
1616 assertEquals(null, array);
1617 }
1618
1619 //-----------------------------------------------------------------------
1620 public void testIndexOf() {
1621 Object[] array = new Object[] { "0", "1", "2", "3", null, "0" };
1622 assertEquals(-1, ArrayUtils.indexOf(null, null));
1623 assertEquals(-1, ArrayUtils.indexOf(null, "0"));
1624 assertEquals(-1, ArrayUtils.indexOf(new Object[0], "0"));
1625 assertEquals(0, ArrayUtils.indexOf(array, "0"));
1626 assertEquals(1, ArrayUtils.indexOf(array, "1"));
1627 assertEquals(2, ArrayUtils.indexOf(array, "2"));
1628 assertEquals(3, ArrayUtils.indexOf(array, "3"));
1629 assertEquals(4, ArrayUtils.indexOf(array, null));
1630 assertEquals(-1, ArrayUtils.indexOf(array, "notInArray"));
1631 }
1632
1633 public void testIndexOfWithStartIndex() {
1634 Object[] array = new Object[] { "0", "1", "2", "3", null, "0" };
1635 assertEquals(-1, ArrayUtils.indexOf(null, null, 2));
1636 assertEquals(-1, ArrayUtils.indexOf(new Object[0], "0", 0));
1637 assertEquals(-1, ArrayUtils.indexOf(null, "0", 2));
1638 assertEquals(5, ArrayUtils.indexOf(array, "0", 2));
1639 assertEquals(-1, ArrayUtils.indexOf(array, "1", 2));
1640 assertEquals(2, ArrayUtils.indexOf(array, "2", 2));
1641 assertEquals(3, ArrayUtils.indexOf(array, "3", 2));
1642 assertEquals(4, ArrayUtils.indexOf(array, null, 2));
1643 assertEquals(-1, ArrayUtils.indexOf(array, "notInArray", 2));
1644
1645 assertEquals(4, ArrayUtils.indexOf(array, null, -1));
1646 assertEquals(-1, ArrayUtils.indexOf(array, null, 8));
1647 assertEquals(-1, ArrayUtils.indexOf(array, "0", 8));
1648 }
1649
1650 public void testLastIndexOf() {
1651 Object[] array = new Object[] { "0", "1", "2", "3", null, "0" };
1652 assertEquals(-1, ArrayUtils.lastIndexOf(null, null));
1653 assertEquals(-1, ArrayUtils.lastIndexOf(null, "0"));
1654 assertEquals(5, ArrayUtils.lastIndexOf(array, "0"));
1655 assertEquals(1, ArrayUtils.lastIndexOf(array, "1"));
1656 assertEquals(2, ArrayUtils.lastIndexOf(array, "2"));
1657 assertEquals(3, ArrayUtils.lastIndexOf(array, "3"));
1658 assertEquals(4, ArrayUtils.lastIndexOf(array, null));
1659 assertEquals(-1, ArrayUtils.lastIndexOf(array, "notInArray"));
1660 }
1661
1662 public void testLastIndexOfWithStartIndex() {
1663 Object[] array = new Object[] { "0", "1", "2", "3", null, "0" };
1664 assertEquals(-1, ArrayUtils.lastIndexOf(null, null, 2));
1665 assertEquals(-1, ArrayUtils.lastIndexOf(null, "0", 2));
1666 assertEquals(0, ArrayUtils.lastIndexOf(array, "0", 2));
1667 assertEquals(1, ArrayUtils.lastIndexOf(array, "1", 2));
1668 assertEquals(2, ArrayUtils.lastIndexOf(array, "2", 2));
1669 assertEquals(-1, ArrayUtils.lastIndexOf(array, "3", 2));
1670 assertEquals(-1, ArrayUtils.lastIndexOf(array, "3", -1));
1671 assertEquals(4, ArrayUtils.lastIndexOf(array, null, 5));
1672 assertEquals(-1, ArrayUtils.lastIndexOf(array, null, 2));
1673 assertEquals(-1, ArrayUtils.lastIndexOf(array, "notInArray", 5));
1674
1675 assertEquals(-1, ArrayUtils.lastIndexOf(array, null, -1));
1676 assertEquals(5, ArrayUtils.lastIndexOf(array, "0", 88));
1677 }
1678
1679 public void testContains() {
1680 Object[] array = new Object[] { "0", "1", "2", "3", null, "0" };
1681 assertEquals(false, ArrayUtils.contains(null, null));
1682 assertEquals(false, ArrayUtils.contains(null, "1"));
1683 assertEquals(true, ArrayUtils.contains(array, "0"));
1684 assertEquals(true, ArrayUtils.contains(array, "1"));
1685 assertEquals(true, ArrayUtils.contains(array, "2"));
1686 assertEquals(true, ArrayUtils.contains(array, "3"));
1687 assertEquals(true, ArrayUtils.contains(array, null));
1688 assertEquals(false, ArrayUtils.contains(array, "notInArray"));
1689 }
1690
1691 //-----------------------------------------------------------------------
1692 public void testIndexOfLong() {
1693 long[] array = null;
1694 assertEquals(-1, ArrayUtils.indexOf(array, 0));
1695 array = new long[] { 0, 1, 2, 3, 0 };
1696 assertEquals(0, ArrayUtils.indexOf(array, 0));
1697 assertEquals(1, ArrayUtils.indexOf(array, 1));
1698 assertEquals(2, ArrayUtils.indexOf(array, 2));
1699 assertEquals(3, ArrayUtils.indexOf(array, 3));
1700 assertEquals(-1, ArrayUtils.indexOf(array, 99));
1701 }
1702
1703 public void testIndexOfLongWithStartIndex() {
1704 long[] array = null;
1705 assertEquals(-1, ArrayUtils.indexOf(array, 0, 2));
1706 array = new long[] { 0, 1, 2, 3, 0 };
1707 assertEquals(4, ArrayUtils.indexOf(array, 0, 2));
1708 assertEquals(-1, ArrayUtils.indexOf(array, 1, 2));
1709 assertEquals(2, ArrayUtils.indexOf(array, 2, 2));
1710 assertEquals(3, ArrayUtils.indexOf(array, 3, 2));
1711 assertEquals(3, ArrayUtils.indexOf(array, 3, -1));
1712 assertEquals(-1, ArrayUtils.indexOf(array, 99, 0));
1713 assertEquals(-1, ArrayUtils.indexOf(array, 0, 6));
1714 }
1715
1716 public void testLastIndexOfLong() {
1717 long[] array = null;
1718 assertEquals(-1, ArrayUtils.lastIndexOf(array, 0));
1719 array = new long[] { 0, 1, 2, 3, 0 };
1720 assertEquals(4, ArrayUtils.lastIndexOf(array, 0));
1721 assertEquals(1, ArrayUtils.lastIndexOf(array, 1));
1722 assertEquals(2, ArrayUtils.lastIndexOf(array, 2));
1723 assertEquals(3, ArrayUtils.lastIndexOf(array, 3));
1724 assertEquals(-1, ArrayUtils.lastIndexOf(array, 99));
1725 }
1726
1727 public void testLastIndexOfLongWithStartIndex() {
1728 long[] array = null;
1729 assertEquals(-1, ArrayUtils.lastIndexOf(array, 0, 2));
1730 array = new long[] { 0, 1, 2, 3, 0 };
1731 assertEquals(0, ArrayUtils.lastIndexOf(array, 0, 2));
1732 assertEquals(1, ArrayUtils.lastIndexOf(array, 1, 2));
1733 assertEquals(2, ArrayUtils.lastIndexOf(array, 2, 2));
1734 assertEquals(-1, ArrayUtils.lastIndexOf(array, 3, 2));
1735 assertEquals(-1, ArrayUtils.lastIndexOf(array, 3, -1));
1736 assertEquals(-1, ArrayUtils.lastIndexOf(array, 99, 4));
1737 assertEquals(4, ArrayUtils.lastIndexOf(array, 0, 88));
1738 }
1739
1740 public void testContainsLong() {
1741 long[] array = null;
1742 assertEquals(false, ArrayUtils.contains(array, 1));
1743 array = new long[] { 0, 1, 2, 3, 0 };
1744 assertEquals(true, ArrayUtils.contains(array, 0));
1745 assertEquals(true, ArrayUtils.contains(array, 1));
1746 assertEquals(true, ArrayUtils.contains(array, 2));
1747 assertEquals(true, ArrayUtils.contains(array, 3));
1748 assertEquals(false, ArrayUtils.contains(array, 99));
1749 }
1750
1751 //-----------------------------------------------------------------------
1752 public void testIndexOfInt() {
1753 int[] array = null;
1754 assertEquals(-1, ArrayUtils.indexOf(array, 0));
1755 array = new int[] { 0, 1, 2, 3, 0 };
1756 assertEquals(0, ArrayUtils.indexOf(array, 0));
1757 assertEquals(1, ArrayUtils.indexOf(array, 1));
1758 assertEquals(2, ArrayUtils.indexOf(array, 2));
1759 assertEquals(3, ArrayUtils.indexOf(array, 3));
1760 assertEquals(-1, ArrayUtils.indexOf(array, 99));
1761 }
1762
1763 public void testIndexOfIntWithStartIndex() {
1764 int[] array = null;
1765 assertEquals(-1, ArrayUtils.indexOf(array, 0, 2));
1766 array = new int[] { 0, 1, 2, 3, 0 };
1767 assertEquals(4, ArrayUtils.indexOf(array, 0, 2));
1768 assertEquals(-1, ArrayUtils.indexOf(array, 1, 2));
1769 assertEquals(2, ArrayUtils.indexOf(array, 2, 2));
1770 assertEquals(3, ArrayUtils.indexOf(array, 3, 2));
1771 assertEquals(3, ArrayUtils.indexOf(array, 3, -1));
1772 assertEquals(-1, ArrayUtils.indexOf(array, 99, 0));
1773 assertEquals(-1, ArrayUtils.indexOf(array, 0, 6));
1774 }
1775
1776 public void testLastIndexOfInt() {
1777 int[] array = null;
1778 assertEquals(-1, ArrayUtils.lastIndexOf(array, 0));
1779 array = new int[] { 0, 1, 2, 3, 0 };
1780 assertEquals(4, ArrayUtils.lastIndexOf(array, 0));
1781 assertEquals(1, ArrayUtils.lastIndexOf(array, 1));
1782 assertEquals(2, ArrayUtils.lastIndexOf(array, 2));
1783 assertEquals(3, ArrayUtils.lastIndexOf(array, 3));
1784 assertEquals(-1, ArrayUtils.lastIndexOf(array, 99));
1785 }
1786
1787 public void testLastIndexOfIntWithStartIndex() {
1788 int[] array = null;
1789 assertEquals(-1, ArrayUtils.lastIndexOf(array, 0, 2));
1790 array = new int[] { 0, 1, 2, 3, 0 };
1791 assertEquals(0, ArrayUtils.lastIndexOf(array, 0, 2));
1792 assertEquals(1, ArrayUtils.lastIndexOf(array, 1, 2));
1793 assertEquals(2, ArrayUtils.lastIndexOf(array, 2, 2));
1794 assertEquals(-1, ArrayUtils.lastIndexOf(array, 3, 2));
1795 assertEquals(-1, ArrayUtils.lastIndexOf(array, 3, -1));
1796 assertEquals(-1, ArrayUtils.lastIndexOf(array, 99));
1797 assertEquals(4, ArrayUtils.lastIndexOf(array, 0, 88));
1798 }
1799
1800 public void testContainsInt() {
1801 int[] array = null;
1802 assertEquals(false, ArrayUtils.contains(array, 1));
1803 array = new int[] { 0, 1, 2, 3, 0 };
1804 assertEquals(true, ArrayUtils.contains(array, 0));
1805 assertEquals(true, ArrayUtils.contains(array, 1));
1806 assertEquals(true, ArrayUtils.contains(array, 2));
1807 assertEquals(true, ArrayUtils.contains(array, 3));
1808 assertEquals(false, ArrayUtils.contains(array, 99));
1809 }
1810
1811 //-----------------------------------------------------------------------
1812 public void testIndexOfShort() {
1813 short[] array = null;
1814 assertEquals(-1, ArrayUtils.indexOf(array, (short) 0));
1815 array = new short[] { 0, 1, 2, 3, 0 };
1816 assertEquals(0, ArrayUtils.indexOf(array, (short) 0));
1817 assertEquals(1, ArrayUtils.indexOf(array, (short) 1));
1818 assertEquals(2, ArrayUtils.indexOf(array, (short) 2));
1819 assertEquals(3, ArrayUtils.indexOf(array, (short) 3));
1820 assertEquals(-1, ArrayUtils.indexOf(array, (short) 99));
1821 }
1822
1823 public void testIndexOfShortWithStartIndex() {
1824 short[] array = null;
1825 assertEquals(-1, ArrayUtils.indexOf(array, (short) 0, 2));
1826 array = new short[] { 0, 1, 2, 3, 0 };
1827 assertEquals(4, ArrayUtils.indexOf(array, (short) 0, 2));
1828 assertEquals(-1, ArrayUtils.indexOf(array, (short) 1, 2));
1829 assertEquals(2, ArrayUtils.indexOf(array, (short) 2, 2));
1830 assertEquals(3, ArrayUtils.indexOf(array, (short) 3, 2));
1831 assertEquals(3, ArrayUtils.indexOf(array, (short) 3, -1));
1832 assertEquals(-1, ArrayUtils.indexOf(array, (short) 99, 0));
1833 assertEquals(-1, ArrayUtils.indexOf(array, (short) 0, 6));
1834 }
1835
1836 public void testLastIndexOfShort() {
1837 short[] array = null;
1838 assertEquals(-1, ArrayUtils.lastIndexOf(array, (short) 0));
1839 array = new short[] { 0, 1, 2, 3, 0 };
1840 assertEquals(4, ArrayUtils.lastIndexOf(array, (short) 0));
1841 assertEquals(1, ArrayUtils.lastIndexOf(array, (short) 1));
1842 assertEquals(2, ArrayUtils.lastIndexOf(array, (short) 2));
1843 assertEquals(3, ArrayUtils.lastIndexOf(array, (short) 3));
1844 assertEquals(-1, ArrayUtils.lastIndexOf(array, (short) 99));
1845 }
1846
1847 public void testLastIndexOfShortWithStartIndex() {
1848 short[] array = null;
1849 assertEquals(-1, ArrayUtils.lastIndexOf(array, (short) 0, 2));
1850 array = new short[] { 0, 1, 2, 3, 0 };
1851 assertEquals(0, ArrayUtils.lastIndexOf(array, (short) 0, 2));
1852 assertEquals(1, ArrayUtils.lastIndexOf(array, (short) 1, 2));
1853 assertEquals(2, ArrayUtils.lastIndexOf(array, (short) 2, 2));
1854 assertEquals(-1, ArrayUtils.lastIndexOf(array, (short) 3, 2));
1855 assertEquals(-1, ArrayUtils.lastIndexOf(array, (short) 3, -1));
1856 assertEquals(-1, ArrayUtils.lastIndexOf(array, (short) 99));
1857 assertEquals(4, ArrayUtils.lastIndexOf(array, (short) 0, 88));
1858 }
1859
1860 public void testContainsShort() {
1861 short[] array = null;
1862 assertEquals(false, ArrayUtils.contains(array, (short) 1));
1863 array = new short[] { 0, 1, 2, 3, 0 };
1864 assertEquals(true, ArrayUtils.contains(array, (short) 0));
1865 assertEquals(true, ArrayUtils.contains(array, (short) 1));
1866 assertEquals(true, ArrayUtils.contains(array, (short) 2));
1867 assertEquals(true, ArrayUtils.contains(array, (short) 3));
1868 assertEquals(false, ArrayUtils.contains(array, (short) 99));
1869 }
1870
1871 //-----------------------------------------------------------------------
1872 public void testIndexOfChar() {
1873 char[] array = null;
1874 assertEquals(-1, ArrayUtils.indexOf(array, 'a'));
1875 array = new char[] { 'a', 'b', 'c', 'd', 'a' };
1876 assertEquals(0, ArrayUtils.indexOf(array, 'a'));
1877 assertEquals(1, ArrayUtils.indexOf(array, 'b'));
1878 assertEquals(2, ArrayUtils.indexOf(array, 'c'));
1879 assertEquals(3, ArrayUtils.indexOf(array, 'd'));
1880 assertEquals(-1, ArrayUtils.indexOf(array, 'e'));
1881 }
1882
1883 public void testIndexOfCharWithStartIndex() {
1884 char[] array = null;
1885 assertEquals(-1, ArrayUtils.indexOf(array, 'a', 2));
1886 array = new char[] { 'a', 'b', 'c', 'd', 'a' };
1887 assertEquals(4, ArrayUtils.indexOf(array, 'a', 2));
1888 assertEquals(-1, ArrayUtils.indexOf(array, 'b', 2));
1889 assertEquals(2, ArrayUtils.indexOf(array, 'c', 2));
1890 assertEquals(3, ArrayUtils.indexOf(array, 'd', 2));
1891 assertEquals(3, ArrayUtils.indexOf(array, 'd', -1));
1892 assertEquals(-1, ArrayUtils.indexOf(array, 'e', 0));
1893 assertEquals(-1, ArrayUtils.indexOf(array, 'a', 6));
1894 }
1895
1896 public void testLastIndexOfChar() {
1897 char[] array = null;
1898 assertEquals(-1, ArrayUtils.lastIndexOf(array, 'a'));
1899 array = new char[] { 'a', 'b', 'c', 'd', 'a' };
1900 assertEquals(4, ArrayUtils.lastIndexOf(array, 'a'));
1901 assertEquals(1, ArrayUtils.lastIndexOf(array, 'b'));
1902 assertEquals(2, ArrayUtils.lastIndexOf(array, 'c'));
1903 assertEquals(3, ArrayUtils.lastIndexOf(array, 'd'));
1904 assertEquals(-1, ArrayUtils.lastIndexOf(array, 'e'));
1905 }
1906
1907 public void testLastIndexOfCharWithStartIndex() {
1908 char[] array = null;
1909 assertEquals(-1, ArrayUtils.lastIndexOf(array, 'a', 2));
1910 array = new char[] { 'a', 'b', 'c', 'd', 'a' };
1911 assertEquals(0, ArrayUtils.lastIndexOf(array, 'a', 2));
1912 assertEquals(1, ArrayUtils.lastIndexOf(array, 'b', 2));
1913 assertEquals(2, ArrayUtils.lastIndexOf(array, 'c', 2));
1914 assertEquals(-1, ArrayUtils.lastIndexOf(array, 'd', 2));
1915 assertEquals(-1, ArrayUtils.lastIndexOf(array, 'd', -1));
1916 assertEquals(-1, ArrayUtils.lastIndexOf(array, 'e'));
1917 assertEquals(4, ArrayUtils.lastIndexOf(array, 'a', 88));
1918 }
1919
1920 public void testContainsChar() {
1921 char[] array = null;
1922 assertEquals(false, ArrayUtils.contains(array, 'b'));
1923 array = new char[] { 'a', 'b', 'c', 'd', 'a' };
1924 assertEquals(true, ArrayUtils.contains(array, 'a'));
1925 assertEquals(true, ArrayUtils.contains(array, 'b'));
1926 assertEquals(true, ArrayUtils.contains(array, 'c'));
1927 assertEquals(true, ArrayUtils.contains(array, 'd'));
1928 assertEquals(false, ArrayUtils.contains(array, 'e'));
1929 }
1930
1931 //-----------------------------------------------------------------------
1932 public void testIndexOfByte() {
1933 byte[] array = null;
1934 assertEquals(-1, ArrayUtils.indexOf(array, (byte) 0));
1935 array = new byte[] { 0, 1, 2, 3, 0 };
1936 assertEquals(0, ArrayUtils.indexOf(array, (byte) 0));
1937 assertEquals(1, ArrayUtils.indexOf(array, (byte) 1));
1938 assertEquals(2, ArrayUtils.indexOf(array, (byte) 2));
1939 assertEquals(3, ArrayUtils.indexOf(array, (byte) 3));
1940 assertEquals(-1, ArrayUtils.indexOf(array, (byte) 99));
1941 }
1942
1943 public void testIndexOfByteWithStartIndex() {
1944 byte[] array = null;
1945 assertEquals(-1, ArrayUtils.indexOf(array, (byte) 0, 2));
1946 array = new byte[] { 0, 1, 2, 3, 0 };
1947 assertEquals(4, ArrayUtils.indexOf(array, (byte) 0, 2));
1948 assertEquals(-1, ArrayUtils.indexOf(array, (byte) 1, 2));
1949 assertEquals(2, ArrayUtils.indexOf(array, (byte) 2, 2));
1950 assertEquals(3, ArrayUtils.indexOf(array, (byte) 3, 2));
1951 assertEquals(3, ArrayUtils.indexOf(array, (byte) 3, -1));
1952 assertEquals(-1, ArrayUtils.indexOf(array, (byte) 99, 0));
1953 assertEquals(-1, ArrayUtils.indexOf(array, (byte) 0, 6));
1954 }
1955
1956 public void testLastIndexOfByte() {
1957 byte[] array = null;
1958 assertEquals(-1, ArrayUtils.lastIndexOf(array, (byte) 0));
1959 array = new byte[] { 0, 1, 2, 3, 0 };
1960 assertEquals(4, ArrayUtils.lastIndexOf(array, (byte) 0));
1961 assertEquals(1, ArrayUtils.lastIndexOf(array, (byte) 1));
1962 assertEquals(2, ArrayUtils.lastIndexOf(array, (byte) 2));
1963 assertEquals(3, ArrayUtils.lastIndexOf(array, (byte) 3));
1964 assertEquals(-1, ArrayUtils.lastIndexOf(array, (byte) 99));
1965 }
1966
1967 public void testLastIndexOfByteWithStartIndex() {
1968 byte[] array = null;
1969 assertEquals(-1, ArrayUtils.lastIndexOf(array, (byte) 0, 2));
1970 array = new byte[] { 0, 1, 2, 3, 0 };
1971 assertEquals(0, ArrayUtils.lastIndexOf(array, (byte) 0, 2));
1972 assertEquals(1, ArrayUtils.lastIndexOf(array, (byte) 1, 2));
1973 assertEquals(2, ArrayUtils.lastIndexOf(array, (byte) 2, 2));
1974 assertEquals(-1, ArrayUtils.lastIndexOf(array, (byte) 3, 2));
1975 assertEquals(-1, ArrayUtils.lastIndexOf(array, (byte) 3, -1));
1976 assertEquals(-1, ArrayUtils.lastIndexOf(array, (byte) 99));
1977 assertEquals(4, ArrayUtils.lastIndexOf(array, (byte) 0, 88));
1978 }
1979
1980 public void testContainsByte() {
1981 byte[] array = null;
1982 assertEquals(false, ArrayUtils.contains(array, (byte) 1));
1983 array = new byte[] { 0, 1, 2, 3, 0 };
1984 assertEquals(true, ArrayUtils.contains(array, (byte) 0));
1985 assertEquals(true, ArrayUtils.contains(array, (byte) 1));
1986 assertEquals(true, ArrayUtils.contains(array, (byte) 2));
1987 assertEquals(true, ArrayUtils.contains(array, (byte) 3));
1988 assertEquals(false, ArrayUtils.contains(array, (byte) 99));
1989 }
1990
1991 //-----------------------------------------------------------------------
1992 @SuppressWarnings("cast")
1993 public void testIndexOfDouble() {
1994 double[] array = null;
1995 assertEquals(-1, ArrayUtils.indexOf(array, (double) 0));
1996 array = new double[0];
1997 assertEquals(-1, ArrayUtils.indexOf(array, (double) 0));
1998 array = new double[] { 0, 1, 2, 3, 0 };
1999 assertEquals(0, ArrayUtils.indexOf(array, (double) 0));
2000 assertEquals(1, ArrayUtils.indexOf(array, (double) 1));
2001 assertEquals(2, ArrayUtils.indexOf(array, (double) 2));
2002 assertEquals(3, ArrayUtils.indexOf(array, (double) 3));
2003 assertEquals(3, ArrayUtils.indexOf(array, (double) 3, -1));
2004 assertEquals(-1, ArrayUtils.indexOf(array, (double) 99));
2005 }
2006
2007 @SuppressWarnings("cast")
2008 public void testIndexOfDoubleTolerance() {
2009 double[] array = null;
2010 assertEquals(-1, ArrayUtils.indexOf(array, (double) 0, (double) 0));
2011 array = new double[0];
2012 assertEquals(-1, ArrayUtils.indexOf(array, (double) 0, (double) 0));
2013 array = new double[] { 0, 1, 2, 3, 0 };
2014 assertEquals(0, ArrayUtils.indexOf(array, (double) 0, (double) 0.3));
2015 assertEquals(2, ArrayUtils.indexOf(array, (double) 2.2, (double) 0.35));
2016 assertEquals(3, ArrayUtils.indexOf(array, (double) 4.15, (double) 2.0));
2017 assertEquals(1, ArrayUtils.indexOf(array, (double) 1.00001324, (double) 0.0001));
2018 }
2019
2020 @SuppressWarnings("cast")
2021 public void testIndexOfDoubleWithStartIndex() {
2022 double[] array = null;
2023 assertEquals(-1, ArrayUtils.indexOf(array, (double) 0, 2));
2024 array = new double[0];
2025 assertEquals(-1, ArrayUtils.indexOf(array, (double) 0, 2));
2026 array = new double[] { 0, 1, 2, 3, 0 };
2027 assertEquals(4, ArrayUtils.indexOf(array, (double) 0, 2));
2028 assertEquals(-1, ArrayUtils.indexOf(array, (double) 1, 2));
2029 assertEquals(2, ArrayUtils.indexOf(array, (double) 2, 2));
2030 assertEquals(3, ArrayUtils.indexOf(array, (double) 3, 2));
2031 assertEquals(-1, ArrayUtils.indexOf(array, (double) 99, 0));
2032 assertEquals(-1, ArrayUtils.indexOf(array, (double) 0, 6));
2033 }
2034
2035 @SuppressWarnings("cast")
2036 public void testIndexOfDoubleWithStartIndexTolerance() {
2037 double[] array = null;
2038 assertEquals(-1, ArrayUtils.indexOf(array, (double) 0, 2, (double) 0));
2039 array = new double[0];
2040 assertEquals(-1, ArrayUtils.indexOf(array, (double) 0, 2, (double) 0));
2041 array = new double[] { 0, 1, 2, 3, 0 };
2042 assertEquals(-1, ArrayUtils.indexOf(array, (double) 0, 99, (double) 0.3));
2043 assertEquals(0, ArrayUtils.indexOf(array, (double) 0, 0, (double) 0.3));
2044 assertEquals(4, ArrayUtils.indexOf(array, (double) 0, 3, (double) 0.3));
2045 assertEquals(2, ArrayUtils.indexOf(array, (double) 2.2, 0, (double) 0.35));
2046 assertEquals(3, ArrayUtils.indexOf(array, (double) 4.15, 0, (double) 2.0));
2047 assertEquals(1, ArrayUtils.indexOf(array, (double) 1.00001324, 0, (double) 0.0001));
2048 assertEquals(3, ArrayUtils.indexOf(array, (double) 4.15, -1, (double) 2.0));
2049 assertEquals(1, ArrayUtils.indexOf(array, (double) 1.00001324, -300, (double) 0.0001));
2050 }
2051
2052 @SuppressWarnings("cast")
2053 public void testLastIndexOfDouble() {
2054 double[] array = null;
2055 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 0));
2056 array = new double[0];
2057 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 0));
2058 array = new double[] { 0, 1, 2, 3, 0 };
2059 assertEquals(4, ArrayUtils.lastIndexOf(array, (double) 0));
2060 assertEquals(1, ArrayUtils.lastIndexOf(array, (double) 1));
2061 assertEquals(2, ArrayUtils.lastIndexOf(array, (double) 2));
2062 assertEquals(3, ArrayUtils.lastIndexOf(array, (double) 3));
2063 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 99));
2064 }
2065
2066 @SuppressWarnings("cast")
2067 public void testLastIndexOfDoubleTolerance() {
2068 double[] array = null;
2069 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 0, (double) 0));
2070 array = new double[0];
2071 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 0, (double) 0));
2072 array = new double[] { 0, 1, 2, 3, 0 };
2073 assertEquals(4, ArrayUtils.lastIndexOf(array, (double) 0, (double) 0.3));
2074 assertEquals(2, ArrayUtils.lastIndexOf(array, (double) 2.2, (double) 0.35));
2075 assertEquals(3, ArrayUtils.lastIndexOf(array, (double) 4.15, (double) 2.0));
2076 assertEquals(1, ArrayUtils.lastIndexOf(array, (double) 1.00001324, (double) 0.0001));
2077 }
2078
2079 @SuppressWarnings("cast")
2080 public void testLastIndexOfDoubleWithStartIndex() {
2081 double[] array = null;
2082 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 0, 2));
2083 array = new double[0];
2084 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 0, 2));
2085 array = new double[] { 0, 1, 2, 3, 0 };
2086 assertEquals(0, ArrayUtils.lastIndexOf(array, (double) 0, 2));
2087 assertEquals(1, ArrayUtils.lastIndexOf(array, (double) 1, 2));
2088 assertEquals(2, ArrayUtils.lastIndexOf(array, (double) 2, 2));
2089 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 3, 2));
2090 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 3, -1));
2091 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 99));
2092 assertEquals(4, ArrayUtils.lastIndexOf(array, (double) 0, 88));
2093 }
2094
2095 @SuppressWarnings("cast")
2096 public void testLastIndexOfDoubleWithStartIndexTolerance() {
2097 double[] array = null;
2098 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 0, 2, (double) 0));
2099 array = new double[0];
2100 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 0, 2, (double) 0));
2101 array = new double[] { (double) 3 };
2102 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 1, 0, (double) 0));
2103 array = new double[] { 0, 1, 2, 3, 0 };
2104 assertEquals(4, ArrayUtils.lastIndexOf(array, (double) 0, 99, (double) 0.3));
2105 assertEquals(0, ArrayUtils.lastIndexOf(array, (double) 0, 3, (double) 0.3));
2106 assertEquals(2, ArrayUtils.lastIndexOf(array, (double) 2.2, 3, (double) 0.35));
2107 assertEquals(3, ArrayUtils.lastIndexOf(array, (double) 4.15, array.length, (double) 2.0));
2108 assertEquals(1, ArrayUtils.lastIndexOf(array, (double) 1.00001324, array.length, (double) 0.0001));
2109 assertEquals(-1, ArrayUtils.lastIndexOf(array, (double) 4.15, -200, (double) 2.0));
2110 }
2111
2112 @SuppressWarnings("cast")
2113 public void testContainsDouble() {
2114 double[] array = null;
2115 assertEquals(false, ArrayUtils.contains(array, (double) 1));
2116 array = new double[] { 0, 1, 2, 3, 0 };
2117 assertEquals(true, ArrayUtils.contains(array, (double) 0));
2118 assertEquals(true, ArrayUtils.contains(array, (double) 1));
2119 assertEquals(true, ArrayUtils.contains(array, (double) 2));
2120 assertEquals(true, ArrayUtils.contains(array, (double) 3));
2121 assertEquals(false, ArrayUtils.contains(array, (double) 99));
2122 }
2123
2124 @SuppressWarnings("cast")
2125 public void testContainsDoubleTolerance() {
2126 double[] array = null;
2127 assertEquals(false, ArrayUtils.contains(array, (double) 1, (double) 0));
2128 array = new double[] { 0, 1, 2, 3, 0 };
2129 assertEquals(false, ArrayUtils.contains(array, (double) 4.0, (double) 0.33));
2130 assertEquals(false, ArrayUtils.contains(array, (double) 2.5, (double) 0.49));
2131 assertEquals(true, ArrayUtils.contains(array, (double) 2.5, (double) 0.50));
2132 assertEquals(true, ArrayUtils.contains(array, (double) 2.5, (double) 0.51));
2133 }
2134
2135 //-----------------------------------------------------------------------
2136 @SuppressWarnings("cast")
2137 public void testIndexOfFloat() {
2138 float[] array = null;
2139 assertEquals(-1, ArrayUtils.indexOf(array, (float) 0));
2140 array = new float[0];
2141 assertEquals(-1, ArrayUtils.indexOf(array, (float) 0));
2142 array = new float[] { 0, 1, 2, 3, 0 };
2143 assertEquals(0, ArrayUtils.indexOf(array, (float) 0));
2144 assertEquals(1, ArrayUtils.indexOf(array, (float) 1));
2145 assertEquals(2, ArrayUtils.indexOf(array, (float) 2));
2146 assertEquals(3, ArrayUtils.indexOf(array, (float) 3));
2147 assertEquals(-1, ArrayUtils.indexOf(array, (float) 99));
2148 }
2149
2150 @SuppressWarnings("cast")
2151 public void testIndexOfFloatWithStartIndex() {
2152 float[] array = null;
2153 assertEquals(-1, ArrayUtils.indexOf(array, (float) 0, 2));
2154 array = new float[0];
2155 assertEquals(-1, ArrayUtils.indexOf(array, (float) 0, 2));
2156 array = new float[] { 0, 1, 2, 3, 0 };
2157 assertEquals(4, ArrayUtils.indexOf(array, (float) 0, 2));
2158 assertEquals(-1, ArrayUtils.indexOf(array, (float) 1, 2));
2159 assertEquals(2, ArrayUtils.indexOf(array, (float) 2, 2));
2160 assertEquals(3, ArrayUtils.indexOf(array, (float) 3, 2));
2161 assertEquals(3, ArrayUtils.indexOf(array, (float) 3, -1));
2162 assertEquals(-1, ArrayUtils.indexOf(array, (float) 99, 0));
2163 assertEquals(-1, ArrayUtils.indexOf(array, (float) 0, 6));
2164 }
2165
2166 @SuppressWarnings("cast")
2167 public void testLastIndexOfFloat() {
2168 float[] array = null;
2169 assertEquals(-1, ArrayUtils.lastIndexOf(array, (float) 0));
2170 array = new float[0];
2171 assertEquals(-1, ArrayUtils.lastIndexOf(array, (float) 0));
2172 array = new float[] { 0, 1, 2, 3, 0 };
2173 assertEquals(4, ArrayUtils.lastIndexOf(array, (float) 0));
2174 assertEquals(1, ArrayUtils.lastIndexOf(array, (float) 1));
2175 assertEquals(2, ArrayUtils.lastIndexOf(array, (float) 2));
2176 assertEquals(3, ArrayUtils.lastIndexOf(array, (float) 3));
2177 assertEquals(-1, ArrayUtils.lastIndexOf(array, (float) 99));
2178 }
2179
2180 @SuppressWarnings("cast")
2181 public void testLastIndexOfFloatWithStartIndex() {
2182 float[] array = null;
2183 assertEquals(-1, ArrayUtils.lastIndexOf(array, (float) 0, 2));
2184 array = new float[0];
2185 assertEquals(-1, ArrayUtils.lastIndexOf(array, (float) 0, 2));
2186 array = new float[] { 0, 1, 2, 3, 0 };
2187 assertEquals(0, ArrayUtils.lastIndexOf(array, (float) 0, 2));
2188 assertEquals(1, ArrayUtils.lastIndexOf(array, (float) 1, 2));
2189 assertEquals(2, ArrayUtils.lastIndexOf(array, (float) 2, 2));
2190 assertEquals(-1, ArrayUtils.lastIndexOf(array, (float) 3, 2));
2191 assertEquals(-1, ArrayUtils.lastIndexOf(array, (float) 3, -1));
2192 assertEquals(-1, ArrayUtils.lastIndexOf(array, (float) 99));
2193 assertEquals(4, ArrayUtils.lastIndexOf(array, (float) 0, 88));
2194 }
2195
2196 @SuppressWarnings("cast")
2197 public void testContainsFloat() {
2198 float[] array = null;
2199 assertEquals(false, ArrayUtils.contains(array, (float) 1));
2200 array = new float[] { 0, 1, 2, 3, 0 };
2201 assertEquals(true, ArrayUtils.contains(array, (float) 0));
2202 assertEquals(true, ArrayUtils.contains(array, (float) 1));
2203 assertEquals(true, ArrayUtils.contains(array, (float) 2));
2204 assertEquals(true, ArrayUtils.contains(array, (float) 3));
2205 assertEquals(false, ArrayUtils.contains(array, (float) 99));
2206 }
2207
2208 //-----------------------------------------------------------------------
2209 public void testIndexOfBoolean() {
2210 boolean[] array = null;
2211 assertEquals(-1, ArrayUtils.indexOf(array, true));
2212 array = new boolean[0];
2213 assertEquals(-1, ArrayUtils.indexOf(array, true));
2214 array = new boolean[] { true, false, true };
2215 assertEquals(0, ArrayUtils.indexOf(array, true));
2216 assertEquals(1, ArrayUtils.indexOf(array, false));
2217 array = new boolean[] { true, true };
2218 assertEquals(-1, ArrayUtils.indexOf(array, false));
2219 }
2220
2221 public void testIndexOfBooleanWithStartIndex() {
2222 boolean[] array = null;
2223 assertEquals(-1, ArrayUtils.indexOf(array, true, 2));
2224 array = new boolean[0];
2225 assertEquals(-1, ArrayUtils.indexOf(array, true, 2));
2226 array = new boolean[] { true, false, true };
2227 assertEquals(2, ArrayUtils.indexOf(array, true, 1));
2228 assertEquals(-1, ArrayUtils.indexOf(array, false, 2));
2229 assertEquals(1, ArrayUtils.indexOf(array, false, 0));
2230 assertEquals(1, ArrayUtils.indexOf(array, false, -1));
2231 array = new boolean[] { true, true };
2232 assertEquals(-1, ArrayUtils.indexOf(array, false, 0));
2233 assertEquals(-1, ArrayUtils.indexOf(array, false, -1));
2234 }
2235
2236 public void testLastIndexOfBoolean() {
2237 boolean[] array = null;
2238 assertEquals(-1, ArrayUtils.lastIndexOf(array, true));
2239 array = new boolean[0];
2240 assertEquals(-1, ArrayUtils.lastIndexOf(array, true));
2241 array = new boolean[] { true, false, true };
2242 assertEquals(2, ArrayUtils.lastIndexOf(array, true));
2243 assertEquals(1, ArrayUtils.lastIndexOf(array, false));
2244 array = new boolean[] { true, true };
2245 assertEquals(-1, ArrayUtils.lastIndexOf(array, false));
2246 }
2247
2248 public void testLastIndexOfBooleanWithStartIndex() {
2249 boolean[] array = null;
2250 assertEquals(-1, ArrayUtils.lastIndexOf(array, true, 2));
2251 array = new boolean[0];
2252 assertEquals(-1, ArrayUtils.lastIndexOf(array, true, 2));
2253 array = new boolean[] { true, false, true };
2254 assertEquals(2, ArrayUtils.lastIndexOf(array, true, 2));
2255 assertEquals(0, ArrayUtils.lastIndexOf(array, true, 1));
2256 assertEquals(1, ArrayUtils.lastIndexOf(array, false, 2));
2257 assertEquals(-1, ArrayUtils.lastIndexOf(array, true, -1));
2258 array = new boolean[] { true, true };
2259 assertEquals(-1, ArrayUtils.lastIndexOf(array, false, 2));
2260 assertEquals(-1, ArrayUtils.lastIndexOf(array, true, -1));
2261 }
2262
2263 public void testContainsBoolean() {
2264 boolean[] array = null;
2265 assertEquals(false, ArrayUtils.contains(array, true));
2266 array = new boolean[] { true, false, true };
2267 assertEquals(true, ArrayUtils.contains(array, true));
2268 assertEquals(true, ArrayUtils.contains(array, false));
2269 array = new boolean[] { true, true };
2270 assertEquals(true, ArrayUtils.contains(array, true));
2271 assertEquals(false, ArrayUtils.contains(array, false));
2272 }
2273
2274 // testToPrimitive/Object for boolean
2275 // -----------------------------------------------------------------------
2276 public void testToPrimitive_boolean() {
2277 final Boolean[] b = null;
2278 assertEquals(null, ArrayUtils.toPrimitive(b));
2279 assertSame(ArrayUtils.EMPTY_BOOLEAN_ARRAY, ArrayUtils.toPrimitive(new Boolean[0]));
2280 assertTrue(Arrays.equals(
2281 new boolean[] {true, false, true},
2282 ArrayUtils.toPrimitive(new Boolean[] {Boolean.TRUE, Boolean.FALSE, Boolean.TRUE}))
2283 );
2284
2285 try {
2286 ArrayUtils.toPrimitive(new Boolean[] {Boolean.TRUE, null});
2287 fail();
2288 } catch (NullPointerException ex) {}
2289 }
2290
2291 public void testToPrimitive_boolean_boolean() {
2292 assertEquals(null, ArrayUtils.toPrimitive(null, false));
2293 assertSame(ArrayUtils.EMPTY_BOOLEAN_ARRAY, ArrayUtils.toPrimitive(new Boolean[0], false));
2294 assertTrue(Arrays.equals(
2295 new boolean[] {true, false, true},
2296 ArrayUtils.toPrimitive(new Boolean[] {Boolean.TRUE, Boolean.FALSE, Boolean.TRUE}, false))
2297 );
2298 assertTrue(Arrays.equals(
2299 new boolean[] {true, false, false},
2300 ArrayUtils.toPrimitive(new Boolean[] {Boolean.TRUE, null, Boolean.FALSE}, false))
2301 );
2302 assertTrue(Arrays.equals(
2303 new boolean[] {true, true, false},
2304 ArrayUtils.toPrimitive(new Boolean[] {Boolean.TRUE, null, Boolean.FALSE}, true))
2305 );
2306 }
2307
2308 public void testToObject_boolean() {
2309 final boolean[] b = null;
2310 assertEquals(null, ArrayUtils.toObject(b));
2311 assertSame(ArrayUtils.EMPTY_BOOLEAN_OBJECT_ARRAY, ArrayUtils.toObject(new boolean[0]));
2312 assertTrue(Arrays.equals(
2313 new Boolean[] {Boolean.TRUE, Boolean.FALSE, Boolean.TRUE},
2314 ArrayUtils.toObject(new boolean[] {true, false, true}))
2315 );
2316 }
2317
2318 // testToPrimitive/Object for byte
2319 // -----------------------------------------------------------------------
2320 public void testToPrimitive_char() {
2321 final Character[] b = null;
2322 assertEquals(null, ArrayUtils.toPrimitive(b));
2323
2324 assertSame(ArrayUtils.EMPTY_CHAR_ARRAY, ArrayUtils.toPrimitive(new Character[0]));
2325
2326 assertTrue(Arrays.equals(
2327 new char[] {Character.MIN_VALUE, Character.MAX_VALUE, '0'},
2328 ArrayUtils.toPrimitive(new Character[] {new Character(Character.MIN_VALUE),
2329 new Character(Character.MAX_VALUE), new Character('0')}))
2330 );
2331
2332 try {
2333 ArrayUtils.toPrimitive(new Character[] {new Character(Character.MIN_VALUE), null});
2334 fail();
2335 } catch (NullPointerException ex) {}
2336 }
2337
2338 public void testToPrimitive_char_char() {
2339 final Character[] b = null;
2340 assertEquals(null, ArrayUtils.toPrimitive(b, Character.MIN_VALUE));
2341
2342 assertSame(ArrayUtils.EMPTY_CHAR_ARRAY,
2343 ArrayUtils.toPrimitive(new Character[0], (char)0));
2344
2345 assertTrue(Arrays.equals(
2346 new char[] {Character.MIN_VALUE, Character.MAX_VALUE, '0'},
2347 ArrayUtils.toPrimitive(new Character[] {new Character(Character.MIN_VALUE),
2348 new Character(Character.MAX_VALUE), new Character('0')},
2349 Character.MIN_VALUE))
2350 );
2351
2352 assertTrue(Arrays.equals(
2353 new char[] {Character.MIN_VALUE, Character.MAX_VALUE, '0'},
2354 ArrayUtils.toPrimitive(new Character[] {new Character(Character.MIN_VALUE), null,
2355 new Character('0')}, Character.MAX_VALUE))
2356 );
2357 }
2358
2359 public void testToObject_char() {
2360 final char[] b = null;
2361 assertEquals(null, ArrayUtils.toObject(b));
2362
2363 assertSame(ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY,
2364 ArrayUtils.toObject(new char[0]));
2365
2366 assertTrue(Arrays.equals(
2367 new Character[] {new Character(Character.MIN_VALUE),
2368 new Character(Character.MAX_VALUE), new Character('0')},
2369 ArrayUtils.toObject(new char[] {Character.MIN_VALUE, Character.MAX_VALUE,
2370 '0'} ))
2371 );
2372 }
2373
2374 // testToPrimitive/Object for byte
2375 // -----------------------------------------------------------------------
2376 public void testToPrimitive_byte() {
2377 final Byte[] b = null;
2378 assertEquals(null, ArrayUtils.toPrimitive(b));
2379
2380 assertSame(ArrayUtils.EMPTY_BYTE_ARRAY, ArrayUtils.toPrimitive(new Byte[0]));
2381
2382 assertTrue(Arrays.equals(
2383 new byte[] {Byte.MIN_VALUE, Byte.MAX_VALUE, (byte)9999999},
2384 ArrayUtils.toPrimitive(new Byte[] {Byte.valueOf(Byte.MIN_VALUE),
2385 Byte.valueOf(Byte.MAX_VALUE), Byte.valueOf((byte)9999999)}))
2386 );
2387
2388 try {
2389 ArrayUtils.toPrimitive(new Byte[] {Byte.valueOf(Byte.MIN_VALUE), null});
2390 fail();
2391 } catch (NullPointerException ex) {}
2392 }
2393
2394 public void testToPrimitive_byte_byte() {
2395 final Byte[] b = null;
2396 assertEquals(null, ArrayUtils.toPrimitive(b, Byte.MIN_VALUE));
2397
2398 assertSame(ArrayUtils.EMPTY_BYTE_ARRAY,
2399 ArrayUtils.toPrimitive(new Byte[0], (byte)1));
2400
2401 assertTrue(Arrays.equals(
2402 new byte[] {Byte.MIN_VALUE, Byte.MAX_VALUE, (byte)9999999},
2403 ArrayUtils.toPrimitive(new Byte[] {Byte.valueOf(Byte.MIN_VALUE),
2404 Byte.valueOf(Byte.MAX_VALUE), Byte.valueOf((byte)9999999)},
2405 Byte.MIN_VALUE))
2406 );
2407
2408 assertTrue(Arrays.equals(
2409 new byte[] {Byte.MIN_VALUE, Byte.MAX_VALUE, (byte)9999999},
2410 ArrayUtils.toPrimitive(new Byte[] {Byte.valueOf(Byte.MIN_VALUE), null,
2411 Byte.valueOf((byte)9999999)}, Byte.MAX_VALUE))
2412 );
2413 }
2414
2415 public void testToObject_byte() {
2416 final byte[] b = null;
2417 assertEquals(null, ArrayUtils.toObject(b));
2418
2419 assertSame(ArrayUtils.EMPTY_BYTE_OBJECT_ARRAY,
2420 ArrayUtils.toObject(new byte[0]));
2421
2422 assertTrue(Arrays.equals(
2423 new Byte[] {Byte.valueOf(Byte.MIN_VALUE),
2424 Byte.valueOf(Byte.MAX_VALUE), Byte.valueOf((byte)9999999)},
2425 ArrayUtils.toObject(new byte[] {Byte.MIN_VALUE, Byte.MAX_VALUE,
2426 (byte)9999999}))
2427 );
2428 }
2429
2430 // testToPrimitive/Object for short
2431 // -----------------------------------------------------------------------
2432 public void testToPrimitive_short() {
2433 final Short[] b = null;
2434 assertEquals(null, ArrayUtils.toPrimitive(b));
2435
2436 assertSame(ArrayUtils.EMPTY_SHORT_ARRAY, ArrayUtils.toPrimitive(new Short[0]));
2437
2438 assertTrue(Arrays.equals(
2439 new short[] {Short.MIN_VALUE, Short.MAX_VALUE, (short)9999999},
2440 ArrayUtils.toPrimitive(new Short[] {Short.valueOf(Short.MIN_VALUE),
2441 Short.valueOf(Short.MAX_VALUE), Short.valueOf((short)9999999)}))
2442 );
2443
2444 try {
2445 ArrayUtils.toPrimitive(new Short[] {Short.valueOf(Short.MIN_VALUE), null});
2446 fail();
2447 } catch (NullPointerException ex) {}
2448 }
2449
2450 public void testToPrimitive_short_short() {
2451 final Short[] s = null;
2452 assertEquals(null, ArrayUtils.toPrimitive(s, Short.MIN_VALUE));
2453
2454 assertSame(ArrayUtils.EMPTY_SHORT_ARRAY, ArrayUtils.toPrimitive(new Short[0],
2455 Short.MIN_VALUE));
2456
2457 assertTrue(Arrays.equals(
2458 new short[] {Short.MIN_VALUE, Short.MAX_VALUE, (short)9999999},
2459 ArrayUtils.toPrimitive(new Short[] {Short.valueOf(Short.MIN_VALUE),
2460 Short.valueOf(Short.MAX_VALUE), Short.valueOf((short)9999999)}, Short.MIN_VALUE))
2461 );
2462
2463 assertTrue(Arrays.equals(
2464 new short[] {Short.MIN_VALUE, Short.MAX_VALUE, (short)9999999},
2465 ArrayUtils.toPrimitive(new Short[] {Short.valueOf(Short.MIN_VALUE), null,
2466 Short.valueOf((short)9999999)}, Short.MAX_VALUE))
2467 );
2468 }
2469
2470 public void testToObject_short() {
2471 final short[] b = null;
2472 assertEquals(null, ArrayUtils.toObject(b));
2473
2474 assertSame(ArrayUtils.EMPTY_SHORT_OBJECT_ARRAY,
2475 ArrayUtils.toObject(new short[0]));
2476
2477 assertTrue(Arrays.equals(
2478 new Short[] {Short.valueOf(Short.MIN_VALUE), Short.valueOf(Short.MAX_VALUE),
2479 Short.valueOf((short)9999999)},
2480 ArrayUtils.toObject(new short[] {Short.MIN_VALUE, Short.MAX_VALUE,
2481 (short)9999999}))
2482 );
2483 }
2484
2485 // testToPrimitive/Object for int
2486 // -----------------------------------------------------------------------
2487 public void testToPrimitive_int() {
2488 final Integer[] b = null;
2489 assertEquals(null, ArrayUtils.toPrimitive(b));
2490 assertSame(ArrayUtils.EMPTY_INT_ARRAY, ArrayUtils.toPrimitive(new Integer[0]));
2491 assertTrue(Arrays.equals(
2492 new int[] {Integer.MIN_VALUE, Integer.MAX_VALUE, 9999999},
2493 ArrayUtils.toPrimitive(new Integer[] {Integer.valueOf(Integer.MIN_VALUE),
2494 Integer.valueOf(Integer.MAX_VALUE), Integer.valueOf(9999999)}))
2495 );
2496
2497 try {
2498 ArrayUtils.toPrimitive(new Integer[] {Integer.valueOf(Integer.MIN_VALUE), null});
2499 fail();
2500 } catch (NullPointerException ex) {}
2501 }
2502
2503 public void testToPrimitive_int_int() {
2504 final Long[] l = null;
2505 assertEquals(null, ArrayUtils.toPrimitive(l, Integer.MIN_VALUE));
2506 assertSame(ArrayUtils.EMPTY_INT_ARRAY,
2507 ArrayUtils.toPrimitive(new Integer[0], 1));
2508 assertTrue(Arrays.equals(
2509 new int[] {Integer.MIN_VALUE, Integer.MAX_VALUE, 9999999},
2510 ArrayUtils.toPrimitive(new Integer[] {Integer.valueOf(Integer.MIN_VALUE),
2511 Integer.valueOf(Integer.MAX_VALUE), Integer.valueOf(9999999)},1)));
2512 assertTrue(Arrays.equals(
2513 new int[] {Integer.MIN_VALUE, Integer.MAX_VALUE, 9999999},
2514 ArrayUtils.toPrimitive(new Integer[] {Integer.valueOf(Integer.MIN_VALUE),
2515 null, Integer.valueOf(9999999)}, Integer.MAX_VALUE))
2516 );
2517 }
2518
2519 public void testToPrimitive_intNull() {
2520 Integer[] iArray = null;
2521 assertEquals(null, ArrayUtils.toPrimitive(iArray, Integer.MIN_VALUE));
2522 }
2523
2524 public void testToObject_int() {
2525 final int[] b = null;
2526 assertEquals(null, ArrayUtils.toObject(b));
2527
2528 assertSame(
2529 ArrayUtils.EMPTY_INTEGER_OBJECT_ARRAY,
2530 ArrayUtils.toObject(new int[0]));
2531
2532 assertTrue(
2533 Arrays.equals(
2534 new Integer[] {
2535 Integer.valueOf(Integer.MIN_VALUE),
2536 Integer.valueOf(Integer.MAX_VALUE),
2537 Integer.valueOf(9999999)},
2538 ArrayUtils.toObject(
2539 new int[] { Integer.MIN_VALUE, Integer.MAX_VALUE, 9999999 })));
2540 }
2541
2542 // testToPrimitive/Object for long
2543 // -----------------------------------------------------------------------
2544 public void testToPrimitive_long() {
2545 final Long[] b = null;
2546 assertEquals(null, ArrayUtils.toPrimitive(b));
2547
2548 assertSame(ArrayUtils.EMPTY_LONG_ARRAY,
2549 ArrayUtils.toPrimitive(new Long[0]));
2550
2551 assertTrue(Arrays.equals(
2552 new long[] {Long.MIN_VALUE, Long.MAX_VALUE, 9999999},
2553 ArrayUtils.toPrimitive(new Long[] {Long.valueOf(Long.MIN_VALUE),
2554 Long.valueOf(Long.MAX_VALUE), Long.valueOf(9999999)}))
2555 );
2556
2557 try {
2558 ArrayUtils.toPrimitive(new Long[] {Long.valueOf(Long.MIN_VALUE), null});
2559 fail();
2560 } catch (NullPointerException ex) {}
2561 }
2562
2563 public void testToPrimitive_long_long() {
2564 final Long[] l = null;
2565 assertEquals(null, ArrayUtils.toPrimitive(l, Long.MIN_VALUE));
2566
2567 assertSame(ArrayUtils.EMPTY_LONG_ARRAY,
2568 ArrayUtils.toPrimitive(new Long[0], 1));
2569
2570 assertTrue(Arrays.equals(
2571 new long[] {Long.MIN_VALUE, Long.MAX_VALUE, 9999999},
2572 ArrayUtils.toPrimitive(new Long[] {Long.valueOf(Long.MIN_VALUE),
2573 Long.valueOf(Long.MAX_VALUE), Long.valueOf(9999999)},1)));
2574
2575 assertTrue(Arrays.equals(
2576 new long[] {Long.MIN_VALUE, Long.MAX_VALUE, 9999999},
2577 ArrayUtils.toPrimitive(new Long[] {Long.valueOf(Long.MIN_VALUE),
2578 null, Long.valueOf(9999999)}, Long.MAX_VALUE))
2579 );
2580 }
2581
2582 public void testToObject_long() {
2583 final long[] b = null;
2584 assertEquals(null, ArrayUtils.toObject(b));
2585
2586 assertSame(
2587 ArrayUtils.EMPTY_LONG_OBJECT_ARRAY,
2588 ArrayUtils.toObject(new long[0]));
2589
2590 assertTrue(
2591 Arrays.equals(
2592 new Long[] {
2593 Long.valueOf(Long.MIN_VALUE),
2594 Long.valueOf(Long.MAX_VALUE),
2595 Long.valueOf(9999999)},
2596 ArrayUtils.toObject(
2597 new long[] { Long.MIN_VALUE, Long.MAX_VALUE, 9999999 })));
2598 }
2599
2600 // testToPrimitive/Object for float
2601 // -----------------------------------------------------------------------
2602 public void testToPrimitive_float() {
2603 final Float[] b = null;
2604 assertEquals(null, ArrayUtils.toPrimitive(b));
2605
2606 assertSame(ArrayUtils.EMPTY_FLOAT_ARRAY,
2607 ArrayUtils.toPrimitive(new Float[0]));
2608
2609 assertTrue(Arrays.equals(
2610 new float[] {Float.MIN_VALUE, Float.MAX_VALUE, 9999999},
2611 ArrayUtils.toPrimitive(new Float[] {Float.valueOf(Float.MIN_VALUE),
2612 Float.valueOf(Float.MAX_VALUE), Float.valueOf(9999999)}))
2613 );
2614
2615 try {
2616 ArrayUtils.toPrimitive(new Float[] {Float.valueOf(Float.MIN_VALUE), null});
2617 fail();
2618 } catch (NullPointerException ex) {}
2619 }
2620
2621 public void testToPrimitive_float_float() {
2622 final Float[] l = null;
2623 assertEquals(null, ArrayUtils.toPrimitive(l, Float.MIN_VALUE));
2624
2625 assertSame(ArrayUtils.EMPTY_FLOAT_ARRAY,
2626 ArrayUtils.toPrimitive(new Float[0], 1));
2627
2628 assertTrue(Arrays.equals(
2629 new float[] {Float.MIN_VALUE, Float.MAX_VALUE, 9999999},
2630 ArrayUtils.toPrimitive(new Float[] {Float.valueOf(Float.MIN_VALUE),
2631 Float.valueOf(Float.MAX_VALUE), Float.valueOf(9999999)},1)));
2632
2633 assertTrue(Arrays.equals(
2634 new float[] {Float.MIN_VALUE, Float.MAX_VALUE, 9999999},
2635 ArrayUtils.toPrimitive(new Float[] {Float.valueOf(Float.MIN_VALUE),
2636 null, Float.valueOf(9999999)}, Float.MAX_VALUE))
2637 );
2638 }
2639
2640 public void testToObject_float() {
2641 final float[] b = null;
2642 assertEquals(null, ArrayUtils.toObject(b));
2643
2644 assertSame(
2645 ArrayUtils.EMPTY_FLOAT_OBJECT_ARRAY,
2646 ArrayUtils.toObject(new float[0]));
2647
2648 assertTrue(
2649 Arrays.equals(
2650 new Float[] {
2651 Float.valueOf(Float.MIN_VALUE),
2652 Float.valueOf(Float.MAX_VALUE),
2653 Float.valueOf(9999999)},
2654 ArrayUtils.toObject(
2655 new float[] { Float.MIN_VALUE, Float.MAX_VALUE, 9999999 })));
2656 }
2657
2658 // testToPrimitive/Object for double
2659 // -----------------------------------------------------------------------
2660 public void testToPrimitive_double() {
2661 final Double[] b = null;
2662 assertEquals(null, ArrayUtils.toPrimitive(b));
2663
2664 assertSame(ArrayUtils.EMPTY_DOUBLE_ARRAY,
2665 ArrayUtils.toPrimitive(new Double[0]));
2666
2667 assertTrue(Arrays.equals(
2668 new double[] {Double.MIN_VALUE, Double.MAX_VALUE, 9999999},
2669 ArrayUtils.toPrimitive(new Double[] {Double.valueOf(Double.MIN_VALUE),
2670 Double.valueOf(Double.MAX_VALUE), Double.valueOf(9999999)}))
2671 );
2672
2673 try {
2674 ArrayUtils.toPrimitive(new Float[] {Float.valueOf(Float.MIN_VALUE), null});
2675 fail();
2676 } catch (NullPointerException ex) {}
2677 }
2678
2679 public void testToPrimitive_double_double() {
2680 final Double[] l = null;
2681 assertEquals(null, ArrayUtils.toPrimitive(l, Double.MIN_VALUE));
2682
2683 assertSame(ArrayUtils.EMPTY_DOUBLE_ARRAY,
2684 ArrayUtils.toPrimitive(new Double[0], 1));
2685
2686 assertTrue(Arrays.equals(
2687 new double[] {Double.MIN_VALUE, Double.MAX_VALUE, 9999999},
2688 ArrayUtils.toPrimitive(new Double[] {Double.valueOf(Double.MIN_VALUE),
2689 Double.valueOf(Double.MAX_VALUE), Double.valueOf(9999999)},1)));
2690
2691 assertTrue(Arrays.equals(
2692 new double[] {Double.MIN_VALUE, Double.MAX_VALUE, 9999999},
2693 ArrayUtils.toPrimitive(new Double[] {Double.valueOf(Double.MIN_VALUE),
2694 null, Double.valueOf(9999999)}, Double.MAX_VALUE))
2695 );
2696 }
2697
2698 public void testToObject_double() {
2699 final double[] b = null;
2700 assertEquals(null, ArrayUtils.toObject(b));
2701
2702 assertSame(
2703 ArrayUtils.EMPTY_DOUBLE_OBJECT_ARRAY,
2704 ArrayUtils.toObject(new double[0]));
2705
2706 assertTrue(
2707 Arrays.equals(
2708 new Double[] {
2709 Double.valueOf(Double.MIN_VALUE),
2710 Double.valueOf(Double.MAX_VALUE),
2711 Double.valueOf(9999999)},
2712 ArrayUtils.toObject(
2713 new double[] { Double.MIN_VALUE, Double.MAX_VALUE, 9999999 })));
2714 }
2715
2716 //-----------------------------------------------------------------------
2717 /**
2718 * Test for {@link ArrayUtils#isEmpty(java.lang.Object[])}.
2719 */
2720 public void testIsEmptyObject() {
2721 Object[] emptyArray = new Object[] {};
2722 Object[] notEmptyArray = new Object[] { new String("Value") };
2723 assertEquals(true, ArrayUtils.isEmpty((Object[])null));
2724 assertEquals(true, ArrayUtils.isEmpty(emptyArray));
2725 assertEquals(false, ArrayUtils.isEmpty(notEmptyArray));
2726 }
2727
2728 /**
2729 * Tests for {@link ArrayUtils#isEmpty(long[])},
2730 * {@link ArrayUtils#isEmpty(int[])},
2731 * {@link ArrayUtils#isEmpty(short[])},
2732 * {@link ArrayUtils#isEmpty(char[])},
2733 * {@link ArrayUtils#isEmpty(byte[])},
2734 * {@link ArrayUtils#isEmpty(double[])},
2735 * {@link ArrayUtils#isEmpty(float[])} and
2736 * {@link ArrayUtils#isEmpty(boolean[])}.
2737 */
2738 public void testIsEmptyPrimitives() {
2739 long[] emptyLongArray = new long[] {};
2740 long[] notEmptyLongArray = new long[] { 1L };
2741 assertEquals(true, ArrayUtils.isEmpty((long[])null));
2742 assertEquals(true, ArrayUtils.isEmpty(emptyLongArray));
2743 assertEquals(false, ArrayUtils.isEmpty(notEmptyLongArray));
2744
2745 int[] emptyIntArray = new int[] {};
2746 int[] notEmptyIntArray = new int[] { 1 };
2747 assertEquals(true, ArrayUtils.isEmpty((int[])null));
2748 assertEquals(true, ArrayUtils.isEmpty(emptyIntArray));
2749 assertEquals(false, ArrayUtils.isEmpty(notEmptyIntArray));
2750
2751 short[] emptyShortArray = new short[] {};
2752 short[] notEmptyShortArray = new short[] { 1 };
2753 assertEquals(true, ArrayUtils.isEmpty((short[])null));
2754 assertEquals(true, ArrayUtils.isEmpty(emptyShortArray));
2755 assertEquals(false, ArrayUtils.isEmpty(notEmptyShortArray));
2756
2757 char[] emptyCharArray = new char[] {};
2758 char[] notEmptyCharArray = new char[] { 1 };
2759 assertEquals(true, ArrayUtils.isEmpty((char[])null));
2760 assertEquals(true, ArrayUtils.isEmpty(emptyCharArray));
2761 assertEquals(false, ArrayUtils.isEmpty(notEmptyCharArray));
2762
2763 byte[] emptyByteArray = new byte[] {};
2764 byte[] notEmptyByteArray = new byte[] { 1 };
2765 assertEquals(true, ArrayUtils.isEmpty((byte[])null));
2766 assertEquals(true, ArrayUtils.isEmpty(emptyByteArray));
2767 assertEquals(false, ArrayUtils.isEmpty(notEmptyByteArray));
2768
2769 double[] emptyDoubleArray = new double[] {};
2770 double[] notEmptyDoubleArray = new double[] { 1.0 };
2771 assertEquals(true, ArrayUtils.isEmpty((double[])null));
2772 assertEquals(true, ArrayUtils.isEmpty(emptyDoubleArray));
2773 assertEquals(false, ArrayUtils.isEmpty(notEmptyDoubleArray));
2774
2775 float[] emptyFloatArray = new float[] {};
2776 float[] notEmptyFloatArray = new float[] { 1.0F };
2777 assertEquals(true, ArrayUtils.isEmpty((float[])null));
2778 assertEquals(true, ArrayUtils.isEmpty(emptyFloatArray));
2779 assertEquals(false, ArrayUtils.isEmpty(notEmptyFloatArray));
2780
2781 boolean[] emptyBooleanArray = new boolean[] {};
2782 boolean[] notEmptyBooleanArray = new boolean[] { true };
2783 assertEquals(true, ArrayUtils.isEmpty((boolean[])null));
2784 assertEquals(true, ArrayUtils.isEmpty(emptyBooleanArray));
2785 assertEquals(false, ArrayUtils.isEmpty(notEmptyBooleanArray));
2786 }
2787
2788 /**
2789 * Test for {@link ArrayUtils#isNotEmpty(java.lang.Object[])}.
2790 */
2791 public void testIsNotEmptyObject() {
2792 Object[] emptyArray = new Object[] {};
2793 Object[] notEmptyArray = new Object[] { new String("Value") };
2794 assertFalse(ArrayUtils.isNotEmpty((Object[])null));
2795 assertFalse(ArrayUtils.isNotEmpty(emptyArray));
2796 assertTrue(ArrayUtils.isNotEmpty(notEmptyArray));
2797 }
2798
2799 /**
2800 * Tests for {@link ArrayUtils#isNotEmpty(long[])},
2801 * {@link ArrayUtils#isNotEmpty(int[])},
2802 * {@link ArrayUtils#isNotEmpty(short[])},
2803 * {@link ArrayUtils#isNotEmpty(char[])},
2804 * {@link ArrayUtils#isNotEmpty(byte[])},
2805 * {@link ArrayUtils#isNotEmpty(double[])},
2806 * {@link ArrayUtils#isNotEmpty(float[])} and
2807 * {@link ArrayUtils#isNotEmpty(boolean[])}.
2808 */
2809 public void testIsNotEmptyPrimitives() {
2810 long[] emptyLongArray = new long[] {};
2811 long[] notEmptyLongArray = new long[] { 1L };
2812 assertFalse(ArrayUtils.isNotEmpty((long[])null));
2813 assertFalse(ArrayUtils.isNotEmpty(emptyLongArray));
2814 assertTrue(ArrayUtils.isNotEmpty(notEmptyLongArray));
2815
2816 int[] emptyIntArray = new int[] {};
2817 int[] notEmptyIntArray = new int[] { 1 };
2818 assertFalse(ArrayUtils.isNotEmpty((int[])null));
2819 assertFalse(ArrayUtils.isNotEmpty(emptyIntArray));
2820 assertTrue(ArrayUtils.isNotEmpty(notEmptyIntArray));
2821
2822 short[] emptyShortArray = new short[] {};
2823 short[] notEmptyShortArray = new short[] { 1 };
2824 assertFalse(ArrayUtils.isNotEmpty((short[])null));
2825 assertFalse(ArrayUtils.isNotEmpty(emptyShortArray));
2826 assertTrue(ArrayUtils.isNotEmpty(notEmptyShortArray));
2827
2828 char[] emptyCharArray = new char[] {};
2829 char[] notEmptyCharArray = new char[] { 1 };
2830 assertFalse(ArrayUtils.isNotEmpty((char[])null));
2831 assertFalse(ArrayUtils.isNotEmpty(emptyCharArray));
2832 assertTrue(ArrayUtils.isNotEmpty(notEmptyCharArray));
2833
2834 byte[] emptyByteArray = new byte[] {};
2835 byte[] notEmptyByteArray = new byte[] { 1 };
2836 assertFalse(ArrayUtils.isNotEmpty((byte[])null));
2837 assertFalse(ArrayUtils.isNotEmpty(emptyByteArray));
2838 assertTrue(ArrayUtils.isNotEmpty(notEmptyByteArray));
2839
2840 double[] emptyDoubleArray = new double[] {};
2841 double[] notEmptyDoubleArray = new double[] { 1.0 };
2842 assertFalse(ArrayUtils.isNotEmpty((double[])null));
2843 assertFalse(ArrayUtils.isNotEmpty(emptyDoubleArray));
2844 assertTrue(ArrayUtils.isNotEmpty(notEmptyDoubleArray));
2845
2846 float[] emptyFloatArray = new float[] {};
2847 float[] notEmptyFloatArray = new float[] { 1.0F };
2848 assertFalse(ArrayUtils.isNotEmpty((float[])null));
2849 assertFalse(ArrayUtils.isNotEmpty(emptyFloatArray));
2850 assertTrue(ArrayUtils.isNotEmpty(notEmptyFloatArray));
2851
2852 boolean[] emptyBooleanArray = new boolean[] {};
2853 boolean[] notEmptyBooleanArray = new boolean[] { true };
2854 assertFalse(ArrayUtils.isNotEmpty((boolean[])null));
2855 assertFalse(ArrayUtils.isNotEmpty(emptyBooleanArray));
2856 assertTrue(ArrayUtils.isNotEmpty(notEmptyBooleanArray));
2857 }
2858 // ------------------------------------------------------------------------
2859 public void testGetLength() {
2860 assertEquals(0, ArrayUtils.getLength(null));
2861
2862 Object[] emptyObjectArray = new Object[0];
2863 Object[] notEmptyObjectArray = new Object[] {"aValue"};
2864 assertEquals(0, ArrayUtils.getLength((Object[]) null));
2865 assertEquals(0, ArrayUtils.getLength(emptyObjectArray));
2866 assertEquals(1, ArrayUtils.getLength(notEmptyObjectArray));
2867
2868 int[] emptyIntArray = new int[] {};
2869 int[] notEmptyIntArray = new int[] { 1 };
2870 assertEquals(0, ArrayUtils.getLength((int[]) null));
2871 assertEquals(0, ArrayUtils.getLength(emptyIntArray));
2872 assertEquals(1, ArrayUtils.getLength(notEmptyIntArray));
2873
2874 short[] emptyShortArray = new short[] {};
2875 short[] notEmptyShortArray = new short[] { 1 };
2876 assertEquals(0, ArrayUtils.getLength((short[]) null));
2877 assertEquals(0, ArrayUtils.getLength(emptyShortArray));
2878 assertEquals(1, ArrayUtils.getLength(notEmptyShortArray));
2879
2880 char[] emptyCharArray = new char[] {};
2881 char[] notEmptyCharArray = new char[] { 1 };
2882 assertEquals(0, ArrayUtils.getLength((char[]) null));
2883 assertEquals(0, ArrayUtils.getLength(emptyCharArray));
2884 assertEquals(1, ArrayUtils.getLength(notEmptyCharArray));
2885
2886 byte[] emptyByteArray = new byte[] {};
2887 byte[] notEmptyByteArray = new byte[] { 1 };
2888 assertEquals(0, ArrayUtils.getLength((byte[]) null));
2889 assertEquals(0, ArrayUtils.getLength(emptyByteArray));
2890 assertEquals(1, ArrayUtils.getLength(notEmptyByteArray));
2891
2892 double[] emptyDoubleArray = new double[] {};
2893 double[] notEmptyDoubleArray = new double[] { 1.0 };
2894 assertEquals(0, ArrayUtils.getLength((double[]) null));
2895 assertEquals(0, ArrayUtils.getLength(emptyDoubleArray));
2896 assertEquals(1, ArrayUtils.getLength(notEmptyDoubleArray));
2897
2898 float[] emptyFloatArray = new float[] {};
2899 float[] notEmptyFloatArray = new float[] { 1.0F };
2900 assertEquals(0, ArrayUtils.getLength((float[]) null));
2901 assertEquals(0, ArrayUtils.getLength(emptyFloatArray));
2902 assertEquals(1, ArrayUtils.getLength(notEmptyFloatArray));
2903
2904 boolean[] emptyBooleanArray = new boolean[] {};
2905 boolean[] notEmptyBooleanArray = new boolean[] { true };
2906 assertEquals(0, ArrayUtils.getLength((boolean[]) null));
2907 assertEquals(0, ArrayUtils.getLength(emptyBooleanArray));
2908 assertEquals(1, ArrayUtils.getLength(notEmptyBooleanArray));
2909
2910 try {
2911 ArrayUtils.getLength("notAnArray");
2912 fail("IllegalArgumentException should have been thrown");
2913 } catch (IllegalArgumentException e) {}
2914 }
2915
2916 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import junit.framework.TestCase;
19
20 /**
21 * Class to test BitField functionality
22 *
23 * @version $Id: BitFieldTest.java 1088899 2011-04-05 05:31:27Z bayard $
24 */
25 public class BitFieldTest extends TestCase {
26
27 private static final BitField bf_multi = new BitField(0x3F80);
28 private static final BitField bf_single = new BitField(0x4000);
29 private static final BitField bf_zero = new BitField(0);
30
31 /**
32 * Constructor BitFieldTest
33 *
34 * @param name
35 */
36 public BitFieldTest(String name) {
37 super(name);
38 }
39
40 /**
41 * test the getValue() method
42 */
43 public void testGetValue() {
44 assertEquals(bf_multi.getValue(-1), 127);
45 assertEquals(bf_multi.getValue(0), 0);
46 assertEquals(bf_single.getValue(-1), 1);
47 assertEquals(bf_single.getValue(0), 0);
48 assertEquals(bf_zero.getValue(-1), 0);
49 assertEquals(bf_zero.getValue(0), 0);
50 }
51
52 /**
53 * test the getShortValue() method
54 */
55 public void testGetShortValue() {
56 assertEquals(bf_multi.getShortValue((short) - 1), (short) 127);
57 assertEquals(bf_multi.getShortValue((short) 0), (short) 0);
58 assertEquals(bf_single.getShortValue((short) - 1), (short) 1);
59 assertEquals(bf_single.getShortValue((short) 0), (short) 0);
60 assertEquals(bf_zero.getShortValue((short) -1), (short) 0);
61 assertEquals(bf_zero.getShortValue((short) 0), (short) 0);
62 }
63
64 /**
65 * test the getRawValue() method
66 */
67 public void testGetRawValue() {
68 assertEquals(bf_multi.getRawValue(-1), 0x3F80);
69 assertEquals(bf_multi.getRawValue(0), 0);
70 assertEquals(bf_single.getRawValue(-1), 0x4000);
71 assertEquals(bf_single.getRawValue(0), 0);
72 assertEquals(bf_zero.getRawValue(-1), 0);
73 assertEquals(bf_zero.getRawValue(0), 0);
74 }
75
76 /**
77 * test the getShortRawValue() method
78 */
79 public void testGetShortRawValue() {
80 assertEquals(bf_multi.getShortRawValue((short) - 1), (short) 0x3F80);
81 assertEquals(bf_multi.getShortRawValue((short) 0), (short) 0);
82 assertEquals(bf_single.getShortRawValue((short) - 1), (short) 0x4000);
83 assertEquals(bf_single.getShortRawValue((short) 0), (short) 0);
84 assertEquals(bf_zero.getShortRawValue((short) -1), (short) 0);
85 assertEquals(bf_zero.getShortRawValue((short) 0), (short) 0);
86 }
87
88 /**
89 * test the isSet() method
90 */
91 public void testIsSet() {
92 assertTrue(!bf_multi.isSet(0));
93 assertTrue(!bf_zero.isSet(0));
94 for (int j = 0x80; j <= 0x3F80; j += 0x80) {
95 assertTrue(bf_multi.isSet(j));
96 }
97 for (int j = 0x80; j <= 0x3F80; j += 0x80) {
98 assertTrue(!bf_zero.isSet(j));
99 }
100 assertTrue(!bf_single.isSet(0));
101 assertTrue(bf_single.isSet(0x4000));
102 }
103
104 /**
105 * test the isAllSet() method
106 */
107 public void testIsAllSet() {
108 for (int j = 0; j < 0x3F80; j += 0x80) {
109 assertTrue(!bf_multi.isAllSet(j));
110 assertTrue(bf_zero.isAllSet(j));
111 }
112 assertTrue(bf_multi.isAllSet(0x3F80));
113 assertTrue(!bf_single.isAllSet(0));
114 assertTrue(bf_single.isAllSet(0x4000));
115 }
116
117 /**
118 * test the setValue() method
119 */
120 public void testSetValue() {
121 for (int j = 0; j < 128; j++) {
122 assertEquals(bf_multi.getValue(bf_multi.setValue(0, j)), j);
123 assertEquals(bf_multi.setValue(0, j), j << 7);
124 }
125 for (int j = 0; j < 128; j++) {
126 assertEquals(bf_zero.getValue(bf_zero.setValue(0, j)), 0);
127 assertEquals(bf_zero.setValue(0, j), 0);
128 }
129
130 // verify that excess bits are stripped off
131 assertEquals(bf_multi.setValue(0x3f80, 128), 0);
132 for (int j = 0; j < 2; j++) {
133 assertEquals(bf_single.getValue(bf_single.setValue(0, j)), j);
134 assertEquals(bf_single.setValue(0, j), j << 14);
135 }
136
137 // verify that excess bits are stripped off
138 assertEquals(bf_single.setValue(0x4000, 2), 0);
139 }
140
141 /**
142 * test the setShortValue() method
143 */
144 public void testSetShortValue() {
145 for (int j = 0; j < 128; j++) {
146 assertEquals(bf_multi.getShortValue(bf_multi.setShortValue((short) 0, (short) j)), (short) j);
147 assertEquals(bf_multi.setShortValue((short) 0, (short) j), (short) (j << 7));
148 }
149 for (int j = 0; j < 128; j++) {
150 assertEquals(bf_zero.getShortValue(bf_zero.setShortValue((short) 0, (short) j)), (short) 0);
151 assertEquals(bf_zero.setShortValue((short) 0, (short) j), (short) (0));
152 }
153
154 // verify that excess bits are stripped off
155 assertEquals(bf_multi.setShortValue((short) 0x3f80, (short) 128), (short) 0);
156 for (int j = 0; j < 2; j++) {
157 assertEquals(bf_single.getShortValue(bf_single.setShortValue((short) 0, (short) j)), (short) j);
158 assertEquals(bf_single.setShortValue((short) 0, (short) j), (short) (j << 14));
159 }
160
161 // verify that excess bits are stripped off
162 assertEquals(bf_single.setShortValue((short) 0x4000, (short) 2), (short) 0);
163 }
164
165 public void testByte() {
166 assertEquals(0, new BitField(0).setByteBoolean((byte) 0, true));
167 assertEquals(1, new BitField(1).setByteBoolean((byte) 0, true));
168 assertEquals(2, new BitField(2).setByteBoolean((byte) 0, true));
169 assertEquals(4, new BitField(4).setByteBoolean((byte) 0, true));
170 assertEquals(8, new BitField(8).setByteBoolean((byte) 0, true));
171 assertEquals(16, new BitField(16).setByteBoolean((byte) 0, true));
172 assertEquals(32, new BitField(32).setByteBoolean((byte) 0, true));
173 assertEquals(64, new BitField(64).setByteBoolean((byte) 0, true));
174 assertEquals(-128, new BitField(128).setByteBoolean((byte) 0, true));
175 assertEquals(1, new BitField(0).setByteBoolean((byte) 1, false));
176 assertEquals(0, new BitField(1).setByteBoolean((byte) 1, false));
177 assertEquals(0, new BitField(2).setByteBoolean((byte) 2, false));
178 assertEquals(0, new BitField(4).setByteBoolean((byte) 4, false));
179 assertEquals(0, new BitField(8).setByteBoolean((byte) 8, false));
180 assertEquals(0, new BitField(16).setByteBoolean((byte) 16, false));
181 assertEquals(0, new BitField(32).setByteBoolean((byte) 32, false));
182 assertEquals(0, new BitField(64).setByteBoolean((byte) 64, false));
183 assertEquals(0, new BitField(128).setByteBoolean((byte) 128, false));
184 assertEquals(-2, new BitField(1).setByteBoolean((byte) 255, false));
185 byte clearedBit = new BitField(0x40).setByteBoolean((byte) - 63, false);
186
187 assertEquals(false, new BitField(0x40).isSet(clearedBit));
188 }
189
190 /**
191 * test the clear() method
192 */
193 public void testClear() {
194 assertEquals(bf_multi.clear(-1), 0xFFFFC07F);
195 assertEquals(bf_single.clear(-1), 0xFFFFBFFF);
196 assertEquals(bf_zero.clear(-1), 0xFFFFFFFF);
197 }
198
199 /**
200 * test the clearShort() method
201 */
202 public void testClearShort() {
203 assertEquals(bf_multi.clearShort((short) - 1), (short) 0xC07F);
204 assertEquals(bf_single.clearShort((short) - 1), (short) 0xBFFF);
205 assertEquals(bf_zero.clearShort((short) -1), (short) 0xFFFF);
206 }
207
208 /**
209 * test the set() method
210 */
211 public void testSet() {
212 assertEquals(bf_multi.set(0), 0x3F80);
213 assertEquals(bf_single.set(0), 0x4000);
214 assertEquals(bf_zero.set(0), 0);
215 }
216
217 /**
218 * test the setShort() method
219 */
220 public void testSetShort() {
221 assertEquals(bf_multi.setShort((short) 0), (short) 0x3F80);
222 assertEquals(bf_single.setShort((short) 0), (short) 0x4000);
223 assertEquals(bf_zero.setShort((short) 0), (short) 0);
224 }
225
226 /**
227 * test the setBoolean() method
228 */
229 public void testSetBoolean() {
230 assertEquals(bf_multi.set(0), bf_multi.setBoolean(0, true));
231 assertEquals(bf_single.set(0), bf_single.setBoolean(0, true));
232 assertEquals(bf_zero.set(0), bf_zero.setBoolean(0, true));
233 assertEquals(bf_multi.clear(-1), bf_multi.setBoolean(-1, false));
234 assertEquals(bf_single.clear(-1), bf_single.setBoolean(-1, false));
235 assertEquals(bf_zero.clear(-1), bf_zero.setBoolean(-1, false));
236 }
237
238 /**
239 * test the setShortBoolean() method
240 */
241 public void testSetShortBoolean() {
242 assertEquals(bf_multi.setShort((short) 0), bf_multi.setShortBoolean((short) 0, true));
243 assertEquals(bf_single.setShort((short) 0), bf_single.setShortBoolean((short) 0, true));
244 assertEquals(bf_zero.setShort((short) 0), bf_zero.setShortBoolean((short) 0, true));
245 assertEquals(bf_multi.clearShort((short) - 1), bf_multi.setShortBoolean((short) - 1, false));
246 assertEquals(bf_single.clearShort((short) - 1), bf_single.setShortBoolean((short) - 1, false));
247 assertEquals(bf_zero.clearShort((short) -1), bf_zero.setShortBoolean((short) -1, false));
248 }
249
250 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import static org.junit.Assert.*;
19
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Modifier;
22
23 import org.junit.Test;
24
25 /**
26 * Unit tests {@link org.apache.commons.lang3.BooleanUtils}.
27 *
28 * @version $Id: BooleanUtilsTest.java 1153484 2011-08-03 13:39:42Z ggregory $
29 */
30 public class BooleanUtilsTest {
31
32 //-----------------------------------------------------------------------
33 @Test
34 public void testConstructor() {
35 assertNotNull(new BooleanUtils());
36 Constructor<?>[] cons = BooleanUtils.class.getDeclaredConstructors();
37 assertEquals(1, cons.length);
38 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
39 assertEquals(true, Modifier.isPublic(BooleanUtils.class.getModifiers()));
40 assertEquals(false, Modifier.isFinal(BooleanUtils.class.getModifiers()));
41 }
42
43 //-----------------------------------------------------------------------
44 @Test
45 public void test_negate_Boolean() {
46 assertSame(null, BooleanUtils.negate(null));
47 assertSame(Boolean.TRUE, BooleanUtils.negate(Boolean.FALSE));
48 assertSame(Boolean.FALSE, BooleanUtils.negate(Boolean.TRUE));
49 }
50
51 //-----------------------------------------------------------------------
52 @Test
53 public void test_isTrue_Boolean() {
54 assertEquals(true, BooleanUtils.isTrue(Boolean.TRUE));
55 assertEquals(false, BooleanUtils.isTrue(Boolean.FALSE));
56 assertEquals(false, BooleanUtils.isTrue((Boolean) null));
57 }
58
59 @Test
60 public void test_isNotTrue_Boolean() {
61 assertEquals(false, BooleanUtils.isNotTrue(Boolean.TRUE));
62 assertEquals(true, BooleanUtils.isNotTrue(Boolean.FALSE));
63 assertEquals(true, BooleanUtils.isNotTrue((Boolean) null));
64 }
65
66 //-----------------------------------------------------------------------
67 @Test
68 public void test_isFalse_Boolean() {
69 assertEquals(false, BooleanUtils.isFalse(Boolean.TRUE));
70 assertEquals(true, BooleanUtils.isFalse(Boolean.FALSE));
71 assertEquals(false, BooleanUtils.isFalse((Boolean) null));
72 }
73
74 @Test
75 public void test_isNotFalse_Boolean() {
76 assertEquals(true, BooleanUtils.isNotFalse(Boolean.TRUE));
77 assertEquals(false, BooleanUtils.isNotFalse(Boolean.FALSE));
78 assertEquals(true, BooleanUtils.isNotFalse((Boolean) null));
79 }
80
81 //-----------------------------------------------------------------------
82 @Test
83 public void test_toBoolean_Boolean() {
84 assertEquals(true, BooleanUtils.toBoolean(Boolean.TRUE));
85 assertEquals(false, BooleanUtils.toBoolean(Boolean.FALSE));
86 assertEquals(false, BooleanUtils.toBoolean((Boolean) null));
87 }
88
89 @Test
90 public void test_toBooleanDefaultIfNull_Boolean_boolean() {
91 assertEquals(true, BooleanUtils.toBooleanDefaultIfNull(Boolean.TRUE, true));
92 assertEquals(true, BooleanUtils.toBooleanDefaultIfNull(Boolean.TRUE, false));
93 assertEquals(false, BooleanUtils.toBooleanDefaultIfNull(Boolean.FALSE, true));
94 assertEquals(false, BooleanUtils.toBooleanDefaultIfNull(Boolean.FALSE, false));
95 assertEquals(true, BooleanUtils.toBooleanDefaultIfNull((Boolean) null, true));
96 assertEquals(false, BooleanUtils.toBooleanDefaultIfNull((Boolean) null, false));
97 }
98
99 //-----------------------------------------------------------------------
100 //-----------------------------------------------------------------------
101 @Test
102 public void test_toBoolean_int() {
103 assertEquals(true, BooleanUtils.toBoolean(1));
104 assertEquals(true, BooleanUtils.toBoolean(-1));
105 assertEquals(false, BooleanUtils.toBoolean(0));
106 }
107
108 @Test
109 public void test_toBooleanObject_int() {
110 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject(1));
111 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject(-1));
112 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject(0));
113 }
114
115 @Test
116 public void test_toBooleanObject_Integer() {
117 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject(Integer.valueOf(1)));
118 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject(Integer.valueOf(-1)));
119 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject(Integer.valueOf(0)));
120 assertEquals(null, BooleanUtils.toBooleanObject((Integer) null));
121 }
122
123 //-----------------------------------------------------------------------
124 @Test
125 public void test_toBoolean_int_int_int() {
126 assertEquals(true, BooleanUtils.toBoolean(6, 6, 7));
127 assertEquals(false, BooleanUtils.toBoolean(7, 6, 7));
128 }
129
130 @Test(expected = IllegalArgumentException.class)
131 public void test_toBoolean_int_int_int_noMatch() {
132 BooleanUtils.toBoolean(8, 6, 7);
133 }
134
135 @Test
136 public void test_toBoolean_Integer_Integer_Integer() {
137 Integer six = Integer.valueOf(6);
138 Integer seven = Integer.valueOf(7);
139
140 assertEquals(true, BooleanUtils.toBoolean((Integer) null, null, seven));
141 assertEquals(false, BooleanUtils.toBoolean((Integer) null, six, null));
142
143 assertEquals(true, BooleanUtils.toBoolean(Integer.valueOf(6), six, seven));
144 assertEquals(false, BooleanUtils.toBoolean(Integer.valueOf(7), six, seven));
145 }
146
147 @Test(expected = IllegalArgumentException.class)
148 public void test_toBoolean_Integer_Integer_Integer_nullValue() {
149 BooleanUtils.toBoolean(null, Integer.valueOf(6), Integer.valueOf(7));
150 }
151
152 @Test(expected = IllegalArgumentException.class)
153 public void test_toBoolean_Integer_Integer_Integer_noMatch() {
154 BooleanUtils.toBoolean(Integer.valueOf(8), Integer.valueOf(6), Integer.valueOf(7));
155 }
156
157 //-----------------------------------------------------------------------
158 @Test
159 public void test_toBooleanObject_int_int_int() {
160 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject(6, 6, 7, 8));
161 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject(7, 6, 7, 8));
162 assertEquals(null, BooleanUtils.toBooleanObject(8, 6, 7, 8));
163 }
164
165 @Test(expected = IllegalArgumentException.class)
166 public void test_toBooleanObject_int_int_int_noMatch() {
167 BooleanUtils.toBooleanObject(9, 6, 7, 8);
168 }
169
170 @Test
171 public void test_toBooleanObject_Integer_Integer_Integer_Integer() {
172 Integer six = Integer.valueOf(6);
173 Integer seven = Integer.valueOf(7);
174 Integer eight = Integer.valueOf(8);
175
176 assertSame(Boolean.TRUE, BooleanUtils.toBooleanObject((Integer) null, null, seven, eight));
177 assertSame(Boolean.FALSE, BooleanUtils.toBooleanObject((Integer) null, six, null, eight));
178 assertSame(null, BooleanUtils.toBooleanObject((Integer) null, six, seven, null));
179
180 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject(Integer.valueOf(6), six, seven, eight));
181 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject(Integer.valueOf(7), six, seven, eight));
182 assertEquals(null, BooleanUtils.toBooleanObject(Integer.valueOf(8), six, seven, eight));
183 }
184
185 @Test(expected = IllegalArgumentException.class)
186 public void test_toBooleanObject_Integer_Integer_Integer_Integer_nullValue() {
187 BooleanUtils.toBooleanObject(null, Integer.valueOf(6), Integer.valueOf(7), Integer.valueOf(8));
188 }
189
190 @Test(expected = IllegalArgumentException.class)
191 public void test_toBooleanObject_Integer_Integer_Integer_Integer_noMatch() {
192 BooleanUtils.toBooleanObject(Integer.valueOf(9), Integer.valueOf(6), Integer.valueOf(7), Integer.valueOf(8));
193 }
194
195 //-----------------------------------------------------------------------
196 @Test
197 public void test_toInteger_boolean() {
198 assertEquals(1, BooleanUtils.toInteger(true));
199 assertEquals(0, BooleanUtils.toInteger(false));
200 }
201
202 @Test
203 public void test_toIntegerObject_boolean() {
204 assertEquals(Integer.valueOf(1), BooleanUtils.toIntegerObject(true));
205 assertEquals(Integer.valueOf(0), BooleanUtils.toIntegerObject(false));
206 }
207
208 @Test
209 public void test_toIntegerObject_Boolean() {
210 assertEquals(Integer.valueOf(1), BooleanUtils.toIntegerObject(Boolean.TRUE));
211 assertEquals(Integer.valueOf(0), BooleanUtils.toIntegerObject(Boolean.FALSE));
212 assertEquals(null, BooleanUtils.toIntegerObject((Boolean) null));
213 }
214
215 //-----------------------------------------------------------------------
216 @Test
217 public void test_toInteger_boolean_int_int() {
218 assertEquals(6, BooleanUtils.toInteger(true, 6, 7));
219 assertEquals(7, BooleanUtils.toInteger(false, 6, 7));
220 }
221
222 @Test
223 public void test_toInteger_Boolean_int_int_int() {
224 assertEquals(6, BooleanUtils.toInteger(Boolean.TRUE, 6, 7, 8));
225 assertEquals(7, BooleanUtils.toInteger(Boolean.FALSE, 6, 7, 8));
226 assertEquals(8, BooleanUtils.toInteger(null, 6, 7, 8));
227 }
228
229 @Test
230 public void test_toIntegerObject_boolean_Integer_Integer() {
231 Integer six = Integer.valueOf(6);
232 Integer seven = Integer.valueOf(7);
233 assertEquals(six, BooleanUtils.toIntegerObject(true, six, seven));
234 assertEquals(seven, BooleanUtils.toIntegerObject(false, six, seven));
235 }
236
237 @Test
238 public void test_toIntegerObject_Boolean_Integer_Integer_Integer() {
239 Integer six = Integer.valueOf(6);
240 Integer seven = Integer.valueOf(7);
241 Integer eight = Integer.valueOf(8);
242 assertEquals(six, BooleanUtils.toIntegerObject(Boolean.TRUE, six, seven, eight));
243 assertEquals(seven, BooleanUtils.toIntegerObject(Boolean.FALSE, six, seven, eight));
244 assertEquals(eight, BooleanUtils.toIntegerObject((Boolean) null, six, seven, eight));
245 assertEquals(null, BooleanUtils.toIntegerObject((Boolean) null, six, seven, null));
246 }
247
248 //-----------------------------------------------------------------------
249 //-----------------------------------------------------------------------
250 @Test
251 public void test_toBooleanObject_String() {
252 assertEquals(null, BooleanUtils.toBooleanObject((String) null));
253 assertEquals(null, BooleanUtils.toBooleanObject(""));
254 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("false"));
255 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("no"));
256 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("off"));
257 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("FALSE"));
258 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("NO"));
259 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("OFF"));
260 assertEquals(null, BooleanUtils.toBooleanObject("oof"));
261 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("true"));
262 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("yes"));
263 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("on"));
264 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("TRUE"));
265 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("ON"));
266 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("YES"));
267 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("TruE"));
268 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("TruE"));
269
270 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("y"));
271 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("Y"));
272 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("t"));
273 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("T"));
274 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("f"));
275 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("F"));
276 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("n"));
277 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("N"));
278 assertEquals(null, BooleanUtils.toBooleanObject("z"));
279
280 assertEquals(null, BooleanUtils.toBooleanObject("ab"));
281 assertEquals(null, BooleanUtils.toBooleanObject("yoo"));
282 }
283
284 @Test
285 public void test_toBooleanObject_String_String_String_String() {
286 assertSame(Boolean.TRUE, BooleanUtils.toBooleanObject((String) null, null, "N", "U"));
287 assertSame(Boolean.FALSE, BooleanUtils.toBooleanObject((String) null, "Y", null, "U"));
288 assertSame(null, BooleanUtils.toBooleanObject((String) null, "Y", "N", null));
289
290 assertEquals(Boolean.TRUE, BooleanUtils.toBooleanObject("Y", "Y", "N", "U"));
291 assertEquals(Boolean.FALSE, BooleanUtils.toBooleanObject("N", "Y", "N", "U"));
292 assertEquals(null, BooleanUtils.toBooleanObject("U", "Y", "N", "U"));
293 }
294
295 @Test(expected = IllegalArgumentException.class)
296 public void test_toBooleanObject_String_String_String_String_nullValue() {
297 BooleanUtils.toBooleanObject((String) null, "Y", "N", "U");
298 }
299
300 @Test(expected = IllegalArgumentException.class)
301 public void test_toBooleanObject_String_String_String_String_noMatch() {
302 BooleanUtils.toBooleanObject("X", "Y", "N", "U");
303 }
304
305 //-----------------------------------------------------------------------
306 @Test
307 public void test_toBoolean_String() {
308 assertEquals(false, BooleanUtils.toBoolean((String) null));
309 assertEquals(false, BooleanUtils.toBoolean(""));
310 assertEquals(false, BooleanUtils.toBoolean("off"));
311 assertEquals(false, BooleanUtils.toBoolean("oof"));
312 assertEquals(false, BooleanUtils.toBoolean("yep"));
313 assertEquals(false, BooleanUtils.toBoolean("trux"));
314 assertEquals(false, BooleanUtils.toBoolean("false"));
315 assertEquals(false, BooleanUtils.toBoolean("a"));
316 assertEquals(true, BooleanUtils.toBoolean("true")); // interned handled differently
317 assertEquals(true, BooleanUtils.toBoolean(new StringBuffer("tr").append("ue").toString()));
318 assertEquals(true, BooleanUtils.toBoolean("truE"));
319 assertEquals(true, BooleanUtils.toBoolean("trUe"));
320 assertEquals(true, BooleanUtils.toBoolean("trUE"));
321 assertEquals(true, BooleanUtils.toBoolean("tRue"));
322 assertEquals(true, BooleanUtils.toBoolean("tRuE"));
323 assertEquals(true, BooleanUtils.toBoolean("tRUe"));
324 assertEquals(true, BooleanUtils.toBoolean("tRUE"));
325 assertEquals(true, BooleanUtils.toBoolean("TRUE"));
326 assertEquals(true, BooleanUtils.toBoolean("TRUe"));
327 assertEquals(true, BooleanUtils.toBoolean("TRuE"));
328 assertEquals(true, BooleanUtils.toBoolean("TRue"));
329 assertEquals(true, BooleanUtils.toBoolean("TrUE"));
330 assertEquals(true, BooleanUtils.toBoolean("TrUe"));
331 assertEquals(true, BooleanUtils.toBoolean("TruE"));
332 assertEquals(true, BooleanUtils.toBoolean("True"));
333 assertEquals(true, BooleanUtils.toBoolean("on"));
334 assertEquals(true, BooleanUtils.toBoolean("oN"));
335 assertEquals(true, BooleanUtils.toBoolean("On"));
336 assertEquals(true, BooleanUtils.toBoolean("ON"));
337 assertEquals(true, BooleanUtils.toBoolean("yes"));
338 assertEquals(true, BooleanUtils.toBoolean("yeS"));
339 assertEquals(true, BooleanUtils.toBoolean("yEs"));
340 assertEquals(true, BooleanUtils.toBoolean("yES"));
341 assertEquals(true, BooleanUtils.toBoolean("Yes"));
342 assertEquals(true, BooleanUtils.toBoolean("YeS"));
343 assertEquals(true, BooleanUtils.toBoolean("YEs"));
344 assertEquals(true, BooleanUtils.toBoolean("YES"));
345 assertEquals(false, BooleanUtils.toBoolean("yes?"));
346 assertEquals(false, BooleanUtils.toBoolean("tru"));
347
348 assertEquals(false, BooleanUtils.toBoolean("no"));
349 assertEquals(false, BooleanUtils.toBoolean("off"));
350 assertEquals(false, BooleanUtils.toBoolean("yoo"));
351 }
352
353 @Test
354 public void test_toBoolean_String_String_String() {
355 assertEquals(true, BooleanUtils.toBoolean((String) null, null, "N"));
356 assertEquals(false, BooleanUtils.toBoolean((String) null, "Y", null));
357 assertEquals(true, BooleanUtils.toBoolean("Y", "Y", "N"));
358 assertEquals(true, BooleanUtils.toBoolean("Y", new String("Y"), new String("N")));
359 assertEquals(false, BooleanUtils.toBoolean("N", "Y", "N"));
360 assertEquals(false, BooleanUtils.toBoolean("N", new String("Y"), new String("N")));
361 assertEquals(true, BooleanUtils.toBoolean((String) null, null, null));
362 assertEquals(true, BooleanUtils.toBoolean("Y", "Y", "Y"));
363 assertEquals(true, BooleanUtils.toBoolean("Y", new String("Y"), new String("Y")));
364 }
365
366 @Test(expected = IllegalArgumentException.class)
367 public void test_toBoolean_String_String_String_nullValue() {
368 BooleanUtils.toBoolean(null, "Y", "N");
369 }
370
371 @Test(expected = IllegalArgumentException.class)
372 public void test_toBoolean_String_String_String_noMatch() {
373 BooleanUtils.toBoolean("X", "Y", "N");
374 }
375
376 //-----------------------------------------------------------------------
377 @Test
378 public void test_toStringTrueFalse_Boolean() {
379 assertEquals(null, BooleanUtils.toStringTrueFalse((Boolean) null));
380 assertEquals("true", BooleanUtils.toStringTrueFalse(Boolean.TRUE));
381 assertEquals("false", BooleanUtils.toStringTrueFalse(Boolean.FALSE));
382 }
383
384 @Test
385 public void test_toStringOnOff_Boolean() {
386 assertEquals(null, BooleanUtils.toStringOnOff((Boolean) null));
387 assertEquals("on", BooleanUtils.toStringOnOff(Boolean.TRUE));
388 assertEquals("off", BooleanUtils.toStringOnOff(Boolean.FALSE));
389 }
390
391 @Test
392 public void test_toStringYesNo_Boolean() {
393 assertEquals(null, BooleanUtils.toStringYesNo((Boolean) null));
394 assertEquals("yes", BooleanUtils.toStringYesNo(Boolean.TRUE));
395 assertEquals("no", BooleanUtils.toStringYesNo(Boolean.FALSE));
396 }
397
398 @Test
399 public void test_toString_Boolean_String_String_String() {
400 assertEquals("U", BooleanUtils.toString((Boolean) null, "Y", "N", "U"));
401 assertEquals("Y", BooleanUtils.toString(Boolean.TRUE, "Y", "N", "U"));
402 assertEquals("N", BooleanUtils.toString(Boolean.FALSE, "Y", "N", "U"));
403 }
404
405 //-----------------------------------------------------------------------
406 @Test
407 public void test_toStringTrueFalse_boolean() {
408 assertEquals("true", BooleanUtils.toStringTrueFalse(true));
409 assertEquals("false", BooleanUtils.toStringTrueFalse(false));
410 }
411
412 @Test
413 public void test_toStringOnOff_boolean() {
414 assertEquals("on", BooleanUtils.toStringOnOff(true));
415 assertEquals("off", BooleanUtils.toStringOnOff(false));
416 }
417
418 @Test
419 public void test_toStringYesNo_boolean() {
420 assertEquals("yes", BooleanUtils.toStringYesNo(true));
421 assertEquals("no", BooleanUtils.toStringYesNo(false));
422 }
423
424 @Test
425 public void test_toString_boolean_String_String_String() {
426 assertEquals("Y", BooleanUtils.toString(true, "Y", "N"));
427 assertEquals("N", BooleanUtils.toString(false, "Y", "N"));
428 }
429
430 // testXor
431 // -----------------------------------------------------------------------
432 @Test(expected = IllegalArgumentException.class)
433 public void testXor_primitive_nullInput() {
434 BooleanUtils.xor((boolean[]) null);
435 }
436
437 @Test(expected = IllegalArgumentException.class)
438 public void testXor_primitive_emptyInput() {
439 BooleanUtils.xor(new boolean[] {});
440 }
441
442 @Test
443 public void testXor_primitive_validInput_2items() {
444 assertTrue(
445 "True result for (true, true)",
446 ! BooleanUtils.xor(new boolean[] { true, true }));
447
448 assertTrue(
449 "True result for (false, false)",
450 ! BooleanUtils.xor(new boolean[] { false, false }));
451
452 assertTrue(
453 "False result for (true, false)",
454 BooleanUtils.xor(new boolean[] { true, false }));
455
456 assertTrue(
457 "False result for (false, true)",
458 BooleanUtils.xor(new boolean[] { false, true }));
459 }
460
461 @Test
462 public void testXor_primitive_validInput_3items() {
463 assertTrue(
464 "False result for (false, false, true)",
465 BooleanUtils.xor(new boolean[] { false, false, true }));
466
467 assertTrue(
468 "False result for (false, true, false)",
469 BooleanUtils.xor(new boolean[] { false, true, false }));
470
471 assertTrue(
472 "False result for (true, false, false)",
473 BooleanUtils.xor(new boolean[] { true, false, false }));
474
475 assertTrue(
476 "True result for (true, true, true)",
477 ! BooleanUtils.xor(new boolean[] { true, true, true }));
478
479 assertTrue(
480 "True result for (false, false)",
481 ! BooleanUtils.xor(new boolean[] { false, false, false }));
482
483 assertTrue(
484 "True result for (true, true, false)",
485 ! BooleanUtils.xor(new boolean[] { true, true, false }));
486
487 assertTrue(
488 "True result for (true, false, true)",
489 ! BooleanUtils.xor(new boolean[] { true, false, true }));
490
491 assertTrue(
492 "False result for (false, true, true)",
493 ! BooleanUtils.xor(new boolean[] { false, true, true }));
494 }
495
496 @Test(expected = IllegalArgumentException.class)
497 public void testXor_object_nullInput() {
498 BooleanUtils.xor((Boolean[]) null);
499 }
500
501 @Test(expected = IllegalArgumentException.class)
502 public void testXor_object_emptyInput() {
503 BooleanUtils.xor(new Boolean[] {});
504 }
505
506 @Test(expected = IllegalArgumentException.class)
507 public void testXor_object_nullElementInput() {
508 BooleanUtils.xor(new Boolean[] {null});
509 }
510
511 @Test
512 public void testXor_object_validInput_2items() {
513 assertTrue(
514 "True result for (true, true)",
515 ! BooleanUtils
516 .xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE })
517 .booleanValue());
518
519 assertTrue(
520 "True result for (false, false)",
521 ! BooleanUtils
522 .xor(new Boolean[] { Boolean.FALSE, Boolean.FALSE })
523 .booleanValue());
524
525 assertTrue(
526 "False result for (true, false)",
527 BooleanUtils
528 .xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE })
529 .booleanValue());
530
531 assertTrue(
532 "False result for (false, true)",
533 BooleanUtils
534 .xor(new Boolean[] { Boolean.FALSE, Boolean.TRUE })
535 .booleanValue());
536 }
537
538 @Test
539 public void testXor_object_validInput_3items() {
540 assertTrue(
541 "False result for (false, false, true)",
542 BooleanUtils
543 .xor(
544 new Boolean[] {
545 Boolean.FALSE,
546 Boolean.FALSE,
547 Boolean.TRUE })
548 .booleanValue());
549
550 assertTrue(
551 "False result for (false, true, false)",
552 BooleanUtils
553 .xor(
554 new Boolean[] {
555 Boolean.FALSE,
556 Boolean.TRUE,
557 Boolean.FALSE })
558 .booleanValue());
559
560 assertTrue(
561 "False result for (true, false, false)",
562 BooleanUtils
563 .xor(
564 new Boolean[] {
565 Boolean.TRUE,
566 Boolean.FALSE,
567 Boolean.FALSE })
568 .booleanValue());
569
570 assertTrue(
571 "True result for (true, true, true)",
572 ! BooleanUtils
573 .xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE, Boolean.TRUE })
574 .booleanValue());
575
576 assertTrue(
577 "True result for (false, false)",
578 ! BooleanUtils.xor(
579 new Boolean[] {
580 Boolean.FALSE,
581 Boolean.FALSE,
582 Boolean.FALSE })
583 .booleanValue());
584
585 assertTrue(
586 "True result for (true, true, false)",
587 ! BooleanUtils.xor(
588 new Boolean[] {
589 Boolean.TRUE,
590 Boolean.TRUE,
591 Boolean.FALSE })
592 .booleanValue());
593
594 assertTrue(
595 "True result for (true, false, true)",
596 ! BooleanUtils.xor(
597 new Boolean[] {
598 Boolean.TRUE,
599 Boolean.FALSE,
600 Boolean.TRUE })
601 .booleanValue());
602
603 assertTrue(
604 "False result for (false, true, true)",
605 ! BooleanUtils.xor(
606 new Boolean[] {
607 Boolean.FALSE,
608 Boolean.TRUE,
609 Boolean.TRUE })
610 .booleanValue());
611 }
612
613 // testAnd
614 // -----------------------------------------------------------------------
615 @Test(expected = IllegalArgumentException.class)
616 public void testAnd_primitive_nullInput() {
617 BooleanUtils.and((boolean[]) null);
618 }
619
620 @Test(expected = IllegalArgumentException.class)
621 public void testAnd_primitive_emptyInput() {
622 BooleanUtils.and(new boolean[] {});
623 }
624
625 @Test
626 public void testAnd_primitive_validInput_2items() {
627 assertTrue(
628 "False result for (true, true)",
629 BooleanUtils.and(new boolean[] { true, true }));
630
631 assertTrue(
632 "True result for (false, false)",
633 ! BooleanUtils.and(new boolean[] { false, false }));
634
635 assertTrue(
636 "True result for (true, false)",
637 ! BooleanUtils.and(new boolean[] { true, false }));
638
639 assertTrue(
640 "True result for (false, true)",
641 ! BooleanUtils.and(new boolean[] { false, true }));
642 }
643
644 @Test
645 public void testAnd_primitive_validInput_3items() {
646 assertTrue(
647 "True result for (false, false, true)",
648 ! BooleanUtils.and(new boolean[] { false, false, true }));
649
650 assertTrue(
651 "True result for (false, true, false)",
652 ! BooleanUtils.and(new boolean[] { false, true, false }));
653
654 assertTrue(
655 "True result for (true, false, false)",
656 ! BooleanUtils.and(new boolean[] { true, false, false }));
657
658 assertTrue(
659 "False result for (true, true, true)",
660 BooleanUtils.and(new boolean[] { true, true, true }));
661
662 assertTrue(
663 "True result for (false, false)",
664 ! BooleanUtils.and(new boolean[] { false, false, false }));
665
666 assertTrue(
667 "True result for (true, true, false)",
668 ! BooleanUtils.and(new boolean[] { true, true, false }));
669
670 assertTrue(
671 "True result for (true, false, true)",
672 ! BooleanUtils.and(new boolean[] { true, false, true }));
673
674 assertTrue(
675 "True result for (false, true, true)",
676 ! BooleanUtils.and(new boolean[] { false, true, true }));
677 }
678
679 @Test(expected = IllegalArgumentException.class)
680 public void testAnd_object_nullInput() {
681 BooleanUtils.and((Boolean[]) null);
682 }
683
684 @Test(expected = IllegalArgumentException.class)
685 public void testAnd_object_emptyInput() {
686 BooleanUtils.and(new Boolean[] {});
687 }
688
689 @Test(expected = IllegalArgumentException.class)
690 public void testAnd_object_nullElementInput() {
691 BooleanUtils.and(new Boolean[] {null});
692 }
693
694 @Test
695 public void testAnd_object_validInput_2items() {
696 assertTrue(
697 "False result for (true, true)",
698 BooleanUtils
699 .and(new Boolean[] { Boolean.TRUE, Boolean.TRUE })
700 .booleanValue());
701
702 assertTrue(
703 "True result for (false, false)",
704 ! BooleanUtils
705 .and(new Boolean[] { Boolean.FALSE, Boolean.FALSE })
706 .booleanValue());
707
708 assertTrue(
709 "True result for (true, false)",
710 ! BooleanUtils
711 .and(new Boolean[] { Boolean.TRUE, Boolean.FALSE })
712 .booleanValue());
713
714 assertTrue(
715 "True result for (false, true)",
716 ! BooleanUtils
717 .and(new Boolean[] { Boolean.FALSE, Boolean.TRUE })
718 .booleanValue());
719 }
720
721 @Test
722 public void testAnd_object_validInput_3items() {
723 assertTrue(
724 "True result for (false, false, true)",
725 ! BooleanUtils
726 .and(
727 new Boolean[] {
728 Boolean.FALSE,
729 Boolean.FALSE,
730 Boolean.TRUE })
731 .booleanValue());
732
733 assertTrue(
734 "True result for (false, true, false)",
735 ! BooleanUtils
736 .and(
737 new Boolean[] {
738 Boolean.FALSE,
739 Boolean.TRUE,
740 Boolean.FALSE })
741 .booleanValue());
742
743 assertTrue(
744 "True result for (true, false, false)",
745 ! BooleanUtils
746 .and(
747 new Boolean[] {
748 Boolean.TRUE,
749 Boolean.FALSE,
750 Boolean.FALSE })
751 .booleanValue());
752
753 assertTrue(
754 "False result for (true, true, true)",
755 BooleanUtils
756 .and(new Boolean[] { Boolean.TRUE, Boolean.TRUE, Boolean.TRUE })
757 .booleanValue());
758
759 assertTrue(
760 "True result for (false, false)",
761 ! BooleanUtils.and(
762 new Boolean[] {
763 Boolean.FALSE,
764 Boolean.FALSE,
765 Boolean.FALSE })
766 .booleanValue());
767
768 assertTrue(
769 "True result for (true, true, false)",
770 ! BooleanUtils.and(
771 new Boolean[] {
772 Boolean.TRUE,
773 Boolean.TRUE,
774 Boolean.FALSE })
775 .booleanValue());
776
777 assertTrue(
778 "True result for (true, false, true)",
779 ! BooleanUtils.and(
780 new Boolean[] {
781 Boolean.TRUE,
782 Boolean.FALSE,
783 Boolean.TRUE })
784 .booleanValue());
785
786 assertTrue(
787 "True result for (false, true, true)",
788 ! BooleanUtils.and(
789 new Boolean[] {
790 Boolean.FALSE,
791 Boolean.TRUE,
792 Boolean.TRUE })
793 .booleanValue());
794 }
795
796 // testOr
797 // -----------------------------------------------------------------------
798 @Test(expected = IllegalArgumentException.class)
799 public void testOr_primitive_nullInput() {
800 BooleanUtils.or((boolean[]) null);
801 }
802
803 @Test(expected = IllegalArgumentException.class)
804 public void testOr_primitive_emptyInput() {
805 BooleanUtils.or(new boolean[] {});
806 }
807
808 @Test
809 public void testOr_primitive_validInput_2items() {
810 assertTrue(
811 "False result for (true, true)",
812 BooleanUtils.or(new boolean[] { true, true }));
813
814 assertTrue(
815 "True result for (false, false)",
816 ! BooleanUtils.or(new boolean[] { false, false }));
817
818 assertTrue(
819 "False result for (true, false)",
820 BooleanUtils.or(new boolean[] { true, false }));
821
822 assertTrue(
823 "False result for (false, true)",
824 BooleanUtils.or(new boolean[] { false, true }));
825 }
826
827 @Test
828 public void testOr_primitive_validInput_3items() {
829 assertTrue(
830 "False result for (false, false, true)",
831 BooleanUtils.or(new boolean[] { false, false, true }));
832
833 assertTrue(
834 "False result for (false, true, false)",
835 BooleanUtils.or(new boolean[] { false, true, false }));
836
837 assertTrue(
838 "False result for (true, false, false)",
839 BooleanUtils.or(new boolean[] { true, false, false }));
840
841 assertTrue(
842 "False result for (true, true, true)",
843 BooleanUtils.or(new boolean[] { true, true, true }));
844
845 assertTrue(
846 "True result for (false, false)",
847 ! BooleanUtils.or(new boolean[] { false, false, false }));
848
849 assertTrue(
850 "False result for (true, true, false)",
851 BooleanUtils.or(new boolean[] { true, true, false }));
852
853 assertTrue(
854 "False result for (true, false, true)",
855 BooleanUtils.or(new boolean[] { true, false, true }));
856
857 assertTrue(
858 "False result for (false, true, true)",
859 BooleanUtils.or(new boolean[] { false, true, true }));
860
861 }
862 @Test(expected = IllegalArgumentException.class)
863 public void testOr_object_nullInput() {
864 BooleanUtils.or((Boolean[]) null);
865 }
866
867 @Test(expected = IllegalArgumentException.class)
868 public void testOr_object_emptyInput() {
869 BooleanUtils.or(new Boolean[] {});
870 }
871
872 @Test(expected = IllegalArgumentException.class)
873 public void testOr_object_nullElementInput() {
874 BooleanUtils.or(new Boolean[] {null});
875 }
876
877 @Test
878 public void testOr_object_validInput_2items() {
879 assertTrue(
880 "False result for (true, true)",
881 BooleanUtils
882 .or(new Boolean[] { Boolean.TRUE, Boolean.TRUE })
883 .booleanValue());
884
885 assertTrue(
886 "True result for (false, false)",
887 ! BooleanUtils
888 .or(new Boolean[] { Boolean.FALSE, Boolean.FALSE })
889 .booleanValue());
890
891 assertTrue(
892 "False result for (true, false)",
893 BooleanUtils
894 .or(new Boolean[] { Boolean.TRUE, Boolean.FALSE })
895 .booleanValue());
896
897 assertTrue(
898 "False result for (false, true)",
899 BooleanUtils
900 .or(new Boolean[] { Boolean.FALSE, Boolean.TRUE })
901 .booleanValue());
902 }
903
904 @Test
905 public void testOr_object_validInput_3items() {
906 assertTrue(
907 "False result for (false, false, true)",
908 BooleanUtils
909 .or(
910 new Boolean[] {
911 Boolean.FALSE,
912 Boolean.FALSE,
913 Boolean.TRUE })
914 .booleanValue());
915
916 assertTrue(
917 "False result for (false, true, false)",
918 BooleanUtils
919 .or(
920 new Boolean[] {
921 Boolean.FALSE,
922 Boolean.TRUE,
923 Boolean.FALSE })
924 .booleanValue());
925
926 assertTrue(
927 "False result for (true, false, false)",
928 BooleanUtils
929 .or(
930 new Boolean[] {
931 Boolean.TRUE,
932 Boolean.FALSE,
933 Boolean.FALSE })
934 .booleanValue());
935
936 assertTrue(
937 "False result for (true, true, true)",
938 BooleanUtils
939 .or(new Boolean[] { Boolean.TRUE, Boolean.TRUE, Boolean.TRUE })
940 .booleanValue());
941
942 assertTrue(
943 "True result for (false, false)",
944 ! BooleanUtils.or(
945 new Boolean[] {
946 Boolean.FALSE,
947 Boolean.FALSE,
948 Boolean.FALSE })
949 .booleanValue());
950
951 assertTrue(
952 "False result for (true, true, false)",
953 BooleanUtils.or(
954 new Boolean[] {
955 Boolean.TRUE,
956 Boolean.TRUE,
957 Boolean.FALSE })
958 .booleanValue());
959
960 assertTrue(
961 "False result for (true, false, true)",
962 BooleanUtils.or(
963 new Boolean[] {
964 Boolean.TRUE,
965 Boolean.FALSE,
966 Boolean.TRUE })
967 .booleanValue());
968
969 assertTrue(
970 "False result for (false, true, true)",
971 BooleanUtils.or(
972 new Boolean[] {
973 Boolean.FALSE,
974 Boolean.TRUE,
975 Boolean.TRUE })
976 .booleanValue());
977 }
978
979 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3;
18
19 import static org.apache.commons.lang3.JavaVersion.JAVA_1_1;
20 import static org.apache.commons.lang3.JavaVersion.JAVA_1_2;
21 import static org.apache.commons.lang3.JavaVersion.JAVA_1_3;
22 import junit.framework.TestCase;
23
24 /**
25 * Tests CharEncoding.
26 *
27 * @see CharEncoding
28 * @version $Id: CharEncodingTest.java 1088899 2011-04-05 05:31:27Z bayard $
29 */
30 public class CharEncodingTest extends TestCase {
31
32 private void assertSupportedEncoding(String name) {
33 assertTrue("Encoding should be supported: " + name, CharEncoding.isSupported(name));
34 }
35
36 /**
37 * The class can be instantiated.
38 */
39 public void testConstructor() {
40 new CharEncoding();
41 }
42
43 public void testMustBeSupportedJava1_3_1() {
44 if (SystemUtils.isJavaVersionAtLeast(JAVA_1_3)) {
45 this.assertSupportedEncoding(CharEncoding.ISO_8859_1);
46 this.assertSupportedEncoding(CharEncoding.US_ASCII);
47 this.assertSupportedEncoding(CharEncoding.UTF_16);
48 this.assertSupportedEncoding(CharEncoding.UTF_16BE);
49 this.assertSupportedEncoding(CharEncoding.UTF_16LE);
50 this.assertSupportedEncoding(CharEncoding.UTF_8);
51 } else {
52 this.warn("Java 1.3 tests not run since the current version is " + SystemUtils.JAVA_SPECIFICATION_VERSION);
53 }
54 }
55
56 public void testSupported() {
57 assertTrue(CharEncoding.isSupported("UTF8"));
58 assertTrue(CharEncoding.isSupported("UTF-8"));
59 assertTrue(CharEncoding.isSupported("ASCII"));
60 }
61
62 public void testNotSupported() {
63 assertFalse(CharEncoding.isSupported(null));
64 assertFalse(CharEncoding.isSupported(""));
65 assertFalse(CharEncoding.isSupported(" "));
66 assertFalse(CharEncoding.isSupported("\t\r\n"));
67 assertFalse(CharEncoding.isSupported("DOESNOTEXIST"));
68 assertFalse(CharEncoding.isSupported("this is not a valid encoding name"));
69 }
70
71 public void testWorksOnJava1_1_8() {
72 //
73 // In this test, I simply deleted the encodings from the 1.3.1 list.
74 // The Javadoc do not specify which encodings are required.
75 //
76 if (SystemUtils.isJavaVersionAtLeast(JAVA_1_1)) {
77 this.assertSupportedEncoding(CharEncoding.ISO_8859_1);
78 this.assertSupportedEncoding(CharEncoding.US_ASCII);
79 this.assertSupportedEncoding(CharEncoding.UTF_8);
80 } else {
81 this.warn("Java 1.1 tests not run since the current version is " + SystemUtils.JAVA_SPECIFICATION_VERSION);
82 }
83 }
84
85 public void testWorksOnJava1_2_2() {
86 //
87 // In this test, I simply deleted the encodings from the 1.3.1 list.
88 // The Javadoc do not specify which encodings are required.
89 //
90 if (SystemUtils.isJavaVersionAtLeast(JAVA_1_2)) {
91 this.assertSupportedEncoding(CharEncoding.ISO_8859_1);
92 this.assertSupportedEncoding(CharEncoding.US_ASCII);
93 this.assertSupportedEncoding(CharEncoding.UTF_8);
94 } else {
95 this.warn("Java 1.2 tests not run since the current version is " + SystemUtils.JAVA_SPECIFICATION_VERSION);
96 }
97 }
98
99 void warn(String msg) {
100 System.err.println(msg);
101 }
102 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one
2 * or more contributor license agreements. See the NOTICE file
3 * distributed with this work for additional information
4 * regarding copyright ownership. The ASF licenses this file
5 * to you under the Apache License, Version 2.0 (the
6 * "License"); you may not use this file except in compliance
7 * with the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 package org.apache.commons.lang3;
19
20 import java.lang.reflect.Modifier;
21 import java.util.Iterator;
22 import java.util.NoSuchElementException;
23
24 import junit.framework.TestCase;
25
26 /**
27 * Unit tests {@link org.apache.commons.lang3.CharRange}.
28 *
29 * @version $Id: CharRangeTest.java 1090427 2011-04-08 20:17:10Z bayard $
30 */
31 public class CharRangeTest extends TestCase {
32
33 public CharRangeTest(String name) {
34 super(name);
35 }
36
37 //-----------------------------------------------------------------------
38 public void testClass() {
39 // class changed to non-public in 3.0
40 assertEquals(false, Modifier.isPublic(CharRange.class.getModifiers()));
41 assertEquals(true, Modifier.isFinal(CharRange.class.getModifiers()));
42 }
43
44 //-----------------------------------------------------------------------
45 public void testConstructorAccessors_is() {
46 CharRange rangea = CharRange.is('a');
47 assertEquals('a', rangea.getStart());
48 assertEquals('a', rangea.getEnd());
49 assertEquals(false, rangea.isNegated());
50 assertEquals("a", rangea.toString());
51 }
52
53 public void testConstructorAccessors_isNot() {
54 CharRange rangea = CharRange.isNot('a');
55 assertEquals('a', rangea.getStart());
56 assertEquals('a', rangea.getEnd());
57 assertEquals(true, rangea.isNegated());
58 assertEquals("^a", rangea.toString());
59 }
60
61 public void testConstructorAccessors_isIn_Same() {
62 CharRange rangea = CharRange.isIn('a', 'a');
63 assertEquals('a', rangea.getStart());
64 assertEquals('a', rangea.getEnd());
65 assertEquals(false, rangea.isNegated());
66 assertEquals("a", rangea.toString());
67 }
68
69 public void testConstructorAccessors_isIn_Normal() {
70 CharRange rangea = CharRange.isIn('a', 'e');
71 assertEquals('a', rangea.getStart());
72 assertEquals('e', rangea.getEnd());
73 assertEquals(false, rangea.isNegated());
74 assertEquals("a-e", rangea.toString());
75 }
76
77 public void testConstructorAccessors_isIn_Reversed() {
78 CharRange rangea = CharRange.isIn('e', 'a');
79 assertEquals('a', rangea.getStart());
80 assertEquals('e', rangea.getEnd());
81 assertEquals(false, rangea.isNegated());
82 assertEquals("a-e", rangea.toString());
83 }
84
85 public void testConstructorAccessors_isNotIn_Same() {
86 CharRange rangea = CharRange.isNotIn('a', 'a');
87 assertEquals('a', rangea.getStart());
88 assertEquals('a', rangea.getEnd());
89 assertEquals(true, rangea.isNegated());
90 assertEquals("^a", rangea.toString());
91 }
92
93 public void testConstructorAccessors_isNotIn_Normal() {
94 CharRange rangea = CharRange.isNotIn('a', 'e');
95 assertEquals('a', rangea.getStart());
96 assertEquals('e', rangea.getEnd());
97 assertEquals(true, rangea.isNegated());
98 assertEquals("^a-e", rangea.toString());
99 }
100
101 public void testConstructorAccessors_isNotIn_Reversed() {
102 CharRange rangea = CharRange.isNotIn('e', 'a');
103 assertEquals('a', rangea.getStart());
104 assertEquals('e', rangea.getEnd());
105 assertEquals(true, rangea.isNegated());
106 assertEquals("^a-e", rangea.toString());
107 }
108
109 //-----------------------------------------------------------------------
110 public void testEquals_Object() {
111 CharRange rangea = CharRange.is('a');
112 CharRange rangeae = CharRange.isIn('a', 'e');
113 CharRange rangenotbf = CharRange.isIn('b', 'f');
114
115 assertEquals(false, rangea.equals(null));
116
117 assertEquals(true, rangea.equals(rangea));
118 assertEquals(true, rangea.equals(CharRange.is('a')));
119 assertEquals(true, rangeae.equals(rangeae));
120 assertEquals(true, rangeae.equals(CharRange.isIn('a', 'e')));
121 assertEquals(true, rangenotbf.equals(rangenotbf));
122 assertEquals(true, rangenotbf.equals(CharRange.isIn('b', 'f')));
123
124 assertEquals(false, rangea.equals(rangeae));
125 assertEquals(false, rangea.equals(rangenotbf));
126 assertEquals(false, rangeae.equals(rangea));
127 assertEquals(false, rangeae.equals(rangenotbf));
128 assertEquals(false, rangenotbf.equals(rangea));
129 assertEquals(false, rangenotbf.equals(rangeae));
130 }
131
132 public void testHashCode() {
133 CharRange rangea = CharRange.is('a');
134 CharRange rangeae = CharRange.isIn('a', 'e');
135 CharRange rangenotbf = CharRange.isIn('b', 'f');
136
137 assertEquals(true, rangea.hashCode() == rangea.hashCode());
138 assertEquals(true, rangea.hashCode() == CharRange.is('a').hashCode());
139 assertEquals(true, rangeae.hashCode() == rangeae.hashCode());
140 assertEquals(true, rangeae.hashCode() == CharRange.isIn('a', 'e').hashCode());
141 assertEquals(true, rangenotbf.hashCode() == rangenotbf.hashCode());
142 assertEquals(true, rangenotbf.hashCode() == CharRange.isIn('b', 'f').hashCode());
143
144 assertEquals(false, rangea.hashCode() == rangeae.hashCode());
145 assertEquals(false, rangea.hashCode() == rangenotbf.hashCode());
146 assertEquals(false, rangeae.hashCode() == rangea.hashCode());
147 assertEquals(false, rangeae.hashCode() == rangenotbf.hashCode());
148 assertEquals(false, rangenotbf.hashCode() == rangea.hashCode());
149 assertEquals(false, rangenotbf.hashCode() == rangeae.hashCode());
150 }
151
152 //-----------------------------------------------------------------------
153 public void testContains_Char() {
154 CharRange range = CharRange.is('c');
155 assertEquals(false, range.contains('b'));
156 assertEquals(true, range.contains('c'));
157 assertEquals(false, range.contains('d'));
158 assertEquals(false, range.contains('e'));
159
160 range = CharRange.isIn('c', 'd');
161 assertEquals(false, range.contains('b'));
162 assertEquals(true, range.contains('c'));
163 assertEquals(true, range.contains('d'));
164 assertEquals(false, range.contains('e'));
165
166 range = CharRange.isIn('d', 'c');
167 assertEquals(false, range.contains('b'));
168 assertEquals(true, range.contains('c'));
169 assertEquals(true, range.contains('d'));
170 assertEquals(false, range.contains('e'));
171
172 range = CharRange.isNotIn('c', 'd');
173 assertEquals(true, range.contains('b'));
174 assertEquals(false, range.contains('c'));
175 assertEquals(false, range.contains('d'));
176 assertEquals(true, range.contains('e'));
177 assertEquals(true, range.contains((char) 0));
178 assertEquals(true, range.contains(Character.MAX_VALUE));
179 }
180
181 //-----------------------------------------------------------------------
182 public void testContains_Charrange() {
183 CharRange a = CharRange.is('a');
184 CharRange b = CharRange.is('b');
185 CharRange c = CharRange.is('c');
186 CharRange c2 = CharRange.is('c');
187 CharRange d = CharRange.is('d');
188 CharRange e = CharRange.is('e');
189 CharRange cd = CharRange.isIn('c', 'd');
190 CharRange bd = CharRange.isIn('b', 'd');
191 CharRange bc = CharRange.isIn('b', 'c');
192 CharRange ab = CharRange.isIn('a', 'b');
193 CharRange de = CharRange.isIn('d', 'e');
194 CharRange ef = CharRange.isIn('e', 'f');
195 CharRange ae = CharRange.isIn('a', 'e');
196
197 // normal/normal
198 assertEquals(false, c.contains(b));
199 assertEquals(true, c.contains(c));
200 assertEquals(true, c.contains(c2));
201 assertEquals(false, c.contains(d));
202
203 assertEquals(false, c.contains(cd));
204 assertEquals(false, c.contains(bd));
205 assertEquals(false, c.contains(bc));
206 assertEquals(false, c.contains(ab));
207 assertEquals(false, c.contains(de));
208
209 assertEquals(true, cd.contains(c));
210 assertEquals(true, bd.contains(c));
211 assertEquals(true, bc.contains(c));
212 assertEquals(false, ab.contains(c));
213 assertEquals(false, de.contains(c));
214
215 assertEquals(true, ae.contains(b));
216 assertEquals(true, ae.contains(ab));
217 assertEquals(true, ae.contains(bc));
218 assertEquals(true, ae.contains(cd));
219 assertEquals(true, ae.contains(de));
220
221 CharRange notb = CharRange.isNot('b');
222 CharRange notc = CharRange.isNot('c');
223 CharRange notd = CharRange.isNot('d');
224 CharRange notab = CharRange.isNotIn('a', 'b');
225 CharRange notbc = CharRange.isNotIn('b', 'c');
226 CharRange notbd = CharRange.isNotIn('b', 'd');
227 CharRange notcd = CharRange.isNotIn('c', 'd');
228 CharRange notde = CharRange.isNotIn('d', 'e');
229 CharRange notae = CharRange.isNotIn('a', 'e');
230 CharRange all = CharRange.isIn((char) 0, Character.MAX_VALUE);
231 CharRange allbutfirst = CharRange.isIn((char) 1, Character.MAX_VALUE);
232
233 // normal/negated
234 assertEquals(false, c.contains(notc));
235 assertEquals(false, c.contains(notbd));
236 assertEquals(true, all.contains(notc));
237 assertEquals(true, all.contains(notbd));
238 assertEquals(false, allbutfirst.contains(notc));
239 assertEquals(false, allbutfirst.contains(notbd));
240
241 // negated/normal
242 assertEquals(true, notc.contains(a));
243 assertEquals(true, notc.contains(b));
244 assertEquals(false, notc.contains(c));
245 assertEquals(true, notc.contains(d));
246 assertEquals(true, notc.contains(e));
247
248 assertEquals(true, notc.contains(ab));
249 assertEquals(false, notc.contains(bc));
250 assertEquals(false, notc.contains(bd));
251 assertEquals(false, notc.contains(cd));
252 assertEquals(true, notc.contains(de));
253 assertEquals(false, notc.contains(ae));
254 assertEquals(false, notc.contains(all));
255 assertEquals(false, notc.contains(allbutfirst));
256
257 assertEquals(true, notbd.contains(a));
258 assertEquals(false, notbd.contains(b));
259 assertEquals(false, notbd.contains(c));
260 assertEquals(false, notbd.contains(d));
261 assertEquals(true, notbd.contains(e));
262
263 assertEquals(true, notcd.contains(ab));
264 assertEquals(false, notcd.contains(bc));
265 assertEquals(false, notcd.contains(bd));
266 assertEquals(false, notcd.contains(cd));
267 assertEquals(false, notcd.contains(de));
268 assertEquals(false, notcd.contains(ae));
269 assertEquals(true, notcd.contains(ef));
270 assertEquals(false, notcd.contains(all));
271 assertEquals(false, notcd.contains(allbutfirst));
272
273 // negated/negated
274 assertEquals(false, notc.contains(notb));
275 assertEquals(true, notc.contains(notc));
276 assertEquals(false, notc.contains(notd));
277
278 assertEquals(false, notc.contains(notab));
279 assertEquals(true, notc.contains(notbc));
280 assertEquals(true, notc.contains(notbd));
281 assertEquals(true, notc.contains(notcd));
282 assertEquals(false, notc.contains(notde));
283
284 assertEquals(false, notbd.contains(notb));
285 assertEquals(false, notbd.contains(notc));
286 assertEquals(false, notbd.contains(notd));
287
288 assertEquals(false, notbd.contains(notab));
289 assertEquals(false, notbd.contains(notbc));
290 assertEquals(true, notbd.contains(notbd));
291 assertEquals(false, notbd.contains(notcd));
292 assertEquals(false, notbd.contains(notde));
293 assertEquals(true, notbd.contains(notae));
294 }
295
296 public void testContainsNullArg() {
297 CharRange range = CharRange.is('a');
298 try {
299 @SuppressWarnings("unused")
300 boolean contains = range.contains(null);
301 } catch(IllegalArgumentException e) {
302 assertEquals("The Range must not be null", e.getMessage());
303 }
304 }
305
306 public void testIterator() {
307 CharRange a = CharRange.is('a');
308 CharRange ad = CharRange.isIn('a', 'd');
309 CharRange nota = CharRange.isNot('a');
310 CharRange emptySet = CharRange.isNotIn((char) 0, Character.MAX_VALUE);
311 CharRange notFirst = CharRange.isNotIn((char) 1, Character.MAX_VALUE);
312 CharRange notLast = CharRange.isNotIn((char) 0, (char) (Character.MAX_VALUE - 1));
313
314 Iterator<Character> aIt = a.iterator();
315 assertNotNull(aIt);
316 assertTrue(aIt.hasNext());
317 assertEquals(Character.valueOf('a'), aIt.next());
318 assertFalse(aIt.hasNext());
319
320 Iterator<Character> adIt = ad.iterator();
321 assertNotNull(adIt);
322 assertTrue(adIt.hasNext());
323 assertEquals(Character.valueOf('a'), adIt.next());
324 assertEquals(Character.valueOf('b'), adIt.next());
325 assertEquals(Character.valueOf('c'), adIt.next());
326 assertEquals(Character.valueOf('d'), adIt.next());
327 assertFalse(adIt.hasNext());
328
329 Iterator<Character> notaIt = nota.iterator();
330 assertNotNull(notaIt);
331 assertTrue(notaIt.hasNext());
332 while (notaIt.hasNext()) {
333 Character c = notaIt.next();
334 assertFalse('a' == c.charValue());
335 }
336
337 Iterator<Character> emptySetIt = emptySet.iterator();
338 assertNotNull(emptySetIt);
339 assertFalse(emptySetIt.hasNext());
340 try {
341 emptySetIt.next();
342 fail("Should throw NoSuchElementException");
343 } catch (NoSuchElementException e) {
344 assertTrue(true);
345 }
346
347 Iterator<Character> notFirstIt = notFirst.iterator();
348 assertNotNull(notFirstIt);
349 assertTrue(notFirstIt.hasNext());
350 assertEquals(Character.valueOf((char) 0), notFirstIt.next());
351 assertFalse(notFirstIt.hasNext());
352 try {
353 notFirstIt.next();
354 fail("Should throw NoSuchElementException");
355 } catch (NoSuchElementException e) {
356 assertTrue(true);
357 }
358
359 Iterator<Character> notLastIt = notLast.iterator();
360 assertNotNull(notLastIt);
361 assertTrue(notLastIt.hasNext());
362 assertEquals(Character.valueOf(Character.MAX_VALUE), notLastIt.next());
363 assertFalse(notLastIt.hasNext());
364 try {
365 notLastIt.next();
366 fail("Should throw NoSuchElementException");
367 } catch (NoSuchElementException e) {
368 assertTrue(true);
369 }
370 }
371
372 //-----------------------------------------------------------------------
373 public void testSerialization() {
374 CharRange range = CharRange.is('a');
375 assertEquals(range, SerializationUtils.clone(range));
376 range = CharRange.isIn('a', 'e');
377 assertEquals(range, SerializationUtils.clone(range));
378 range = CharRange.isNotIn('a', 'e');
379 assertEquals(range, SerializationUtils.clone(range));
380 }
381
382 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.Modifier;
20
21 import junit.framework.Assert;
22 import junit.framework.TestCase;
23
24 /**
25 * Tests CharSequenceUtils
26 *
27 * @version $Id: CharSequenceUtilsTest.java 1066341 2011-02-02 06:21:53Z bayard $
28 */
29 public class CharSequenceUtilsTest extends TestCase {
30
31 //-----------------------------------------------------------------------
32 public void testConstructor() {
33 assertNotNull(new CharSequenceUtils());
34 Constructor<?>[] cons = CharSequenceUtils.class.getDeclaredConstructors();
35 assertEquals(1, cons.length);
36 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
37 assertEquals(true, Modifier.isPublic(CharSequenceUtils.class.getModifiers()));
38 assertEquals(false, Modifier.isFinal(CharSequenceUtils.class.getModifiers()));
39 }
40
41 //-----------------------------------------------------------------------
42 public void testSubSequence() {
43 //
44 // null input
45 //
46 Assert.assertEquals(null, CharSequenceUtils.subSequence(null, -1));
47 Assert.assertEquals(null, CharSequenceUtils.subSequence(null, 0));
48 Assert.assertEquals(null, CharSequenceUtils.subSequence(null, 1));
49 //
50 // non-null input
51 //
52 Assert.assertEquals(StringUtils.EMPTY, CharSequenceUtils.subSequence(StringUtils.EMPTY, 0));
53 Assert.assertEquals("012", CharSequenceUtils.subSequence("012", 0));
54 Assert.assertEquals("12", CharSequenceUtils.subSequence("012", 1));
55 Assert.assertEquals("2", CharSequenceUtils.subSequence("012", 2));
56 Assert.assertEquals(StringUtils.EMPTY, CharSequenceUtils.subSequence("012", 3));
57 //
58 // Exception expected
59 //
60 try {
61 Assert.assertEquals(null, CharSequenceUtils.subSequence(StringUtils.EMPTY, -1));
62 Assert.fail("Expected " + IndexOutOfBoundsException.class.getName());
63 } catch (IndexOutOfBoundsException e) {
64 // Expected
65 }
66 try {
67 Assert.assertEquals(null, CharSequenceUtils.subSequence(StringUtils.EMPTY, 1));
68 Assert.fail("Expected " + IndexOutOfBoundsException.class.getName());
69 } catch (IndexOutOfBoundsException e) {
70 // Expected
71 }
72 }
73
74 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one
2 * or more contributor license agreements. See the NOTICE file
3 * distributed with this work for additional information
4 * regarding copyright ownership. The ASF licenses this file
5 * to you under the Apache License, Version 2.0 (the
6 * "License"); you may not use this file except in compliance
7 * with the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 package org.apache.commons.lang3;
19
20 import java.lang.reflect.Modifier;
21
22 import junit.framework.TestCase;
23
24 /**
25 * Unit tests {@link org.apache.commons.lang3.CharSet}.
26 *
27 * @version $Id: CharSetTest.java 1088899 2011-04-05 05:31:27Z bayard $
28 */
29 public class CharSetTest extends TestCase {
30
31 public CharSetTest(String name) {
32 super(name);
33 }
34
35 //-----------------------------------------------------------------------
36 public void testClass() {
37 assertEquals(true, Modifier.isPublic(CharSet.class.getModifiers()));
38 assertEquals(false, Modifier.isFinal(CharSet.class.getModifiers()));
39 }
40
41 //-----------------------------------------------------------------------
42 public void testGetInstance() {
43 assertSame(CharSet.EMPTY, CharSet.getInstance( (String) null));
44 assertSame(CharSet.EMPTY, CharSet.getInstance(""));
45 assertSame(CharSet.ASCII_ALPHA, CharSet.getInstance("a-zA-Z"));
46 assertSame(CharSet.ASCII_ALPHA, CharSet.getInstance("A-Za-z"));
47 assertSame(CharSet.ASCII_ALPHA_LOWER, CharSet.getInstance("a-z"));
48 assertSame(CharSet.ASCII_ALPHA_UPPER, CharSet.getInstance("A-Z"));
49 assertSame(CharSet.ASCII_NUMERIC, CharSet.getInstance("0-9"));
50 }
51
52 //-----------------------------------------------------------------------
53 public void testGetInstance_Stringarray() {
54 assertEquals(null, CharSet.getInstance((String[]) null));
55 assertEquals("[]", CharSet.getInstance(new String[0]).toString());
56 assertEquals("[]", CharSet.getInstance(new String[] {null}).toString());
57 assertEquals("[a-e]", CharSet.getInstance(new String[] {"a-e"}).toString());
58 }
59
60 //-----------------------------------------------------------------------
61 public void testConstructor_String_simple() {
62 CharSet set;
63 CharRange[] array;
64
65 set = CharSet.getInstance((String) null);
66 array = set.getCharRanges();
67 assertEquals("[]", set.toString());
68 assertEquals(0, array.length);
69
70 set = CharSet.getInstance("");
71 array = set.getCharRanges();
72 assertEquals("[]", set.toString());
73 assertEquals(0, array.length);
74
75 set = CharSet.getInstance("a");
76 array = set.getCharRanges();
77 assertEquals("[a]", set.toString());
78 assertEquals(1, array.length);
79 assertEquals("a", array[0].toString());
80
81 set = CharSet.getInstance("^a");
82 array = set.getCharRanges();
83 assertEquals("[^a]", set.toString());
84 assertEquals(1, array.length);
85 assertEquals("^a", array[0].toString());
86
87 set = CharSet.getInstance("a-e");
88 array = set.getCharRanges();
89 assertEquals("[a-e]", set.toString());
90 assertEquals(1, array.length);
91 assertEquals("a-e", array[0].toString());
92
93 set = CharSet.getInstance("^a-e");
94 array = set.getCharRanges();
95 assertEquals("[^a-e]", set.toString());
96 assertEquals(1, array.length);
97 assertEquals("^a-e", array[0].toString());
98 }
99
100 public void testConstructor_String_combo() {
101 CharSet set;
102 CharRange[] array;
103
104 set = CharSet.getInstance("abc");
105 array = set.getCharRanges();
106 assertEquals(3, array.length);
107 assertEquals(true, ArrayUtils.contains(array, CharRange.is('a')));
108 assertEquals(true, ArrayUtils.contains(array, CharRange.is('b')));
109 assertEquals(true, ArrayUtils.contains(array, CharRange.is('c')));
110
111 set = CharSet.getInstance("a-ce-f");
112 array = set.getCharRanges();
113 assertEquals(2, array.length);
114 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('a', 'c')));
115 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('e', 'f')));
116
117 set = CharSet.getInstance("ae-f");
118 array = set.getCharRanges();
119 assertEquals(2, array.length);
120 assertEquals(true, ArrayUtils.contains(array, CharRange.is('a')));
121 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('e', 'f')));
122
123 set = CharSet.getInstance("e-fa");
124 array = set.getCharRanges();
125 assertEquals(2, array.length);
126 assertEquals(true, ArrayUtils.contains(array, CharRange.is('a')));
127 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('e', 'f')));
128
129 set = CharSet.getInstance("ae-fm-pz");
130 array = set.getCharRanges();
131 assertEquals(4, array.length);
132 assertEquals(true, ArrayUtils.contains(array, CharRange.is('a')));
133 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('e', 'f')));
134 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('m', 'p')));
135 assertEquals(true, ArrayUtils.contains(array, CharRange.is('z')));
136 }
137
138 public void testConstructor_String_comboNegated() {
139 CharSet set;
140 CharRange[] array;
141
142 set = CharSet.getInstance("^abc");
143 array = set.getCharRanges();
144 assertEquals(3, array.length);
145 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('a')));
146 assertEquals(true, ArrayUtils.contains(array, CharRange.is('b')));
147 assertEquals(true, ArrayUtils.contains(array, CharRange.is('c')));
148
149 set = CharSet.getInstance("b^ac");
150 array = set.getCharRanges();
151 assertEquals(3, array.length);
152 assertEquals(true, ArrayUtils.contains(array, CharRange.is('b')));
153 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('a')));
154 assertEquals(true, ArrayUtils.contains(array, CharRange.is('c')));
155
156 set = CharSet.getInstance("db^ac");
157 array = set.getCharRanges();
158 assertEquals(4, array.length);
159 assertEquals(true, ArrayUtils.contains(array, CharRange.is('d')));
160 assertEquals(true, ArrayUtils.contains(array, CharRange.is('b')));
161 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('a')));
162 assertEquals(true, ArrayUtils.contains(array, CharRange.is('c')));
163
164 set = CharSet.getInstance("^b^a");
165 array = set.getCharRanges();
166 assertEquals(2, array.length);
167 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('b')));
168 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('a')));
169
170 set = CharSet.getInstance("b^a-c^z");
171 array = set.getCharRanges();
172 assertEquals(3, array.length);
173 assertEquals(true, ArrayUtils.contains(array, CharRange.isNotIn('a', 'c')));
174 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('z')));
175 assertEquals(true, ArrayUtils.contains(array, CharRange.is('b')));
176 }
177
178 public void testConstructor_String_oddDash() {
179 CharSet set;
180 CharRange[] array;
181
182 set = CharSet.getInstance("-");
183 array = set.getCharRanges();
184 assertEquals(1, array.length);
185 assertEquals(true, ArrayUtils.contains(array, CharRange.is('-')));
186
187 set = CharSet.getInstance("--");
188 array = set.getCharRanges();
189 assertEquals(1, array.length);
190 assertEquals(true, ArrayUtils.contains(array, CharRange.is('-')));
191
192 set = CharSet.getInstance("---");
193 array = set.getCharRanges();
194 assertEquals(1, array.length);
195 assertEquals(true, ArrayUtils.contains(array, CharRange.is('-')));
196
197 set = CharSet.getInstance("----");
198 array = set.getCharRanges();
199 assertEquals(1, array.length);
200 assertEquals(true, ArrayUtils.contains(array, CharRange.is('-')));
201
202 set = CharSet.getInstance("-a");
203 array = set.getCharRanges();
204 assertEquals(2, array.length);
205 assertEquals(true, ArrayUtils.contains(array, CharRange.is('-')));
206 assertEquals(true, ArrayUtils.contains(array, CharRange.is('a')));
207
208 set = CharSet.getInstance("a-");
209 array = set.getCharRanges();
210 assertEquals(2, array.length);
211 assertEquals(true, ArrayUtils.contains(array, CharRange.is('a')));
212 assertEquals(true, ArrayUtils.contains(array, CharRange.is('-')));
213
214 set = CharSet.getInstance("a--");
215 array = set.getCharRanges();
216 assertEquals(1, array.length);
217 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('a', '-')));
218
219 set = CharSet.getInstance("--a");
220 array = set.getCharRanges();
221 assertEquals(1, array.length);
222 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('-', 'a')));
223 }
224
225 public void testConstructor_String_oddNegate() {
226 CharSet set;
227 CharRange[] array;
228 set = CharSet.getInstance("^");
229 array = set.getCharRanges();
230 assertEquals(1, array.length);
231 assertEquals(true, ArrayUtils.contains(array, CharRange.is('^'))); // "^"
232
233 set = CharSet.getInstance("^^");
234 array = set.getCharRanges();
235 assertEquals(1, array.length);
236 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('^'))); // "^^"
237
238 set = CharSet.getInstance("^^^");
239 array = set.getCharRanges();
240 assertEquals(2, array.length);
241 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('^'))); // "^^"
242 assertEquals(true, ArrayUtils.contains(array, CharRange.is('^'))); // "^"
243
244 set = CharSet.getInstance("^^^^");
245 array = set.getCharRanges();
246 assertEquals(1, array.length);
247 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('^'))); // "^^" x2
248
249 set = CharSet.getInstance("a^");
250 array = set.getCharRanges();
251 assertEquals(2, array.length);
252 assertEquals(true, ArrayUtils.contains(array, CharRange.is('a'))); // "a"
253 assertEquals(true, ArrayUtils.contains(array, CharRange.is('^'))); // "^"
254
255 set = CharSet.getInstance("^a-");
256 array = set.getCharRanges();
257 assertEquals(2, array.length);
258 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('a'))); // "^a"
259 assertEquals(true, ArrayUtils.contains(array, CharRange.is('-'))); // "-"
260
261 set = CharSet.getInstance("^^-c");
262 array = set.getCharRanges();
263 assertEquals(1, array.length);
264 assertEquals(true, ArrayUtils.contains(array, CharRange.isNotIn('^', 'c'))); // "^^-c"
265
266 set = CharSet.getInstance("^c-^");
267 array = set.getCharRanges();
268 assertEquals(1, array.length);
269 assertEquals(true, ArrayUtils.contains(array, CharRange.isNotIn('c', '^'))); // "^c-^"
270
271 set = CharSet.getInstance("^c-^d");
272 array = set.getCharRanges();
273 assertEquals(2, array.length);
274 assertEquals(true, ArrayUtils.contains(array, CharRange.isNotIn('c', '^'))); // "^c-^"
275 assertEquals(true, ArrayUtils.contains(array, CharRange.is('d'))); // "d"
276
277 set = CharSet.getInstance("^^-");
278 array = set.getCharRanges();
279 assertEquals(2, array.length);
280 assertEquals(true, ArrayUtils.contains(array, CharRange.isNot('^'))); // "^^"
281 assertEquals(true, ArrayUtils.contains(array, CharRange.is('-'))); // "-"
282 }
283
284 public void testConstructor_String_oddCombinations() {
285 CharSet set;
286 CharRange[] array = null;
287
288 set = CharSet.getInstance("a-^c");
289 array = set.getCharRanges();
290 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('a', '^'))); // "a-^"
291 assertEquals(true, ArrayUtils.contains(array, CharRange.is('c'))); // "c"
292 assertEquals(false, set.contains('b'));
293 assertEquals(true, set.contains('^'));
294 assertEquals(true, set.contains('_')); // between ^ and a
295 assertEquals(true, set.contains('c'));
296
297 set = CharSet.getInstance("^a-^c");
298 array = set.getCharRanges();
299 assertEquals(true, ArrayUtils.contains(array, CharRange.isNotIn('a', '^'))); // "^a-^"
300 assertEquals(true, ArrayUtils.contains(array, CharRange.is('c'))); // "c"
301 assertEquals(true, set.contains('b'));
302 assertEquals(false, set.contains('^'));
303 assertEquals(false, set.contains('_')); // between ^ and a
304
305 set = CharSet.getInstance("a- ^-- "); //contains everything
306 array = set.getCharRanges();
307 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('a', ' '))); // "a- "
308 assertEquals(true, ArrayUtils.contains(array, CharRange.isNotIn('-', ' '))); // "^-- "
309 assertEquals(true, set.contains('#'));
310 assertEquals(true, set.contains('^'));
311 assertEquals(true, set.contains('a'));
312 assertEquals(true, set.contains('*'));
313 assertEquals(true, set.contains('A'));
314
315 set = CharSet.getInstance("^-b");
316 array = set.getCharRanges();
317 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('^','b'))); // "^-b"
318 assertEquals(true, set.contains('b'));
319 assertEquals(true, set.contains('_')); // between ^ and a
320 assertEquals(false, set.contains('A'));
321 assertEquals(true, set.contains('^'));
322
323 set = CharSet.getInstance("b-^");
324 array = set.getCharRanges();
325 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('^','b'))); // "b-^"
326 assertEquals(true, set.contains('b'));
327 assertEquals(true, set.contains('^'));
328 assertEquals(true, set.contains('a')); // between ^ and b
329 assertEquals(false, set.contains('c'));
330 }
331
332 //-----------------------------------------------------------------------
333 public void testEquals_Object() {
334 CharSet abc = CharSet.getInstance("abc");
335 CharSet abc2 = CharSet.getInstance("abc");
336 CharSet atoc = CharSet.getInstance("a-c");
337 CharSet atoc2 = CharSet.getInstance("a-c");
338 CharSet notatoc = CharSet.getInstance("^a-c");
339 CharSet notatoc2 = CharSet.getInstance("^a-c");
340
341 assertEquals(false, abc.equals(null));
342
343 assertEquals(true, abc.equals(abc));
344 assertEquals(true, abc.equals(abc2));
345 assertEquals(false, abc.equals(atoc));
346 assertEquals(false, abc.equals(notatoc));
347
348 assertEquals(false, atoc.equals(abc));
349 assertEquals(true, atoc.equals(atoc));
350 assertEquals(true, atoc.equals(atoc2));
351 assertEquals(false, atoc.equals(notatoc));
352
353 assertEquals(false, notatoc.equals(abc));
354 assertEquals(false, notatoc.equals(atoc));
355 assertEquals(true, notatoc.equals(notatoc));
356 assertEquals(true, notatoc.equals(notatoc2));
357 }
358
359 public void testHashCode() {
360 CharSet abc = CharSet.getInstance("abc");
361 CharSet abc2 = CharSet.getInstance("abc");
362 CharSet atoc = CharSet.getInstance("a-c");
363 CharSet atoc2 = CharSet.getInstance("a-c");
364 CharSet notatoc = CharSet.getInstance("^a-c");
365 CharSet notatoc2 = CharSet.getInstance("^a-c");
366
367 assertEquals(abc.hashCode(), abc.hashCode());
368 assertEquals(abc.hashCode(), abc2.hashCode());
369 assertEquals(atoc.hashCode(), atoc.hashCode());
370 assertEquals(atoc.hashCode(), atoc2.hashCode());
371 assertEquals(notatoc.hashCode(), notatoc.hashCode());
372 assertEquals(notatoc.hashCode(), notatoc2.hashCode());
373 }
374
375 //-----------------------------------------------------------------------
376 public void testContains_Char() {
377 CharSet btod = CharSet.getInstance("b-d");
378 CharSet dtob = CharSet.getInstance("d-b");
379 CharSet bcd = CharSet.getInstance("bcd");
380 CharSet bd = CharSet.getInstance("bd");
381 CharSet notbtod = CharSet.getInstance("^b-d");
382
383 assertEquals(false, btod.contains('a'));
384 assertEquals(true, btod.contains('b'));
385 assertEquals(true, btod.contains('c'));
386 assertEquals(true, btod.contains('d'));
387 assertEquals(false, btod.contains('e'));
388
389 assertEquals(false, bcd.contains('a'));
390 assertEquals(true, bcd.contains('b'));
391 assertEquals(true, bcd.contains('c'));
392 assertEquals(true, bcd.contains('d'));
393 assertEquals(false, bcd.contains('e'));
394
395 assertEquals(false, bd.contains('a'));
396 assertEquals(true, bd.contains('b'));
397 assertEquals(false, bd.contains('c'));
398 assertEquals(true, bd.contains('d'));
399 assertEquals(false, bd.contains('e'));
400
401 assertEquals(true, notbtod.contains('a'));
402 assertEquals(false, notbtod.contains('b'));
403 assertEquals(false, notbtod.contains('c'));
404 assertEquals(false, notbtod.contains('d'));
405 assertEquals(true, notbtod.contains('e'));
406
407 assertEquals(false, dtob.contains('a'));
408 assertEquals(true, dtob.contains('b'));
409 assertEquals(true, dtob.contains('c'));
410 assertEquals(true, dtob.contains('d'));
411 assertEquals(false, dtob.contains('e'));
412
413 CharRange[] array = dtob.getCharRanges();
414 assertEquals("[b-d]", dtob.toString());
415 assertEquals(1, array.length);
416 }
417
418 //-----------------------------------------------------------------------
419 public void testSerialization() {
420 CharSet set = CharSet.getInstance("a");
421 assertEquals(set, SerializationUtils.clone(set));
422 set = CharSet.getInstance("a-e");
423 assertEquals(set, SerializationUtils.clone(set));
424 set = CharSet.getInstance("be-f^a-z");
425 assertEquals(set, SerializationUtils.clone(set));
426 }
427
428 //-----------------------------------------------------------------------
429 public void testStatics() {
430 CharRange[] array;
431
432 array = CharSet.EMPTY.getCharRanges();
433 assertEquals(0, array.length);
434
435 array = CharSet.ASCII_ALPHA.getCharRanges();
436 assertEquals(2, array.length);
437 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('a', 'z')));
438 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('A', 'Z')));
439
440 array = CharSet.ASCII_ALPHA_LOWER.getCharRanges();
441 assertEquals(1, array.length);
442 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('a', 'z')));
443
444 array = CharSet.ASCII_ALPHA_UPPER.getCharRanges();
445 assertEquals(1, array.length);
446 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('A', 'Z')));
447
448 array = CharSet.ASCII_NUMERIC.getCharRanges();
449 assertEquals(1, array.length);
450 assertEquals(true, ArrayUtils.contains(array, CharRange.isIn('0', '9')));
451 }
452
453 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.Modifier;
20
21 import junit.framework.TestCase;
22
23 /**
24 * Unit tests {@link org.apache.commons.lang3.CharSetUtils}.
25 *
26 * @version $Id: CharSetUtilsTest.java 1088899 2011-04-05 05:31:27Z bayard $
27 */
28 public class CharSetUtilsTest extends TestCase {
29
30 public CharSetUtilsTest(String name) {
31 super(name);
32 }
33
34 //-----------------------------------------------------------------------
35 public void testConstructor() {
36 assertNotNull(new CharSetUtils());
37 Constructor<?>[] cons = CharSetUtils.class.getDeclaredConstructors();
38 assertEquals(1, cons.length);
39 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
40 assertEquals(true, Modifier.isPublic(CharSetUtils.class.getModifiers()));
41 assertEquals(false, Modifier.isFinal(CharSetUtils.class.getModifiers()));
42 }
43
44 //-----------------------------------------------------------------------
45 public void testSqueeze_StringString() {
46 assertEquals(null, CharSetUtils.squeeze(null, (String) null));
47 assertEquals(null, CharSetUtils.squeeze(null, ""));
48
49 assertEquals("", CharSetUtils.squeeze("", (String) null));
50 assertEquals("", CharSetUtils.squeeze("", ""));
51 assertEquals("", CharSetUtils.squeeze("", "a-e"));
52
53 assertEquals("hello", CharSetUtils.squeeze("hello", (String) null));
54 assertEquals("hello", CharSetUtils.squeeze("hello", ""));
55 assertEquals("hello", CharSetUtils.squeeze("hello", "a-e"));
56 assertEquals("helo", CharSetUtils.squeeze("hello", "l-p"));
57 assertEquals("heloo", CharSetUtils.squeeze("helloo", "l"));
58 assertEquals("hello", CharSetUtils.squeeze("helloo", "^l"));
59 }
60
61 public void testSqueeze_StringStringarray() {
62 assertEquals(null, CharSetUtils.squeeze(null, (String[]) null));
63 assertEquals(null, CharSetUtils.squeeze(null, new String[0]));
64 assertEquals(null, CharSetUtils.squeeze(null, new String[] {null}));
65 assertEquals(null, CharSetUtils.squeeze(null, new String[] {"el"}));
66
67 assertEquals("", CharSetUtils.squeeze("", (String[]) null));
68 assertEquals("", CharSetUtils.squeeze("", new String[0]));
69 assertEquals("", CharSetUtils.squeeze("", new String[] {null}));
70 assertEquals("", CharSetUtils.squeeze("", new String[] {"a-e"}));
71
72 assertEquals("hello", CharSetUtils.squeeze("hello", (String[]) null));
73 assertEquals("hello", CharSetUtils.squeeze("hello", new String[0]));
74 assertEquals("hello", CharSetUtils.squeeze("hello", new String[] {null}));
75 assertEquals("hello", CharSetUtils.squeeze("hello", new String[] {"a-e"}));
76
77 assertEquals("helo", CharSetUtils.squeeze("hello", new String[] { "el" }));
78 assertEquals("hello", CharSetUtils.squeeze("hello", new String[] { "e" }));
79 assertEquals("fofof", CharSetUtils.squeeze("fooffooff", new String[] { "of" }));
80 assertEquals("fof", CharSetUtils.squeeze("fooooff", new String[] { "fo" }));
81 }
82
83 //-----------------------------------------------------------------------
84 public void testCount_StringString() {
85 assertEquals(0, CharSetUtils.count(null, (String) null));
86 assertEquals(0, CharSetUtils.count(null, ""));
87
88 assertEquals(0, CharSetUtils.count("", (String) null));
89 assertEquals(0, CharSetUtils.count("", ""));
90 assertEquals(0, CharSetUtils.count("", "a-e"));
91
92 assertEquals(0, CharSetUtils.count("hello", (String) null));
93 assertEquals(0, CharSetUtils.count("hello", ""));
94 assertEquals(1, CharSetUtils.count("hello", "a-e"));
95 assertEquals(3, CharSetUtils.count("hello", "l-p"));
96 }
97
98 public void testCount_StringStringarray() {
99 assertEquals(0, CharSetUtils.count(null, (String[]) null));
100 assertEquals(0, CharSetUtils.count(null, new String[0]));
101 assertEquals(0, CharSetUtils.count(null, new String[] {null}));
102 assertEquals(0, CharSetUtils.count(null, new String[] {"a-e"}));
103
104 assertEquals(0, CharSetUtils.count("", (String[]) null));
105 assertEquals(0, CharSetUtils.count("", new String[0]));
106 assertEquals(0, CharSetUtils.count("", new String[] {null}));
107 assertEquals(0, CharSetUtils.count("", new String[] {"a-e"}));
108
109 assertEquals(0, CharSetUtils.count("hello", (String[]) null));
110 assertEquals(0, CharSetUtils.count("hello", new String[0]));
111 assertEquals(0, CharSetUtils.count("hello", new String[] {null}));
112 assertEquals(1, CharSetUtils.count("hello", new String[] {"a-e"}));
113
114 assertEquals(3, CharSetUtils.count("hello", new String[] { "el" }));
115 assertEquals(0, CharSetUtils.count("hello", new String[] { "x" }));
116 assertEquals(2, CharSetUtils.count("hello", new String[] { "e-i" }));
117 assertEquals(5, CharSetUtils.count("hello", new String[] { "a-z" }));
118 assertEquals(0, CharSetUtils.count("hello", new String[] { "" }));
119 }
120
121 //-----------------------------------------------------------------------
122 public void testKeep_StringString() {
123 assertEquals(null, CharSetUtils.keep(null, (String) null));
124 assertEquals(null, CharSetUtils.keep(null, ""));
125
126 assertEquals("", CharSetUtils.keep("", (String) null));
127 assertEquals("", CharSetUtils.keep("", ""));
128 assertEquals("", CharSetUtils.keep("", "a-e"));
129
130 assertEquals("", CharSetUtils.keep("hello", (String) null));
131 assertEquals("", CharSetUtils.keep("hello", ""));
132 assertEquals("", CharSetUtils.keep("hello", "xyz"));
133 assertEquals("hello", CharSetUtils.keep("hello", "a-z"));
134 assertEquals("hello", CharSetUtils.keep("hello", "oleh"));
135 assertEquals("ell", CharSetUtils.keep("hello", "el"));
136 }
137
138 public void testKeep_StringStringarray() {
139 assertEquals(null, CharSetUtils.keep(null, (String[]) null));
140 assertEquals(null, CharSetUtils.keep(null, new String[0]));
141 assertEquals(null, CharSetUtils.keep(null, new String[] {null}));
142 assertEquals(null, CharSetUtils.keep(null, new String[] {"a-e"}));
143
144 assertEquals("", CharSetUtils.keep("", (String[]) null));
145 assertEquals("", CharSetUtils.keep("", new String[0]));
146 assertEquals("", CharSetUtils.keep("", new String[] {null}));
147 assertEquals("", CharSetUtils.keep("", new String[] {"a-e"}));
148
149 assertEquals("", CharSetUtils.keep("hello", (String[]) null));
150 assertEquals("", CharSetUtils.keep("hello", new String[0]));
151 assertEquals("", CharSetUtils.keep("hello", new String[] {null}));
152 assertEquals("e", CharSetUtils.keep("hello", new String[] {"a-e"}));
153
154 assertEquals("e", CharSetUtils.keep("hello", new String[] { "a-e" }));
155 assertEquals("ell", CharSetUtils.keep("hello", new String[] { "el" }));
156 assertEquals("hello", CharSetUtils.keep("hello", new String[] { "elho" }));
157 assertEquals("hello", CharSetUtils.keep("hello", new String[] { "a-z" }));
158 assertEquals("----", CharSetUtils.keep("----", new String[] { "-" }));
159 assertEquals("ll", CharSetUtils.keep("hello", new String[] { "l" }));
160 }
161
162 //-----------------------------------------------------------------------
163 public void testDelete_StringString() {
164 assertEquals(null, CharSetUtils.delete(null, (String) null));
165 assertEquals(null, CharSetUtils.delete(null, ""));
166
167 assertEquals("", CharSetUtils.delete("", (String) null));
168 assertEquals("", CharSetUtils.delete("", ""));
169 assertEquals("", CharSetUtils.delete("", "a-e"));
170
171 assertEquals("hello", CharSetUtils.delete("hello", (String) null));
172 assertEquals("hello", CharSetUtils.delete("hello", ""));
173 assertEquals("hllo", CharSetUtils.delete("hello", "a-e"));
174 assertEquals("he", CharSetUtils.delete("hello", "l-p"));
175 assertEquals("hello", CharSetUtils.delete("hello", "z"));
176 }
177
178 public void testDelete_StringStringarray() {
179 assertEquals(null, CharSetUtils.delete(null, (String[]) null));
180 assertEquals(null, CharSetUtils.delete(null, new String[0]));
181 assertEquals(null, CharSetUtils.delete(null, new String[] {null}));
182 assertEquals(null, CharSetUtils.delete(null, new String[] {"el"}));
183
184 assertEquals("", CharSetUtils.delete("", (String[]) null));
185 assertEquals("", CharSetUtils.delete("", new String[0]));
186 assertEquals("", CharSetUtils.delete("", new String[] {null}));
187 assertEquals("", CharSetUtils.delete("", new String[] {"a-e"}));
188
189 assertEquals("hello", CharSetUtils.delete("hello", (String[]) null));
190 assertEquals("hello", CharSetUtils.delete("hello", new String[0]));
191 assertEquals("hello", CharSetUtils.delete("hello", new String[] {null}));
192 assertEquals("hello", CharSetUtils.delete("hello", new String[] {"xyz"}));
193
194 assertEquals("ho", CharSetUtils.delete("hello", new String[] { "el" }));
195 assertEquals("", CharSetUtils.delete("hello", new String[] { "elho" }));
196 assertEquals("hello", CharSetUtils.delete("hello", new String[] { "" }));
197 assertEquals("hello", CharSetUtils.delete("hello", ""));
198 assertEquals("", CharSetUtils.delete("hello", new String[] { "a-z" }));
199 assertEquals("", CharSetUtils.delete("----", new String[] { "-" }));
200 assertEquals("heo", CharSetUtils.delete("hello", new String[] { "l" }));
201 }
202
203 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3;
18
19 import java.text.NumberFormat;
20 import java.util.Calendar;
21
22 /**
23 * Tests the difference in performance between CharUtils and CharSet.
24 *
25 * Sample runs:
26
27 Now: Thu Mar 18 14:29:48 PST 2004
28 Sun Microsystems Inc. Java(TM) 2 Runtime Environment, Standard Edition 1.3.1_10-b03
29 Sun Microsystems Inc. Java HotSpot(TM) Client VM 1.3.1_10-b03
30 Windows XP 5.1 x86 pentium i486 i386
31 Do nohting: 0 milliseconds.
32 run_CharUtils_isAsciiNumeric: 4,545 milliseconds.
33 run_inlined_CharUtils_isAsciiNumeric: 3,417 milliseconds.
34 run_inlined_CharUtils_isAsciiNumeric: 85,679 milliseconds.
35
36
37 Now: Thu Mar 18 14:24:51 PST 2004
38 Sun Microsystems Inc. Java(TM) 2 Runtime Environment, Standard Edition 1.4.2_04-b05
39 Sun Microsystems Inc. Java HotSpot(TM) Client VM 1.4.2_04-b05
40 Windows XP 5.1 x86 pentium i486 i386
41 Do nohting: 0 milliseconds.
42 run_CharUtils_isAsciiNumeric: 2,578 milliseconds.
43 run_inlined_CharUtils_isAsciiNumeric: 2,477 milliseconds.
44 run_inlined_CharUtils_isAsciiNumeric: 114,429 milliseconds.
45
46 Now: Thu Mar 18 14:27:55 PST 2004
47 Sun Microsystems Inc. Java(TM) 2 Runtime Environment, Standard Edition 1.4.2_04-b05
48 Sun Microsystems Inc. Java HotSpot(TM) Server VM 1.4.2_04-b05
49 Windows XP 5.1 x86 pentium i486 i386
50 Do nohting: 0 milliseconds.
51 run_CharUtils_isAsciiNumeric: 630 milliseconds.
52 run_inlined_CharUtils_isAsciiNumeric: 709 milliseconds.
53 run_inlined_CharUtils_isAsciiNumeric: 84,420 milliseconds.
54
55
56 * @version $Id: CharUtilsPerfRun.java 1144929 2011-07-10 18:26:16Z ggregory $
57 */
58 public class CharUtilsPerfRun {
59 final static String VERSION = "$Id: CharUtilsPerfRun.java 1144929 2011-07-10 18:26:16Z ggregory $";
60
61 final static int WARM_UP = 100;
62
63 final static int COUNT = 5000;
64
65 final static char[] CHAR_SAMPLES;
66 static {
67 CHAR_SAMPLES = new char[Character.MAX_VALUE];
68 for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
69 CHAR_SAMPLES[i] = i;
70 }
71 }
72
73 public static void main(String[] args) {
74 new CharUtilsPerfRun().run();
75 }
76
77 private void printSysInfo() {
78 System.out.println(VERSION);
79 System.out.println("Now: " + Calendar.getInstance().getTime());
80 System.out.println(System.getProperty("java.vendor")
81 + " "
82 + System.getProperty("java.runtime.name")
83 + " "
84 + System.getProperty("java.runtime.version"));
85 System.out.println(System.getProperty("java.vm.vendor")
86 + " "
87 + System.getProperty("java.vm.name")
88 + " "
89 + System.getProperty("java.vm.version"));
90 System.out.println(System.getProperty("os.name")
91 + " "
92 + System.getProperty("os.version")
93 + " "
94 + System.getProperty("os.arch")
95 + " "
96 + System.getProperty("sun.cpu.isalist"));
97 }
98
99 private void run() {
100 this.printSysInfo();
101 long start;
102 start = System.currentTimeMillis();
103 this.printlnTotal("Do nohting", start);
104 //System.out.println("Warming up...");
105 run_CharUtils_isAsciiNumeric(WARM_UP);
106 //System.out.println("Measuring...");
107 start = System.currentTimeMillis();
108 run_CharUtils_isAsciiNumeric(COUNT);
109 this.printlnTotal("run_CharUtils_isAsciiNumeric", start);
110 //System.out.println("Warming up...");
111 run_inlined_CharUtils_isAsciiNumeric(WARM_UP);
112 //System.out.println("Measuring...");
113 start = System.currentTimeMillis();
114 run_inlined_CharUtils_isAsciiNumeric(COUNT);
115 this.printlnTotal("run_inlined_CharUtils_isAsciiNumeric", start);
116 //System.out.println("Warming up...");
117 run_CharSet(WARM_UP);
118 //System.out.println("Measuring...");
119 start = System.currentTimeMillis();
120 run_CharSet(COUNT);
121 this.printlnTotal("run_CharSet", start);
122 }
123
124 private int run_CharSet(int loopCount) {
125 int t = 0;
126 for (int i = 0; i < loopCount; i++) {
127 for (char ch : CHAR_SAMPLES) {
128 boolean b = CharSet.ASCII_NUMERIC.contains(ch);
129 t += b ? 1 : 0;
130 }
131 }
132 return t;
133 }
134
135 private int run_CharUtils_isAsciiNumeric(int loopCount) {
136 int t = 0;
137 for (int i = 0; i < loopCount; i++) {
138 for (char ch : CHAR_SAMPLES) {
139 boolean b = CharUtils.isAsciiNumeric(ch);
140 t += b ? 1 : 0;
141 }
142 }
143 return t;
144 }
145
146 private int run_inlined_CharUtils_isAsciiNumeric(int loopCount) {
147 int t = 0;
148 for (int i = 0; i < loopCount; i++) {
149 for (char ch : CHAR_SAMPLES) {
150 boolean b = (ch >= '0' && ch <= '9');
151 t += b ? 1 : 0;
152 }
153 }
154 return t;
155 }
156
157 private void printlnTotal(String prefix, long start) {
158 long total = System.currentTimeMillis() - start;
159 System.out.println(prefix + ": " + NumberFormat.getInstance().format(total) + " milliseconds.");
160 }
161 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.Modifier;
20
21 import junit.framework.TestCase;
22
23 /**
24 * Unit tests {@link org.apache.commons.lang3.CharUtils}.
25 *
26 * @version $Id: CharUtilsTest.java 1088899 2011-04-05 05:31:27Z bayard $
27 */
28 public class CharUtilsTest extends TestCase {
29
30 private static final Character CHARACTER_A = new Character('A');
31 private static final Character CHARACTER_B = new Character('B');
32 private static final char CHAR_COPY = '\u00a9';
33
34 public CharUtilsTest(String name) {
35 super(name);
36 }
37
38 //-----------------------------------------------------------------------
39 public void testConstructor() {
40 assertNotNull(new CharUtils());
41 Constructor<?>[] cons = CharUtils.class.getDeclaredConstructors();
42 assertEquals(1, cons.length);
43 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
44 assertEquals(true, Modifier.isPublic(BooleanUtils.class.getModifiers()));
45 assertEquals(false, Modifier.isFinal(BooleanUtils.class.getModifiers()));
46 }
47
48 //-----------------------------------------------------------------------
49 public void testToCharacterObject_char() {
50 assertEquals(new Character('a'), CharUtils.toCharacterObject('a'));
51 assertSame(CharUtils.toCharacterObject('a'), CharUtils.toCharacterObject('a'));
52
53 for (int i = 0; i < 128; i++) {
54 Character ch = CharUtils.toCharacterObject((char) i);
55 Character ch2 = CharUtils.toCharacterObject((char) i);
56 assertSame(ch, ch2);
57 assertEquals(i, ch.charValue());
58 }
59 for (int i = 128; i < 196; i++) {
60 Character ch = CharUtils.toCharacterObject((char) i);
61 Character ch2 = CharUtils.toCharacterObject((char) i);
62 assertEquals(ch, ch2);
63 assertTrue(ch != ch2);
64 assertEquals(i, ch.charValue());
65 assertEquals(i, ch2.charValue());
66 }
67 }
68
69 public void testToCharacterObject_String() {
70 assertEquals(null, CharUtils.toCharacterObject(null));
71 assertEquals(null, CharUtils.toCharacterObject(""));
72 assertEquals(new Character('a'), CharUtils.toCharacterObject("a"));
73 assertEquals(new Character('a'), CharUtils.toCharacterObject("abc"));
74 assertSame(CharUtils.toCharacterObject("a"), CharUtils.toCharacterObject("a"));
75 assertSame(CharUtils.toCharacterObject("a"), CharUtils.toCharacterObject('a'));
76 }
77
78 //-----------------------------------------------------------------------
79 public void testToChar_Character() {
80 assertEquals('A', CharUtils.toChar(CHARACTER_A));
81 assertEquals('B', CharUtils.toChar(CHARACTER_B));
82 try {
83 CharUtils.toChar((Character) null);
84 } catch (IllegalArgumentException ex) {}
85 }
86
87 public void testToChar_Character_char() {
88 assertEquals('A', CharUtils.toChar(CHARACTER_A, 'X'));
89 assertEquals('B', CharUtils.toChar(CHARACTER_B, 'X'));
90 assertEquals('X', CharUtils.toChar((Character) null, 'X'));
91 }
92
93 //-----------------------------------------------------------------------
94 public void testToChar_String() {
95 assertEquals('A', CharUtils.toChar("A"));
96 assertEquals('B', CharUtils.toChar("BA"));
97 try {
98 CharUtils.toChar((String) null);
99 } catch (IllegalArgumentException ex) {}
100 try {
101 CharUtils.toChar("");
102 } catch (IllegalArgumentException ex) {}
103 }
104
105 public void testToChar_String_char() {
106 assertEquals('A', CharUtils.toChar("A", 'X'));
107 assertEquals('B', CharUtils.toChar("BA", 'X'));
108 assertEquals('X', CharUtils.toChar("", 'X'));
109 assertEquals('X', CharUtils.toChar((String) null, 'X'));
110 }
111
112 //-----------------------------------------------------------------------
113 public void testToIntValue_char() {
114 assertEquals(0, CharUtils.toIntValue('0'));
115 assertEquals(1, CharUtils.toIntValue('1'));
116 assertEquals(2, CharUtils.toIntValue('2'));
117 assertEquals(3, CharUtils.toIntValue('3'));
118 assertEquals(4, CharUtils.toIntValue('4'));
119 assertEquals(5, CharUtils.toIntValue('5'));
120 assertEquals(6, CharUtils.toIntValue('6'));
121 assertEquals(7, CharUtils.toIntValue('7'));
122 assertEquals(8, CharUtils.toIntValue('8'));
123 assertEquals(9, CharUtils.toIntValue('9'));
124 try {
125 CharUtils.toIntValue('a');
126 } catch (IllegalArgumentException ex) {}
127 }
128
129 public void testToIntValue_char_int() {
130 assertEquals(0, CharUtils.toIntValue('0', -1));
131 assertEquals(3, CharUtils.toIntValue('3', -1));
132 assertEquals(-1, CharUtils.toIntValue('a', -1));
133 }
134
135 //-----------------------------------------------------------------------
136 public void testToIntValue_Character() {
137 assertEquals(0, CharUtils.toIntValue(new Character('0')));
138 assertEquals(3, CharUtils.toIntValue(new Character('3')));
139 try {
140 CharUtils.toIntValue(null);
141 } catch (IllegalArgumentException ex) {}
142 try {
143 CharUtils.toIntValue(CHARACTER_A);
144 } catch (IllegalArgumentException ex) {}
145 }
146
147 public void testToIntValue_Character_int() {
148 assertEquals(0, CharUtils.toIntValue(new Character('0'), -1));
149 assertEquals(3, CharUtils.toIntValue(new Character('3'), -1));
150 assertEquals(-1, CharUtils.toIntValue(new Character('A'), -1));
151 assertEquals(-1, CharUtils.toIntValue(null, -1));
152 }
153
154 //-----------------------------------------------------------------------
155 public void testToString_char() {
156 assertEquals("a", CharUtils.toString('a'));
157 assertSame(CharUtils.toString('a'), CharUtils.toString('a'));
158
159 for (int i = 0; i < 128; i++) {
160 String str = CharUtils.toString((char) i);
161 String str2 = CharUtils.toString((char) i);
162 assertSame(str, str2);
163 assertEquals(1, str.length());
164 assertEquals(i, str.charAt(0));
165 }
166 for (int i = 128; i < 196; i++) {
167 String str = CharUtils.toString((char) i);
168 String str2 = CharUtils.toString((char) i);
169 assertEquals(str, str2);
170 assertTrue(str != str2);
171 assertEquals(1, str.length());
172 assertEquals(i, str.charAt(0));
173 assertEquals(1, str2.length());
174 assertEquals(i, str2.charAt(0));
175 }
176 }
177
178 public void testToString_Character() {
179 assertEquals(null, CharUtils.toString(null));
180 assertEquals("A", CharUtils.toString(CHARACTER_A));
181 assertSame(CharUtils.toString(CHARACTER_A), CharUtils.toString(CHARACTER_A));
182 }
183
184 //-----------------------------------------------------------------------
185 public void testToUnicodeEscaped_char() {
186 assertEquals("\\u0041", CharUtils.unicodeEscaped('A'));
187
188 for (int i = 0; i < 196; i++) {
189 String str = CharUtils.unicodeEscaped((char) i);
190 assertEquals(6, str.length());
191 int val = Integer.parseInt(str.substring(2), 16);
192 assertEquals(i, val);
193 }
194 assertEquals("\\u0999", CharUtils.unicodeEscaped((char) 0x999));
195 assertEquals("\\u1001", CharUtils.unicodeEscaped((char) 0x1001));
196 }
197
198 public void testToUnicodeEscaped_Character() {
199 assertEquals(null, CharUtils.unicodeEscaped(null));
200 assertEquals("\\u0041", CharUtils.unicodeEscaped(CHARACTER_A));
201 }
202
203 //-----------------------------------------------------------------------
204 public void testIsAscii_char() {
205 assertEquals(true, CharUtils.isAscii('a'));
206 assertEquals(true, CharUtils.isAscii('A'));
207 assertEquals(true, CharUtils.isAscii('3'));
208 assertEquals(true, CharUtils.isAscii('-'));
209 assertEquals(true, CharUtils.isAscii('\n'));
210 assertEquals(false, CharUtils.isAscii(CHAR_COPY));
211
212 for (int i = 0; i < 128; i++) {
213 if (i < 128) {
214 assertEquals(true, CharUtils.isAscii((char) i));
215 } else {
216 assertEquals(false, CharUtils.isAscii((char) i));
217 }
218 }
219 }
220
221 //-----------------------------------------------------------------------
222 public void testIsAsciiPrintable_char() {
223 assertEquals(true, CharUtils.isAsciiPrintable('a'));
224 assertEquals(true, CharUtils.isAsciiPrintable('A'));
225 assertEquals(true, CharUtils.isAsciiPrintable('3'));
226 assertEquals(true, CharUtils.isAsciiPrintable('-'));
227 assertEquals(false, CharUtils.isAsciiPrintable('\n'));
228 assertEquals(false, CharUtils.isAscii(CHAR_COPY));
229
230 for (int i = 0; i < 196; i++) {
231 if (i >= 32 && i <= 126) {
232 assertEquals(true, CharUtils.isAsciiPrintable((char) i));
233 } else {
234 assertEquals(false, CharUtils.isAsciiPrintable((char) i));
235 }
236 }
237 }
238
239 //-----------------------------------------------------------------------
240 public void testIsAsciiControl_char() {
241 assertEquals(false, CharUtils.isAsciiControl('a'));
242 assertEquals(false, CharUtils.isAsciiControl('A'));
243 assertEquals(false, CharUtils.isAsciiControl('3'));
244 assertEquals(false, CharUtils.isAsciiControl('-'));
245 assertEquals(true, CharUtils.isAsciiControl('\n'));
246 assertEquals(false, CharUtils.isAsciiControl(CHAR_COPY));
247
248 for (int i = 0; i < 196; i++) {
249 if (i < 32 || i == 127) {
250 assertEquals(true, CharUtils.isAsciiControl((char) i));
251 } else {
252 assertEquals(false, CharUtils.isAsciiControl((char) i));
253 }
254 }
255 }
256
257 //-----------------------------------------------------------------------
258 public void testIsAsciiAlpha_char() {
259 assertEquals(true, CharUtils.isAsciiAlpha('a'));
260 assertEquals(true, CharUtils.isAsciiAlpha('A'));
261 assertEquals(false, CharUtils.isAsciiAlpha('3'));
262 assertEquals(false, CharUtils.isAsciiAlpha('-'));
263 assertEquals(false, CharUtils.isAsciiAlpha('\n'));
264 assertEquals(false, CharUtils.isAsciiAlpha(CHAR_COPY));
265
266 for (int i = 0; i < 196; i++) {
267 if ((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z')) {
268 assertEquals(true, CharUtils.isAsciiAlpha((char) i));
269 } else {
270 assertEquals(false, CharUtils.isAsciiAlpha((char) i));
271 }
272 }
273 }
274
275 //-----------------------------------------------------------------------
276 public void testIsAsciiAlphaUpper_char() {
277 assertEquals(false, CharUtils.isAsciiAlphaUpper('a'));
278 assertEquals(true, CharUtils.isAsciiAlphaUpper('A'));
279 assertEquals(false, CharUtils.isAsciiAlphaUpper('3'));
280 assertEquals(false, CharUtils.isAsciiAlphaUpper('-'));
281 assertEquals(false, CharUtils.isAsciiAlphaUpper('\n'));
282 assertEquals(false, CharUtils.isAsciiAlphaUpper(CHAR_COPY));
283
284 for (int i = 0; i < 196; i++) {
285 if (i >= 'A' && i <= 'Z') {
286 assertEquals(true, CharUtils.isAsciiAlphaUpper((char) i));
287 } else {
288 assertEquals(false, CharUtils.isAsciiAlphaUpper((char) i));
289 }
290 }
291 }
292
293 //-----------------------------------------------------------------------
294 public void testIsAsciiAlphaLower_char() {
295 assertEquals(true, CharUtils.isAsciiAlphaLower('a'));
296 assertEquals(false, CharUtils.isAsciiAlphaLower('A'));
297 assertEquals(false, CharUtils.isAsciiAlphaLower('3'));
298 assertEquals(false, CharUtils.isAsciiAlphaLower('-'));
299 assertEquals(false, CharUtils.isAsciiAlphaLower('\n'));
300 assertEquals(false, CharUtils.isAsciiAlphaLower(CHAR_COPY));
301
302 for (int i = 0; i < 196; i++) {
303 if (i >= 'a' && i <= 'z') {
304 assertEquals(true, CharUtils.isAsciiAlphaLower((char) i));
305 } else {
306 assertEquals(false, CharUtils.isAsciiAlphaLower((char) i));
307 }
308 }
309 }
310
311 //-----------------------------------------------------------------------
312 public void testIsAsciiNumeric_char() {
313 assertEquals(false, CharUtils.isAsciiNumeric('a'));
314 assertEquals(false, CharUtils.isAsciiNumeric('A'));
315 assertEquals(true, CharUtils.isAsciiNumeric('3'));
316 assertEquals(false, CharUtils.isAsciiNumeric('-'));
317 assertEquals(false, CharUtils.isAsciiNumeric('\n'));
318 assertEquals(false, CharUtils.isAsciiNumeric(CHAR_COPY));
319
320 for (int i = 0; i < 196; i++) {
321 if (i >= '0' && i <= '9') {
322 assertEquals(true, CharUtils.isAsciiNumeric((char) i));
323 } else {
324 assertEquals(false, CharUtils.isAsciiNumeric((char) i));
325 }
326 }
327 }
328
329 //-----------------------------------------------------------------------
330 public void testIsAsciiAlphanumeric_char() {
331 assertEquals(true, CharUtils.isAsciiAlphanumeric('a'));
332 assertEquals(true, CharUtils.isAsciiAlphanumeric('A'));
333 assertEquals(true, CharUtils.isAsciiAlphanumeric('3'));
334 assertEquals(false, CharUtils.isAsciiAlphanumeric('-'));
335 assertEquals(false, CharUtils.isAsciiAlphanumeric('\n'));
336 assertEquals(false, CharUtils.isAsciiAlphanumeric(CHAR_COPY));
337
338 for (int i = 0; i < 196; i++) {
339 if ((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z') || (i >= '0' && i <= '9')) {
340 assertEquals(true, CharUtils.isAsciiAlphanumeric((char) i));
341 } else {
342 assertEquals(false, CharUtils.isAsciiAlphanumeric((char) i));
343 }
344 }
345 }
346
347 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import static org.apache.commons.lang3.JavaVersion.JAVA_1_5;
19
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Modifier;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30
31 import junit.framework.TestCase;
32
33 /**
34 * Unit tests {@link org.apache.commons.lang3.ClassUtils}.
35 *
36 * @version $Id: ClassUtilsTest.java 1144929 2011-07-10 18:26:16Z ggregory $
37 */
38 public class ClassUtilsTest extends TestCase {
39
40 public ClassUtilsTest(String name) {
41 super(name);
42 }
43
44 private static class Inner {
45 private class DeeplyNested{}
46 }
47
48 //-----------------------------------------------------------------------
49 public void testConstructor() {
50 assertNotNull(new ClassUtils());
51 Constructor<?>[] cons = ClassUtils.class.getDeclaredConstructors();
52 assertEquals(1, cons.length);
53 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
54 assertEquals(true, Modifier.isPublic(ClassUtils.class.getModifiers()));
55 assertEquals(false, Modifier.isFinal(ClassUtils.class.getModifiers()));
56 }
57
58 // -------------------------------------------------------------------------
59 public void test_getShortClassName_Object() {
60 assertEquals("ClassUtils", ClassUtils.getShortClassName(new ClassUtils(), "<null>"));
61 assertEquals("ClassUtilsTest.Inner", ClassUtils.getShortClassName(new Inner(), "<null>"));
62 assertEquals("String", ClassUtils.getShortClassName("hello", "<null>"));
63 assertEquals("<null>", ClassUtils.getShortClassName(null, "<null>"));
64
65 // Inner types
66 class Named extends Object {};
67 assertEquals("ClassUtilsTest.1", ClassUtils.getShortClassName(new Object(){}, "<null>"));
68 assertEquals("ClassUtilsTest.1Named", ClassUtils.getShortClassName(new Named(), "<null>"));
69 assertEquals("ClassUtilsTest.Inner", ClassUtils.getShortClassName(new Inner(), "<null>"));
70 }
71
72 public void test_getShortClassName_Class() {
73 assertEquals("ClassUtils", ClassUtils.getShortClassName(ClassUtils.class));
74 assertEquals("Map.Entry", ClassUtils.getShortClassName(Map.Entry.class));
75 assertEquals("", ClassUtils.getShortClassName((Class<?>) null));
76
77 // LANG-535
78 assertEquals("String[]", ClassUtils.getShortClassName(String[].class));
79 assertEquals("Map.Entry[]", ClassUtils.getShortClassName(Map.Entry[].class));
80
81 // Primitives
82 assertEquals("boolean", ClassUtils.getShortClassName(boolean.class));
83 assertEquals("byte", ClassUtils.getShortClassName(byte.class));
84 assertEquals("char", ClassUtils.getShortClassName(char.class));
85 assertEquals("short", ClassUtils.getShortClassName(short.class));
86 assertEquals("int", ClassUtils.getShortClassName(int.class));
87 assertEquals("long", ClassUtils.getShortClassName(long.class));
88 assertEquals("float", ClassUtils.getShortClassName(float.class));
89 assertEquals("double", ClassUtils.getShortClassName(double.class));
90
91 // Primitive Arrays
92 assertEquals("boolean[]", ClassUtils.getShortClassName(boolean[].class));
93 assertEquals("byte[]", ClassUtils.getShortClassName(byte[].class));
94 assertEquals("char[]", ClassUtils.getShortClassName(char[].class));
95 assertEquals("short[]", ClassUtils.getShortClassName(short[].class));
96 assertEquals("int[]", ClassUtils.getShortClassName(int[].class));
97 assertEquals("long[]", ClassUtils.getShortClassName(long[].class));
98 assertEquals("float[]", ClassUtils.getShortClassName(float[].class));
99 assertEquals("double[]", ClassUtils.getShortClassName(double[].class));
100
101 // Arrays of arrays of ...
102 assertEquals("String[][]", ClassUtils.getShortClassName(String[][].class));
103 assertEquals("String[][][]", ClassUtils.getShortClassName(String[][][].class));
104 assertEquals("String[][][][]", ClassUtils.getShortClassName(String[][][][].class));
105
106 // Inner types
107 class Named extends Object {};
108 assertEquals("ClassUtilsTest.2", ClassUtils.getShortClassName(new Object(){}.getClass()));
109 assertEquals("ClassUtilsTest.2Named", ClassUtils.getShortClassName(Named.class));
110 assertEquals("ClassUtilsTest.Inner", ClassUtils.getShortClassName(Inner.class));
111 }
112
113
114
115 public void test_getShortClassName_String() {
116 assertEquals("ClassUtils", ClassUtils.getShortClassName(ClassUtils.class.getName()));
117 assertEquals("Map.Entry", ClassUtils.getShortClassName(Map.Entry.class.getName()));
118 assertEquals("", ClassUtils.getShortClassName((String) null));
119 assertEquals("", ClassUtils.getShortClassName(""));
120 }
121
122 public void test_getSimpleName_Class() {
123 assertEquals("ClassUtils", ClassUtils.getSimpleName(ClassUtils.class));
124 assertEquals("Entry", ClassUtils.getSimpleName(Map.Entry.class));
125 assertEquals("", ClassUtils.getSimpleName((Class<?>) null));
126
127 // LANG-535
128 assertEquals("String[]", ClassUtils.getSimpleName(String[].class));
129 assertEquals("Entry[]", ClassUtils.getSimpleName(Map.Entry[].class));
130
131 // Primitives
132 assertEquals("boolean", ClassUtils.getSimpleName(boolean.class));
133 assertEquals("byte", ClassUtils.getSimpleName(byte.class));
134 assertEquals("char", ClassUtils.getSimpleName(char.class));
135 assertEquals("short", ClassUtils.getSimpleName(short.class));
136 assertEquals("int", ClassUtils.getSimpleName(int.class));
137 assertEquals("long", ClassUtils.getSimpleName(long.class));
138 assertEquals("float", ClassUtils.getSimpleName(float.class));
139 assertEquals("double", ClassUtils.getSimpleName(double.class));
140
141 // Primitive Arrays
142 assertEquals("boolean[]", ClassUtils.getSimpleName(boolean[].class));
143 assertEquals("byte[]", ClassUtils.getSimpleName(byte[].class));
144 assertEquals("char[]", ClassUtils.getSimpleName(char[].class));
145 assertEquals("short[]", ClassUtils.getSimpleName(short[].class));
146 assertEquals("int[]", ClassUtils.getSimpleName(int[].class));
147 assertEquals("long[]", ClassUtils.getSimpleName(long[].class));
148 assertEquals("float[]", ClassUtils.getSimpleName(float[].class));
149 assertEquals("double[]", ClassUtils.getSimpleName(double[].class));
150
151 // Arrays of arrays of ...
152 assertEquals("String[][]", ClassUtils.getSimpleName(String[][].class));
153 assertEquals("String[][][]", ClassUtils.getSimpleName(String[][][].class));
154 assertEquals("String[][][][]", ClassUtils.getSimpleName(String[][][][].class));
155
156 // On-the-fly types
157 class Named extends Object {};
158 assertEquals("", ClassUtils.getSimpleName(new Object(){}.getClass()));
159 assertEquals("Named", ClassUtils.getSimpleName(Named.class));
160 }
161
162 public void test_getSimpleName_Object() {
163 assertEquals("ClassUtils", ClassUtils.getSimpleName(new ClassUtils(), "<null>"));
164 assertEquals("Inner", ClassUtils.getSimpleName(new Inner(), "<null>"));
165 assertEquals("String", ClassUtils.getSimpleName("hello", "<null>"));
166 assertEquals("<null>", ClassUtils.getSimpleName(null, "<null>"));
167 }
168
169 // -------------------------------------------------------------------------
170 public void test_getPackageName_Object() {
171 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageName(new ClassUtils(), "<null>"));
172 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageName(new Inner(), "<null>"));
173 assertEquals("<null>", ClassUtils.getPackageName(null, "<null>"));
174 }
175
176 public void test_getPackageName_Class() {
177 assertEquals("java.lang", ClassUtils.getPackageName(String.class));
178 assertEquals("java.util", ClassUtils.getPackageName(Map.Entry.class));
179 assertEquals("", ClassUtils.getPackageName((Class<?>)null));
180
181 // LANG-535
182 assertEquals("java.lang", ClassUtils.getPackageName(String[].class));
183
184 // Primitive Arrays
185 assertEquals("", ClassUtils.getPackageName(boolean[].class));
186 assertEquals("", ClassUtils.getPackageName(byte[].class));
187 assertEquals("", ClassUtils.getPackageName(char[].class));
188 assertEquals("", ClassUtils.getPackageName(short[].class));
189 assertEquals("", ClassUtils.getPackageName(int[].class));
190 assertEquals("", ClassUtils.getPackageName(long[].class));
191 assertEquals("", ClassUtils.getPackageName(float[].class));
192 assertEquals("", ClassUtils.getPackageName(double[].class));
193
194 // Arrays of arrays of ...
195 assertEquals("java.lang", ClassUtils.getPackageName(String[][].class));
196 assertEquals("java.lang", ClassUtils.getPackageName(String[][][].class));
197 assertEquals("java.lang", ClassUtils.getPackageName(String[][][][].class));
198
199 // On-the-fly types
200 class Named extends Object {};
201 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageName(new Object(){}.getClass()));
202 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageName(Named.class));
203 }
204
205 public void test_getPackageName_String() {
206 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageName(ClassUtils.class.getName()));
207 assertEquals("java.util", ClassUtils.getPackageName(Map.Entry.class.getName()));
208 assertEquals("", ClassUtils.getPackageName((String)null));
209 assertEquals("", ClassUtils.getPackageName(""));
210 }
211
212 // -------------------------------------------------------------------------
213 public void test_getAllSuperclasses_Class() {
214 List<?> list = ClassUtils.getAllSuperclasses(CY.class);
215 assertEquals(2, list.size());
216 assertEquals(CX.class, list.get(0));
217 assertEquals(Object.class, list.get(1));
218
219 assertEquals(null, ClassUtils.getAllSuperclasses(null));
220 }
221
222 public void test_getAllInterfaces_Class() {
223 List<?> list = ClassUtils.getAllInterfaces(CY.class);
224 assertEquals(6, list.size());
225 assertEquals(IB.class, list.get(0));
226 assertEquals(IC.class, list.get(1));
227 assertEquals(ID.class, list.get(2));
228 assertEquals(IE.class, list.get(3));
229 assertEquals(IF.class, list.get(4));
230 assertEquals(IA.class, list.get(5));
231
232 assertEquals(null, ClassUtils.getAllInterfaces(null));
233 }
234
235 private static interface IA {
236 }
237 private static interface IB {
238 }
239 private static interface IC extends ID, IE {
240 }
241 private static interface ID {
242 }
243 private static interface IE extends IF {
244 }
245 private static interface IF {
246 }
247 private static class CX implements IB, IA, IE {
248 }
249 private static class CY extends CX implements IB, IC {
250 }
251
252 // -------------------------------------------------------------------------
253 public void test_convertClassNamesToClasses_List() {
254 List<String> list = new ArrayList<String>();
255 List<Class<?>> result = ClassUtils.convertClassNamesToClasses(list);
256 assertEquals(0, result.size());
257
258 list.add("java.lang.String");
259 list.add("java.lang.xxx");
260 list.add("java.lang.Object");
261 result = ClassUtils.convertClassNamesToClasses(list);
262 assertEquals(3, result.size());
263 assertEquals(String.class, result.get(0));
264 assertEquals(null, result.get(1));
265 assertEquals(Object.class, result.get(2));
266
267 @SuppressWarnings("unchecked") // test what happens when non-generic code adds wrong type of element
268 List<Object> olist = (List<Object>)(List<?>)list;
269 olist.add(new Object());
270 try {
271 ClassUtils.convertClassNamesToClasses(list);
272 fail("Should not have been able to convert list");
273 } catch (ClassCastException expected) {}
274 assertEquals(null, ClassUtils.convertClassNamesToClasses(null));
275 }
276
277 public void test_convertClassesToClassNames_List() {
278 List<Class<?>> list = new ArrayList<Class<?>>();
279 List<String> result = ClassUtils.convertClassesToClassNames(list);
280 assertEquals(0, result.size());
281
282 list.add(String.class);
283 list.add(null);
284 list.add(Object.class);
285 result = ClassUtils.convertClassesToClassNames(list);
286 assertEquals(3, result.size());
287 assertEquals("java.lang.String", result.get(0));
288 assertEquals(null, result.get(1));
289 assertEquals("java.lang.Object", result.get(2));
290
291 @SuppressWarnings("unchecked") // test what happens when non-generic code adds wrong type of element
292 List<Object> olist = (List<Object>)(List<?>)list;
293 olist.add(new Object());
294 try {
295 ClassUtils.convertClassesToClassNames(list);
296 fail("Should not have been able to convert list");
297 } catch (ClassCastException expected) {}
298 assertEquals(null, ClassUtils.convertClassesToClassNames(null));
299 }
300
301 // -------------------------------------------------------------------------
302 public void test_isInnerClass_Class() {
303 assertEquals(true, ClassUtils.isInnerClass(Inner.class));
304 assertEquals(true, ClassUtils.isInnerClass(Map.Entry.class));
305 assertEquals(true, ClassUtils.isInnerClass(new Cloneable() {
306 }.getClass()));
307 assertEquals(false, ClassUtils.isInnerClass(this.getClass()));
308 assertEquals(false, ClassUtils.isInnerClass(String.class));
309 assertEquals(false, ClassUtils.isInnerClass(null));
310 }
311
312 // -------------------------------------------------------------------------
313 public void test_isAssignable_ClassArray_ClassArray() throws Exception {
314 Class<?>[] array2 = new Class[] {Object.class, Object.class};
315 Class<?>[] array1 = new Class[] {Object.class};
316 Class<?>[] array1s = new Class[] {String.class};
317 Class<?>[] array0 = new Class[] {};
318 Class<?>[] arrayPrimitives = { Integer.TYPE, Boolean.TYPE };
319 Class<?>[] arrayWrappers = { Integer.class, Boolean.class };
320
321 assertFalse(ClassUtils.isAssignable(array1, array2));
322 assertFalse(ClassUtils.isAssignable(null, array2));
323 assertTrue(ClassUtils.isAssignable(null, array0));
324 assertTrue(ClassUtils.isAssignable(array0, array0));
325 // assertTrue(ClassUtils.isAssignable(array0, null));
326 assertTrue(ClassUtils.isAssignable(array0, (Class<?>[]) null)); // explicit cast to avoid warning
327 assertTrue(ClassUtils.isAssignable((Class[]) null, (Class[]) null));
328
329 assertFalse(ClassUtils.isAssignable(array1, array1s));
330 assertTrue(ClassUtils.isAssignable(array1s, array1s));
331 assertTrue(ClassUtils.isAssignable(array1s, array1));
332
333 boolean autoboxing = SystemUtils.isJavaVersionAtLeast(JAVA_1_5);
334
335 assertEquals(autoboxing, ClassUtils.isAssignable(arrayPrimitives, arrayWrappers));
336 assertEquals(autoboxing, ClassUtils.isAssignable(arrayWrappers, arrayPrimitives));
337 assertFalse(ClassUtils.isAssignable(arrayPrimitives, array1));
338 assertFalse(ClassUtils.isAssignable(arrayWrappers, array1));
339 assertEquals(autoboxing, ClassUtils.isAssignable(arrayPrimitives, array2));
340 assertTrue(ClassUtils.isAssignable(arrayWrappers, array2));
341 }
342
343 public void test_isAssignable_ClassArray_ClassArray_Autoboxing() throws Exception {
344 Class<?>[] array2 = new Class[] {Object.class, Object.class};
345 Class<?>[] array1 = new Class[] {Object.class};
346 Class<?>[] array1s = new Class[] {String.class};
347 Class<?>[] array0 = new Class[] {};
348 Class<?>[] arrayPrimitives = { Integer.TYPE, Boolean.TYPE };
349 Class<?>[] arrayWrappers = { Integer.class, Boolean.class };
350
351 assertFalse(ClassUtils.isAssignable(array1, array2, true));
352 assertFalse(ClassUtils.isAssignable(null, array2, true));
353 assertTrue(ClassUtils.isAssignable(null, array0, true));
354 assertTrue(ClassUtils.isAssignable(array0, array0, true));
355 assertTrue(ClassUtils.isAssignable(array0, null, true));
356 assertTrue(ClassUtils.isAssignable((Class[]) null, (Class[]) null, true));
357
358 assertFalse(ClassUtils.isAssignable(array1, array1s, true));
359 assertTrue(ClassUtils.isAssignable(array1s, array1s, true));
360 assertTrue(ClassUtils.isAssignable(array1s, array1, true));
361
362 assertTrue(ClassUtils.isAssignable(arrayPrimitives, arrayWrappers, true));
363 assertTrue(ClassUtils.isAssignable(arrayWrappers, arrayPrimitives, true));
364 assertFalse(ClassUtils.isAssignable(arrayPrimitives, array1, true));
365 assertFalse(ClassUtils.isAssignable(arrayWrappers, array1, true));
366 assertTrue(ClassUtils.isAssignable(arrayPrimitives, array2, true));
367 assertTrue(ClassUtils.isAssignable(arrayWrappers, array2, true));
368 }
369
370 public void test_isAssignable_ClassArray_ClassArray_NoAutoboxing() throws Exception {
371 Class<?>[] array2 = new Class[] {Object.class, Object.class};
372 Class<?>[] array1 = new Class[] {Object.class};
373 Class<?>[] array1s = new Class[] {String.class};
374 Class<?>[] array0 = new Class[] {};
375 Class<?>[] arrayPrimitives = { Integer.TYPE, Boolean.TYPE };
376 Class<?>[] arrayWrappers = { Integer.class, Boolean.class };
377
378 assertFalse(ClassUtils.isAssignable(array1, array2, false));
379 assertFalse(ClassUtils.isAssignable(null, array2, false));
380 assertTrue(ClassUtils.isAssignable(null, array0, false));
381 assertTrue(ClassUtils.isAssignable(array0, array0, false));
382 assertTrue(ClassUtils.isAssignable(array0, null, false));
383 assertTrue(ClassUtils.isAssignable((Class[]) null, (Class[]) null, false));
384
385 assertFalse(ClassUtils.isAssignable(array1, array1s, false));
386 assertTrue(ClassUtils.isAssignable(array1s, array1s, false));
387 assertTrue(ClassUtils.isAssignable(array1s, array1, false));
388
389 assertFalse(ClassUtils.isAssignable(arrayPrimitives, arrayWrappers, false));
390 assertFalse(ClassUtils.isAssignable(arrayWrappers, arrayPrimitives, false));
391 assertFalse(ClassUtils.isAssignable(arrayPrimitives, array1, false));
392 assertFalse(ClassUtils.isAssignable(arrayWrappers, array1, false));
393 assertTrue(ClassUtils.isAssignable(arrayWrappers, array2, false));
394 assertFalse(ClassUtils.isAssignable(arrayPrimitives, array2, false));
395 }
396
397 public void test_isAssignable() throws Exception {
398 assertFalse(ClassUtils.isAssignable((Class<?>) null, null));
399 assertFalse(ClassUtils.isAssignable(String.class, null));
400
401 assertTrue(ClassUtils.isAssignable(null, Object.class));
402 assertTrue(ClassUtils.isAssignable(null, Integer.class));
403 assertFalse(ClassUtils.isAssignable(null, Integer.TYPE));
404 assertTrue(ClassUtils.isAssignable(String.class, Object.class));
405 assertTrue(ClassUtils.isAssignable(String.class, String.class));
406 assertFalse(ClassUtils.isAssignable(Object.class, String.class));
407
408 boolean autoboxing = SystemUtils.isJavaVersionAtLeast(JAVA_1_5);
409
410 assertEquals(autoboxing, ClassUtils.isAssignable(Integer.TYPE, Integer.class));
411 assertEquals(autoboxing, ClassUtils.isAssignable(Integer.TYPE, Object.class));
412 assertEquals(autoboxing, ClassUtils.isAssignable(Integer.class, Integer.TYPE));
413 assertEquals(autoboxing, ClassUtils.isAssignable(Integer.class, Object.class));
414 assertTrue(ClassUtils.isAssignable(Integer.TYPE, Integer.TYPE));
415 assertTrue(ClassUtils.isAssignable(Integer.class, Integer.class));
416 assertEquals(autoboxing, ClassUtils.isAssignable(Boolean.TYPE, Boolean.class));
417 assertEquals(autoboxing, ClassUtils.isAssignable(Boolean.TYPE, Object.class));
418 assertEquals(autoboxing, ClassUtils.isAssignable(Boolean.class, Boolean.TYPE));
419 assertEquals(autoboxing, ClassUtils.isAssignable(Boolean.class, Object.class));
420 assertTrue(ClassUtils.isAssignable(Boolean.TYPE, Boolean.TYPE));
421 assertTrue(ClassUtils.isAssignable(Boolean.class, Boolean.class));
422 }
423
424 public void test_isAssignable_Autoboxing() throws Exception {
425 assertFalse(ClassUtils.isAssignable((Class<?>) null, null, true));
426 assertFalse(ClassUtils.isAssignable(String.class, null, true));
427
428 assertTrue(ClassUtils.isAssignable(null, Object.class, true));
429 assertTrue(ClassUtils.isAssignable(null, Integer.class, true));
430 assertFalse(ClassUtils.isAssignable(null, Integer.TYPE, true));
431 assertTrue(ClassUtils.isAssignable(String.class, Object.class, true));
432 assertTrue(ClassUtils.isAssignable(String.class, String.class, true));
433 assertFalse(ClassUtils.isAssignable(Object.class, String.class, true));
434 assertTrue(ClassUtils.isAssignable(Integer.TYPE, Integer.class, true));
435 assertTrue(ClassUtils.isAssignable(Integer.TYPE, Object.class, true));
436 assertTrue(ClassUtils.isAssignable(Integer.class, Integer.TYPE, true));
437 assertTrue(ClassUtils.isAssignable(Integer.class, Object.class, true));
438 assertTrue(ClassUtils.isAssignable(Integer.TYPE, Integer.TYPE, true));
439 assertTrue(ClassUtils.isAssignable(Integer.class, Integer.class, true));
440 assertTrue(ClassUtils.isAssignable(Boolean.TYPE, Boolean.class, true));
441 assertTrue(ClassUtils.isAssignable(Boolean.class, Boolean.TYPE, true));
442 assertTrue(ClassUtils.isAssignable(Boolean.class, Object.class, true));
443 assertTrue(ClassUtils.isAssignable(Boolean.TYPE, Boolean.TYPE, true));
444 assertTrue(ClassUtils.isAssignable(Boolean.class, Boolean.class, true));
445 }
446
447 public void test_isAssignable_NoAutoboxing() throws Exception {
448 assertFalse(ClassUtils.isAssignable((Class<?>) null, null, false));
449 assertFalse(ClassUtils.isAssignable(String.class, null, false));
450
451 assertTrue(ClassUtils.isAssignable(null, Object.class, false));
452 assertTrue(ClassUtils.isAssignable(null, Integer.class, false));
453 assertFalse(ClassUtils.isAssignable(null, Integer.TYPE, false));
454 assertTrue(ClassUtils.isAssignable(String.class, Object.class, false));
455 assertTrue(ClassUtils.isAssignable(String.class, String.class, false));
456 assertFalse(ClassUtils.isAssignable(Object.class, String.class, false));
457 assertFalse(ClassUtils.isAssignable(Integer.TYPE, Integer.class, false));
458 assertFalse(ClassUtils.isAssignable(Integer.TYPE, Object.class, false));
459 assertFalse(ClassUtils.isAssignable(Integer.class, Integer.TYPE, false));
460 assertTrue(ClassUtils.isAssignable(Integer.TYPE, Integer.TYPE, false));
461 assertTrue(ClassUtils.isAssignable(Integer.class, Integer.class, false));
462 assertFalse(ClassUtils.isAssignable(Boolean.TYPE, Boolean.class, false));
463 assertFalse(ClassUtils.isAssignable(Boolean.TYPE, Object.class, false));
464 assertFalse(ClassUtils.isAssignable(Boolean.class, Boolean.TYPE, false));
465 assertTrue(ClassUtils.isAssignable(Boolean.class, Object.class, false));
466 assertTrue(ClassUtils.isAssignable(Boolean.TYPE, Boolean.TYPE, false));
467 assertTrue(ClassUtils.isAssignable(Boolean.class, Boolean.class, false));
468 }
469
470 public void test_isAssignable_Widening() throws Exception {
471 // test byte conversions
472 assertFalse("byte -> char", ClassUtils.isAssignable(Byte.TYPE, Character.TYPE));
473 assertTrue("byte -> byte", ClassUtils.isAssignable(Byte.TYPE, Byte.TYPE));
474 assertTrue("byte -> short", ClassUtils.isAssignable(Byte.TYPE, Short.TYPE));
475 assertTrue("byte -> int", ClassUtils.isAssignable(Byte.TYPE, Integer.TYPE));
476 assertTrue("byte -> long", ClassUtils.isAssignable(Byte.TYPE, Long.TYPE));
477 assertTrue("byte -> float", ClassUtils.isAssignable(Byte.TYPE, Float.TYPE));
478 assertTrue("byte -> double", ClassUtils.isAssignable(Byte.TYPE, Double.TYPE));
479 assertFalse("byte -> boolean", ClassUtils.isAssignable(Byte.TYPE, Boolean.TYPE));
480
481 // test short conversions
482 assertFalse("short -> char", ClassUtils.isAssignable(Short.TYPE, Character.TYPE));
483 assertFalse("short -> byte", ClassUtils.isAssignable(Short.TYPE, Byte.TYPE));
484 assertTrue("short -> short", ClassUtils.isAssignable(Short.TYPE, Short.TYPE));
485 assertTrue("short -> int", ClassUtils.isAssignable(Short.TYPE, Integer.TYPE));
486 assertTrue("short -> long", ClassUtils.isAssignable(Short.TYPE, Long.TYPE));
487 assertTrue("short -> float", ClassUtils.isAssignable(Short.TYPE, Float.TYPE));
488 assertTrue("short -> double", ClassUtils.isAssignable(Short.TYPE, Double.TYPE));
489 assertFalse("short -> boolean", ClassUtils.isAssignable(Short.TYPE, Boolean.TYPE));
490
491 // test char conversions
492 assertTrue("char -> char", ClassUtils.isAssignable(Character.TYPE, Character.TYPE));
493 assertFalse("char -> byte", ClassUtils.isAssignable(Character.TYPE, Byte.TYPE));
494 assertFalse("char -> short", ClassUtils.isAssignable(Character.TYPE, Short.TYPE));
495 assertTrue("char -> int", ClassUtils.isAssignable(Character.TYPE, Integer.TYPE));
496 assertTrue("char -> long", ClassUtils.isAssignable(Character.TYPE, Long.TYPE));
497 assertTrue("char -> float", ClassUtils.isAssignable(Character.TYPE, Float.TYPE));
498 assertTrue("char -> double", ClassUtils.isAssignable(Character.TYPE, Double.TYPE));
499 assertFalse("char -> boolean", ClassUtils.isAssignable(Character.TYPE, Boolean.TYPE));
500
501 // test int conversions
502 assertFalse("int -> char", ClassUtils.isAssignable(Integer.TYPE, Character.TYPE));
503 assertFalse("int -> byte", ClassUtils.isAssignable(Integer.TYPE, Byte.TYPE));
504 assertFalse("int -> short", ClassUtils.isAssignable(Integer.TYPE, Short.TYPE));
505 assertTrue("int -> int", ClassUtils.isAssignable(Integer.TYPE, Integer.TYPE));
506 assertTrue("int -> long", ClassUtils.isAssignable(Integer.TYPE, Long.TYPE));
507 assertTrue("int -> float", ClassUtils.isAssignable(Integer.TYPE, Float.TYPE));
508 assertTrue("int -> double", ClassUtils.isAssignable(Integer.TYPE, Double.TYPE));
509 assertFalse("int -> boolean", ClassUtils.isAssignable(Integer.TYPE, Boolean.TYPE));
510
511 // test long conversions
512 assertFalse("long -> char", ClassUtils.isAssignable(Long.TYPE, Character.TYPE));
513 assertFalse("long -> byte", ClassUtils.isAssignable(Long.TYPE, Byte.TYPE));
514 assertFalse("long -> short", ClassUtils.isAssignable(Long.TYPE, Short.TYPE));
515 assertFalse("long -> int", ClassUtils.isAssignable(Long.TYPE, Integer.TYPE));
516 assertTrue("long -> long", ClassUtils.isAssignable(Long.TYPE, Long.TYPE));
517 assertTrue("long -> float", ClassUtils.isAssignable(Long.TYPE, Float.TYPE));
518 assertTrue("long -> double", ClassUtils.isAssignable(Long.TYPE, Double.TYPE));
519 assertFalse("long -> boolean", ClassUtils.isAssignable(Long.TYPE, Boolean.TYPE));
520
521 // test float conversions
522 assertFalse("float -> char", ClassUtils.isAssignable(Float.TYPE, Character.TYPE));
523 assertFalse("float -> byte", ClassUtils.isAssignable(Float.TYPE, Byte.TYPE));
524 assertFalse("float -> short", ClassUtils.isAssignable(Float.TYPE, Short.TYPE));
525 assertFalse("float -> int", ClassUtils.isAssignable(Float.TYPE, Integer.TYPE));
526 assertFalse("float -> long", ClassUtils.isAssignable(Float.TYPE, Long.TYPE));
527 assertTrue("float -> float", ClassUtils.isAssignable(Float.TYPE, Float.TYPE));
528 assertTrue("float -> double", ClassUtils.isAssignable(Float.TYPE, Double.TYPE));
529 assertFalse("float -> boolean", ClassUtils.isAssignable(Float.TYPE, Boolean.TYPE));
530
531 // test double conversions
532 assertFalse("double -> char", ClassUtils.isAssignable(Double.TYPE, Character.TYPE));
533 assertFalse("double -> byte", ClassUtils.isAssignable(Double.TYPE, Byte.TYPE));
534 assertFalse("double -> short", ClassUtils.isAssignable(Double.TYPE, Short.TYPE));
535 assertFalse("double -> int", ClassUtils.isAssignable(Double.TYPE, Integer.TYPE));
536 assertFalse("double -> long", ClassUtils.isAssignable(Double.TYPE, Long.TYPE));
537 assertFalse("double -> float", ClassUtils.isAssignable(Double.TYPE, Float.TYPE));
538 assertTrue("double -> double", ClassUtils.isAssignable(Double.TYPE, Double.TYPE));
539 assertFalse("double -> boolean", ClassUtils.isAssignable(Double.TYPE, Boolean.TYPE));
540
541 // test boolean conversions
542 assertFalse("boolean -> char", ClassUtils.isAssignable(Boolean.TYPE, Character.TYPE));
543 assertFalse("boolean -> byte", ClassUtils.isAssignable(Boolean.TYPE, Byte.TYPE));
544 assertFalse("boolean -> short", ClassUtils.isAssignable(Boolean.TYPE, Short.TYPE));
545 assertFalse("boolean -> int", ClassUtils.isAssignable(Boolean.TYPE, Integer.TYPE));
546 assertFalse("boolean -> long", ClassUtils.isAssignable(Boolean.TYPE, Long.TYPE));
547 assertFalse("boolean -> float", ClassUtils.isAssignable(Boolean.TYPE, Float.TYPE));
548 assertFalse("boolean -> double", ClassUtils.isAssignable(Boolean.TYPE, Double.TYPE));
549 assertTrue("boolean -> boolean", ClassUtils.isAssignable(Boolean.TYPE, Boolean.TYPE));
550 }
551
552 public void test_isAssignable_DefaultUnboxing_Widening() throws Exception {
553 boolean autoboxing = SystemUtils.isJavaVersionAtLeast(JAVA_1_5);
554
555 // test byte conversions
556 assertFalse("byte -> char", ClassUtils.isAssignable(Byte.class, Character.TYPE));
557 assertEquals("byte -> byte", autoboxing, ClassUtils.isAssignable(Byte.class, Byte.TYPE));
558 assertEquals("byte -> short", autoboxing, ClassUtils.isAssignable(Byte.class, Short.TYPE));
559 assertEquals("byte -> int", autoboxing, ClassUtils.isAssignable(Byte.class, Integer.TYPE));
560 assertEquals("byte -> long", autoboxing, ClassUtils.isAssignable(Byte.class, Long.TYPE));
561 assertEquals("byte -> float", autoboxing, ClassUtils.isAssignable(Byte.class, Float.TYPE));
562 assertEquals("byte -> double", autoboxing, ClassUtils.isAssignable(Byte.class, Double.TYPE));
563 assertFalse("byte -> boolean", ClassUtils.isAssignable(Byte.class, Boolean.TYPE));
564
565 // test short conversions
566 assertFalse("short -> char", ClassUtils.isAssignable(Short.class, Character.TYPE));
567 assertFalse("short -> byte", ClassUtils.isAssignable(Short.class, Byte.TYPE));
568 assertEquals("short -> short", autoboxing, ClassUtils.isAssignable(Short.class, Short.TYPE));
569 assertEquals("short -> int", autoboxing, ClassUtils.isAssignable(Short.class, Integer.TYPE));
570 assertEquals("short -> long", autoboxing, ClassUtils.isAssignable(Short.class, Long.TYPE));
571 assertEquals("short -> float", autoboxing, ClassUtils.isAssignable(Short.class, Float.TYPE));
572 assertEquals("short -> double", autoboxing, ClassUtils.isAssignable(Short.class, Double.TYPE));
573 assertFalse("short -> boolean", ClassUtils.isAssignable(Short.class, Boolean.TYPE));
574
575 // test char conversions
576 assertEquals("char -> char", autoboxing, ClassUtils.isAssignable(Character.class, Character.TYPE));
577 assertFalse("char -> byte", ClassUtils.isAssignable(Character.class, Byte.TYPE));
578 assertFalse("char -> short", ClassUtils.isAssignable(Character.class, Short.TYPE));
579 assertEquals("char -> int", autoboxing, ClassUtils.isAssignable(Character.class, Integer.TYPE));
580 assertEquals("char -> long", autoboxing, ClassUtils.isAssignable(Character.class, Long.TYPE));
581 assertEquals("char -> float", autoboxing, ClassUtils.isAssignable(Character.class, Float.TYPE));
582 assertEquals("char -> double", autoboxing, ClassUtils.isAssignable(Character.class, Double.TYPE));
583 assertFalse("char -> boolean", ClassUtils.isAssignable(Character.class, Boolean.TYPE));
584
585 // test int conversions
586 assertFalse("int -> char", ClassUtils.isAssignable(Integer.class, Character.TYPE));
587 assertFalse("int -> byte", ClassUtils.isAssignable(Integer.class, Byte.TYPE));
588 assertFalse("int -> short", ClassUtils.isAssignable(Integer.class, Short.TYPE));
589 assertEquals("int -> int", autoboxing, ClassUtils.isAssignable(Integer.class, Integer.TYPE));
590 assertEquals("int -> long", autoboxing, ClassUtils.isAssignable(Integer.class, Long.TYPE));
591 assertEquals("int -> float", autoboxing, ClassUtils.isAssignable(Integer.class, Float.TYPE));
592 assertEquals("int -> double", autoboxing, ClassUtils.isAssignable(Integer.class, Double.TYPE));
593 assertFalse("int -> boolean", ClassUtils.isAssignable(Integer.class, Boolean.TYPE));
594
595 // test long conversions
596 assertFalse("long -> char", ClassUtils.isAssignable(Long.class, Character.TYPE));
597 assertFalse("long -> byte", ClassUtils.isAssignable(Long.class, Byte.TYPE));
598 assertFalse("long -> short", ClassUtils.isAssignable(Long.class, Short.TYPE));
599 assertFalse("long -> int", ClassUtils.isAssignable(Long.class, Integer.TYPE));
600 assertEquals("long -> long", autoboxing, ClassUtils.isAssignable(Long.class, Long.TYPE));
601 assertEquals("long -> float", autoboxing, ClassUtils.isAssignable(Long.class, Float.TYPE));
602 assertEquals("long -> double", autoboxing, ClassUtils.isAssignable(Long.class, Double.TYPE));
603 assertFalse("long -> boolean", ClassUtils.isAssignable(Long.class, Boolean.TYPE));
604
605 // test float conversions
606 assertFalse("float -> char", ClassUtils.isAssignable(Float.class, Character.TYPE));
607 assertFalse("float -> byte", ClassUtils.isAssignable(Float.class, Byte.TYPE));
608 assertFalse("float -> short", ClassUtils.isAssignable(Float.class, Short.TYPE));
609 assertFalse("float -> int", ClassUtils.isAssignable(Float.class, Integer.TYPE));
610 assertFalse("float -> long", ClassUtils.isAssignable(Float.class, Long.TYPE));
611 assertEquals("float -> float", autoboxing, ClassUtils.isAssignable(Float.class, Float.TYPE));
612 assertEquals("float -> double", autoboxing, ClassUtils.isAssignable(Float.class, Double.TYPE));
613 assertFalse("float -> boolean", ClassUtils.isAssignable(Float.class, Boolean.TYPE));
614
615 // test double conversions
616 assertFalse("double -> char", ClassUtils.isAssignable(Double.class, Character.TYPE));
617 assertFalse("double -> byte", ClassUtils.isAssignable(Double.class, Byte.TYPE));
618 assertFalse("double -> short", ClassUtils.isAssignable(Double.class, Short.TYPE));
619 assertFalse("double -> int", ClassUtils.isAssignable(Double.class, Integer.TYPE));
620 assertFalse("double -> long", ClassUtils.isAssignable(Double.class, Long.TYPE));
621 assertFalse("double -> float", ClassUtils.isAssignable(Double.class, Float.TYPE));
622 assertEquals("double -> double", autoboxing, ClassUtils.isAssignable(Double.class, Double.TYPE));
623 assertFalse("double -> boolean", ClassUtils.isAssignable(Double.class, Boolean.TYPE));
624
625 // test boolean conversions
626 assertFalse("boolean -> char", ClassUtils.isAssignable(Boolean.class, Character.TYPE));
627 assertFalse("boolean -> byte", ClassUtils.isAssignable(Boolean.class, Byte.TYPE));
628 assertFalse("boolean -> short", ClassUtils.isAssignable(Boolean.class, Short.TYPE));
629 assertFalse("boolean -> int", ClassUtils.isAssignable(Boolean.class, Integer.TYPE));
630 assertFalse("boolean -> long", ClassUtils.isAssignable(Boolean.class, Long.TYPE));
631 assertFalse("boolean -> float", ClassUtils.isAssignable(Boolean.class, Float.TYPE));
632 assertFalse("boolean -> double", ClassUtils.isAssignable(Boolean.class, Double.TYPE));
633 assertEquals("boolean -> boolean", autoboxing, ClassUtils.isAssignable(Boolean.class, Boolean.TYPE));
634 }
635
636 public void test_isAssignable_Unboxing_Widening() throws Exception {
637 // test byte conversions
638 assertFalse("byte -> char", ClassUtils.isAssignable(Byte.class, Character.TYPE, true));
639 assertTrue("byte -> byte", ClassUtils.isAssignable(Byte.class, Byte.TYPE, true));
640 assertTrue("byte -> short", ClassUtils.isAssignable(Byte.class, Short.TYPE, true));
641 assertTrue("byte -> int", ClassUtils.isAssignable(Byte.class, Integer.TYPE, true));
642 assertTrue("byte -> long", ClassUtils.isAssignable(Byte.class, Long.TYPE, true));
643 assertTrue("byte -> float", ClassUtils.isAssignable(Byte.class, Float.TYPE, true));
644 assertTrue("byte -> double", ClassUtils.isAssignable(Byte.class, Double.TYPE, true));
645 assertFalse("byte -> boolean", ClassUtils.isAssignable(Byte.class, Boolean.TYPE, true));
646
647 // test short conversions
648 assertFalse("short -> char", ClassUtils.isAssignable(Short.class, Character.TYPE, true));
649 assertFalse("short -> byte", ClassUtils.isAssignable(Short.class, Byte.TYPE, true));
650 assertTrue("short -> short", ClassUtils.isAssignable(Short.class, Short.TYPE, true));
651 assertTrue("short -> int", ClassUtils.isAssignable(Short.class, Integer.TYPE, true));
652 assertTrue("short -> long", ClassUtils.isAssignable(Short.class, Long.TYPE, true));
653 assertTrue("short -> float", ClassUtils.isAssignable(Short.class, Float.TYPE, true));
654 assertTrue("short -> double", ClassUtils.isAssignable(Short.class, Double.TYPE, true));
655 assertFalse("short -> boolean", ClassUtils.isAssignable(Short.class, Boolean.TYPE, true));
656
657 // test char conversions
658 assertTrue("char -> char", ClassUtils.isAssignable(Character.class, Character.TYPE, true));
659 assertFalse("char -> byte", ClassUtils.isAssignable(Character.class, Byte.TYPE, true));
660 assertFalse("char -> short", ClassUtils.isAssignable(Character.class, Short.TYPE, true));
661 assertTrue("char -> int", ClassUtils.isAssignable(Character.class, Integer.TYPE, true));
662 assertTrue("char -> long", ClassUtils.isAssignable(Character.class, Long.TYPE, true));
663 assertTrue("char -> float", ClassUtils.isAssignable(Character.class, Float.TYPE, true));
664 assertTrue("char -> double", ClassUtils.isAssignable(Character.class, Double.TYPE, true));
665 assertFalse("char -> boolean", ClassUtils.isAssignable(Character.class, Boolean.TYPE, true));
666
667 // test int conversions
668 assertFalse("int -> char", ClassUtils.isAssignable(Integer.class, Character.TYPE, true));
669 assertFalse("int -> byte", ClassUtils.isAssignable(Integer.class, Byte.TYPE, true));
670 assertFalse("int -> short", ClassUtils.isAssignable(Integer.class, Short.TYPE, true));
671 assertTrue("int -> int", ClassUtils.isAssignable(Integer.class, Integer.TYPE, true));
672 assertTrue("int -> long", ClassUtils.isAssignable(Integer.class, Long.TYPE, true));
673 assertTrue("int -> float", ClassUtils.isAssignable(Integer.class, Float.TYPE, true));
674 assertTrue("int -> double", ClassUtils.isAssignable(Integer.class, Double.TYPE, true));
675 assertFalse("int -> boolean", ClassUtils.isAssignable(Integer.class, Boolean.TYPE, true));
676
677 // test long conversions
678 assertFalse("long -> char", ClassUtils.isAssignable(Long.class, Character.TYPE, true));
679 assertFalse("long -> byte", ClassUtils.isAssignable(Long.class, Byte.TYPE, true));
680 assertFalse("long -> short", ClassUtils.isAssignable(Long.class, Short.TYPE, true));
681 assertFalse("long -> int", ClassUtils.isAssignable(Long.class, Integer.TYPE, true));
682 assertTrue("long -> long", ClassUtils.isAssignable(Long.class, Long.TYPE, true));
683 assertTrue("long -> float", ClassUtils.isAssignable(Long.class, Float.TYPE, true));
684 assertTrue("long -> double", ClassUtils.isAssignable(Long.class, Double.TYPE, true));
685 assertFalse("long -> boolean", ClassUtils.isAssignable(Long.class, Boolean.TYPE, true));
686
687 // test float conversions
688 assertFalse("float -> char", ClassUtils.isAssignable(Float.class, Character.TYPE, true));
689 assertFalse("float -> byte", ClassUtils.isAssignable(Float.class, Byte.TYPE, true));
690 assertFalse("float -> short", ClassUtils.isAssignable(Float.class, Short.TYPE, true));
691 assertFalse("float -> int", ClassUtils.isAssignable(Float.class, Integer.TYPE, true));
692 assertFalse("float -> long", ClassUtils.isAssignable(Float.class, Long.TYPE, true));
693 assertTrue("float -> float", ClassUtils.isAssignable(Float.class, Float.TYPE, true));
694 assertTrue("float -> double", ClassUtils.isAssignable(Float.class, Double.TYPE, true));
695 assertFalse("float -> boolean", ClassUtils.isAssignable(Float.class, Boolean.TYPE, true));
696
697 // test double conversions
698 assertFalse("double -> char", ClassUtils.isAssignable(Double.class, Character.TYPE, true));
699 assertFalse("double -> byte", ClassUtils.isAssignable(Double.class, Byte.TYPE, true));
700 assertFalse("double -> short", ClassUtils.isAssignable(Double.class, Short.TYPE, true));
701 assertFalse("double -> int", ClassUtils.isAssignable(Double.class, Integer.TYPE, true));
702 assertFalse("double -> long", ClassUtils.isAssignable(Double.class, Long.TYPE, true));
703 assertFalse("double -> float", ClassUtils.isAssignable(Double.class, Float.TYPE, true));
704 assertTrue("double -> double", ClassUtils.isAssignable(Double.class, Double.TYPE, true));
705 assertFalse("double -> boolean", ClassUtils.isAssignable(Double.class, Boolean.TYPE, true));
706
707 // test boolean conversions
708 assertFalse("boolean -> char", ClassUtils.isAssignable(Boolean.class, Character.TYPE, true));
709 assertFalse("boolean -> byte", ClassUtils.isAssignable(Boolean.class, Byte.TYPE, true));
710 assertFalse("boolean -> short", ClassUtils.isAssignable(Boolean.class, Short.TYPE, true));
711 assertFalse("boolean -> int", ClassUtils.isAssignable(Boolean.class, Integer.TYPE, true));
712 assertFalse("boolean -> long", ClassUtils.isAssignable(Boolean.class, Long.TYPE, true));
713 assertFalse("boolean -> float", ClassUtils.isAssignable(Boolean.class, Float.TYPE, true));
714 assertFalse("boolean -> double", ClassUtils.isAssignable(Boolean.class, Double.TYPE, true));
715 assertTrue("boolean -> boolean", ClassUtils.isAssignable(Boolean.class, Boolean.TYPE, true));
716 }
717
718 public void testPrimitiveToWrapper() {
719
720 // test primitive classes
721 assertEquals("boolean -> Boolean.class",
722 Boolean.class, ClassUtils.primitiveToWrapper(Boolean.TYPE));
723 assertEquals("byte -> Byte.class",
724 Byte.class, ClassUtils.primitiveToWrapper(Byte.TYPE));
725 assertEquals("char -> Character.class",
726 Character.class, ClassUtils.primitiveToWrapper(Character.TYPE));
727 assertEquals("short -> Short.class",
728 Short.class, ClassUtils.primitiveToWrapper(Short.TYPE));
729 assertEquals("int -> Integer.class",
730 Integer.class, ClassUtils.primitiveToWrapper(Integer.TYPE));
731 assertEquals("long -> Long.class",
732 Long.class, ClassUtils.primitiveToWrapper(Long.TYPE));
733 assertEquals("double -> Double.class",
734 Double.class, ClassUtils.primitiveToWrapper(Double.TYPE));
735 assertEquals("float -> Float.class",
736 Float.class, ClassUtils.primitiveToWrapper(Float.TYPE));
737
738 // test a few other classes
739 assertEquals("String.class -> String.class",
740 String.class, ClassUtils.primitiveToWrapper(String.class));
741 assertEquals("ClassUtils.class -> ClassUtils.class",
742 org.apache.commons.lang3.ClassUtils.class,
743 ClassUtils.primitiveToWrapper(org.apache.commons.lang3.ClassUtils.class));
744 assertEquals("Void.TYPE -> Void.TYPE",
745 Void.TYPE, ClassUtils.primitiveToWrapper(Void.TYPE));
746
747 // test null
748 assertNull("null -> null",
749 ClassUtils.primitiveToWrapper(null));
750 }
751
752 public void testPrimitivesToWrappers() {
753 // test null
754 // assertNull("null -> null", ClassUtils.primitivesToWrappers(null)); // generates warning
755 assertNull("null -> null", ClassUtils.primitivesToWrappers((Class<?>[]) null)); // equivalent cast to avoid warning
756 // Other possible casts for null
757 assertTrue("empty -> empty", Arrays.equals(ArrayUtils.EMPTY_CLASS_ARRAY, ClassUtils.primitivesToWrappers()));
758 Class<?>[] castNull = ClassUtils.primitivesToWrappers((Class<?>)null); // == new Class<?>[]{null}
759 assertTrue("(Class<?>)null -> [null]", Arrays.equals(new Class<?>[]{null}, castNull));
760 // test empty array is returned unchanged
761 // TODO this is not documented
762 assertEquals("empty -> empty",
763 ArrayUtils.EMPTY_CLASS_ARRAY, ClassUtils.primitivesToWrappers(ArrayUtils.EMPTY_CLASS_ARRAY));
764
765 // test an array of various classes
766 final Class<?>[] primitives = new Class[] {
767 Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE,
768 Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE,
769 String.class, ClassUtils.class
770 };
771 Class<?>[] wrappers= ClassUtils.primitivesToWrappers(primitives);
772
773 for (int i=0; i < primitives.length; i++) {
774 // test each returned wrapper
775 Class<?> primitive = primitives[i];
776 Class<?> expectedWrapper = ClassUtils.primitiveToWrapper(primitive);
777
778 assertEquals(primitive + " -> " + expectedWrapper, expectedWrapper, wrappers[i]);
779 }
780
781 // test an array of no primitive classes
782 final Class<?>[] noPrimitives = new Class[] {
783 String.class, ClassUtils.class, Void.TYPE
784 };
785 // This used to return the exact same array, but no longer does.
786 assertNotSame("unmodified", noPrimitives, ClassUtils.primitivesToWrappers(noPrimitives));
787 }
788
789 public void testWrapperToPrimitive() {
790 // an array with classes to convert
791 final Class<?>[] primitives = {
792 Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE,
793 Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE
794 };
795 for (Class<?> primitive : primitives) {
796 Class<?> wrapperCls = ClassUtils.primitiveToWrapper(primitive);
797 assertFalse("Still primitive", wrapperCls.isPrimitive());
798 assertEquals(wrapperCls + " -> " + primitive, primitive,
799 ClassUtils.wrapperToPrimitive(wrapperCls));
800 }
801 }
802
803 public void testWrapperToPrimitiveNoWrapper() {
804 assertNull("Wrong result for non wrapper class", ClassUtils.wrapperToPrimitive(String.class));
805 }
806
807 public void testWrapperToPrimitiveNull() {
808 assertNull("Wrong result for null class", ClassUtils.wrapperToPrimitive(null));
809 }
810
811 public void testWrappersToPrimitives() {
812 // an array with classes to test
813 final Class<?>[] classes = {
814 Boolean.class, Byte.class, Character.class, Short.class,
815 Integer.class, Long.class, Float.class, Double.class,
816 String.class, ClassUtils.class, null
817 };
818
819 Class<?>[] primitives = ClassUtils.wrappersToPrimitives(classes);
820 // now test the result
821 assertEquals("Wrong length of result array", classes.length, primitives.length);
822 for (int i = 0; i < classes.length; i++) {
823 Class<?> expectedPrimitive = ClassUtils.wrapperToPrimitive(classes[i]);
824 assertEquals(classes[i] + " -> " + expectedPrimitive, expectedPrimitive,
825 primitives[i]);
826 }
827 }
828
829 public void testWrappersToPrimitivesNull() {
830 // assertNull("Wrong result for null input", ClassUtils.wrappersToPrimitives(null)); // generates warning
831 assertNull("Wrong result for null input", ClassUtils.wrappersToPrimitives((Class<?>[]) null)); // equivalent cast
832 // Other possible casts for null
833 assertTrue("empty -> empty", Arrays.equals(ArrayUtils.EMPTY_CLASS_ARRAY, ClassUtils.wrappersToPrimitives()));
834 Class<?>[] castNull = ClassUtils.wrappersToPrimitives((Class<?>)null); // == new Class<?>[]{null}
835 assertTrue("(Class<?>)null -> [null]", Arrays.equals(new Class<?>[]{null}, castNull));
836 }
837
838 public void testWrappersToPrimitivesEmpty() {
839 Class<?>[] empty = new Class[0];
840 assertEquals("Wrong result for empty input", empty, ClassUtils.wrappersToPrimitives(empty));
841 }
842
843 public void testGetClassClassNotFound() throws Exception {
844 assertGetClassThrowsClassNotFound( "bool" );
845 assertGetClassThrowsClassNotFound( "bool[]" );
846 assertGetClassThrowsClassNotFound( "integer[]" );
847 }
848
849 public void testGetClassInvalidArguments() throws Exception {
850 assertGetClassThrowsNullPointerException( null );
851 assertGetClassThrowsClassNotFound( "[][][]" );
852 assertGetClassThrowsClassNotFound( "[[]" );
853 assertGetClassThrowsClassNotFound( "[" );
854 assertGetClassThrowsClassNotFound( "java.lang.String][" );
855 assertGetClassThrowsClassNotFound( ".hello.world" );
856 assertGetClassThrowsClassNotFound( "hello..world" );
857 }
858
859 public void testWithInterleavingWhitespace() throws ClassNotFoundException {
860 assertEquals( int[].class, ClassUtils.getClass( " int [ ] " ) );
861 assertEquals( long[].class, ClassUtils.getClass( "\rlong\t[\n]\r" ) );
862 assertEquals( short[].class, ClassUtils.getClass( "\tshort \t\t[]" ) );
863 assertEquals( byte[].class, ClassUtils.getClass( "byte[\t\t\n\r] " ) );
864 }
865
866 public void testGetInnerClass() throws ClassNotFoundException {
867 assertEquals( Inner.DeeplyNested.class, ClassUtils.getClass( "org.apache.commons.lang3.ClassUtilsTest.Inner.DeeplyNested" ) );
868 assertEquals( Inner.DeeplyNested.class, ClassUtils.getClass( "org.apache.commons.lang3.ClassUtilsTest.Inner$DeeplyNested" ) );
869 assertEquals( Inner.DeeplyNested.class, ClassUtils.getClass( "org.apache.commons.lang3.ClassUtilsTest$Inner$DeeplyNested" ) );
870 assertEquals( Inner.DeeplyNested.class, ClassUtils.getClass( "org.apache.commons.lang3.ClassUtilsTest$Inner.DeeplyNested" ) );
871 }
872
873 public void testGetClassByNormalNameArrays() throws ClassNotFoundException {
874 assertEquals( int[].class, ClassUtils.getClass( "int[]" ) );
875 assertEquals( long[].class, ClassUtils.getClass( "long[]" ) );
876 assertEquals( short[].class, ClassUtils.getClass( "short[]" ) );
877 assertEquals( byte[].class, ClassUtils.getClass( "byte[]" ) );
878 assertEquals( char[].class, ClassUtils.getClass( "char[]" ) );
879 assertEquals( float[].class, ClassUtils.getClass( "float[]" ) );
880 assertEquals( double[].class, ClassUtils.getClass( "double[]" ) );
881 assertEquals( boolean[].class, ClassUtils.getClass( "boolean[]" ) );
882 assertEquals( String[].class, ClassUtils.getClass( "java.lang.String[]" ) );
883 assertEquals( java.util.Map.Entry[].class, ClassUtils.getClass( "java.util.Map.Entry[]" ) );
884 assertEquals( java.util.Map.Entry[].class, ClassUtils.getClass( "java.util.Map$Entry[]" ) );
885 assertEquals( java.util.Map.Entry[].class, ClassUtils.getClass( "[Ljava.util.Map.Entry;" ) );
886 assertEquals( java.util.Map.Entry[].class, ClassUtils.getClass( "[Ljava.util.Map$Entry;" ) );
887 }
888
889 public void testGetClassByNormalNameArrays2D() throws ClassNotFoundException {
890 assertEquals( int[][].class, ClassUtils.getClass( "int[][]" ) );
891 assertEquals( long[][].class, ClassUtils.getClass( "long[][]" ) );
892 assertEquals( short[][].class, ClassUtils.getClass( "short[][]" ) );
893 assertEquals( byte[][].class, ClassUtils.getClass( "byte[][]" ) );
894 assertEquals( char[][].class, ClassUtils.getClass( "char[][]" ) );
895 assertEquals( float[][].class, ClassUtils.getClass( "float[][]" ) );
896 assertEquals( double[][].class, ClassUtils.getClass( "double[][]" ) );
897 assertEquals( boolean[][].class, ClassUtils.getClass( "boolean[][]" ) );
898 assertEquals( String[][].class, ClassUtils.getClass( "java.lang.String[][]" ) );
899 }
900
901 public void testGetClassWithArrayClasses2D() throws Exception {
902 assertGetClassReturnsClass( String[][].class );
903 assertGetClassReturnsClass( int[][].class );
904 assertGetClassReturnsClass( long[][].class );
905 assertGetClassReturnsClass( short[][].class );
906 assertGetClassReturnsClass( byte[][].class );
907 assertGetClassReturnsClass( char[][].class );
908 assertGetClassReturnsClass( float[][].class );
909 assertGetClassReturnsClass( double[][].class );
910 assertGetClassReturnsClass( boolean[][].class );
911 }
912
913 public void testGetClassWithArrayClasses() throws Exception {
914 assertGetClassReturnsClass( String[].class );
915 assertGetClassReturnsClass( int[].class );
916 assertGetClassReturnsClass( long[].class );
917 assertGetClassReturnsClass( short[].class );
918 assertGetClassReturnsClass( byte[].class );
919 assertGetClassReturnsClass( char[].class );
920 assertGetClassReturnsClass( float[].class );
921 assertGetClassReturnsClass( double[].class );
922 assertGetClassReturnsClass( boolean[].class );
923 }
924
925 public void testGetClassRawPrimitives() throws ClassNotFoundException {
926 assertEquals( int.class, ClassUtils.getClass( "int" ) );
927 assertEquals( long.class, ClassUtils.getClass( "long" ) );
928 assertEquals( short.class, ClassUtils.getClass( "short" ) );
929 assertEquals( byte.class, ClassUtils.getClass( "byte" ) );
930 assertEquals( char.class, ClassUtils.getClass( "char" ) );
931 assertEquals( float.class, ClassUtils.getClass( "float" ) );
932 assertEquals( double.class, ClassUtils.getClass( "double" ) );
933 assertEquals( boolean.class, ClassUtils.getClass( "boolean" ) );
934 }
935
936 private void assertGetClassReturnsClass( Class<?> c ) throws Exception {
937 assertEquals( c, ClassUtils.getClass( c.getName() ) );
938 }
939
940 private void assertGetClassThrowsException( String className, Class<?> exceptionType ) throws Exception {
941 try {
942 ClassUtils.getClass( className );
943 fail( "ClassUtils.getClass() should fail with an exception of type " + exceptionType.getName() + " when given class name \"" + className + "\"." );
944 }
945 catch( Exception e ) {
946 assertTrue( exceptionType.isAssignableFrom( e.getClass() ) );
947 }
948 }
949
950 private void assertGetClassThrowsNullPointerException( String className ) throws Exception {
951 assertGetClassThrowsException( className, NullPointerException.class );
952 }
953
954 private void assertGetClassThrowsClassNotFound( String className ) throws Exception {
955 assertGetClassThrowsException( className, ClassNotFoundException.class );
956 }
957
958 // Show the Java bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957
959 // We may have to delete this if a JDK fixes the bug.
960 public void testShowJavaBug() throws Exception {
961 // Tests with Collections$UnmodifiableSet
962 Set<?> set = Collections.unmodifiableSet(new HashSet<Object>());
963 Method isEmptyMethod = set.getClass().getMethod("isEmpty", new Class[0]);
964 try {
965 isEmptyMethod.invoke(set, new Object[0]);
966 fail("Failed to throw IllegalAccessException as expected");
967 } catch(IllegalAccessException iae) {
968 // expected
969 }
970 }
971
972 public void testGetPublicMethod() throws Exception {
973 // Tests with Collections$UnmodifiableSet
974 Set<?> set = Collections.unmodifiableSet(new HashSet<Object>());
975 Method isEmptyMethod = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
976 assertTrue(Modifier.isPublic(isEmptyMethod.getDeclaringClass().getModifiers()));
977
978 try {
979 isEmptyMethod.invoke(set, new Object[0]);
980 } catch(java.lang.IllegalAccessException iae) {
981 fail("Should not have thrown IllegalAccessException");
982 }
983
984 // Tests with a public Class
985 Method toStringMethod = ClassUtils.getPublicMethod(Object.class, "toString", new Class[0]);
986 assertEquals(Object.class.getMethod("toString", new Class[0]), toStringMethod);
987 }
988
989 public void testToClass_object() {
990 // assertNull(ClassUtils.toClass(null)); // generates warning
991 assertNull(ClassUtils.toClass((Object[]) null)); // equivalent explicit cast
992
993 // Additional varargs tests
994 assertTrue("empty -> empty", Arrays.equals(ArrayUtils.EMPTY_CLASS_ARRAY, ClassUtils.toClass()));
995 Class<?>[] castNull = ClassUtils.toClass((Object) null); // == new Object[]{null}
996 assertTrue("(Object)null -> [null]", Arrays.equals(new Object[]{null}, castNull));
997
998 assertSame(ArrayUtils.EMPTY_CLASS_ARRAY, ClassUtils.toClass(ArrayUtils.EMPTY_OBJECT_ARRAY));
999
1000 assertTrue(Arrays.equals(new Class[] { String.class, Integer.class, Double.class },
1001 ClassUtils.toClass(new Object[] { "Test", Integer.valueOf(1), Double.valueOf(99d) })));
1002
1003 assertTrue(Arrays.equals(new Class[] { String.class, null, Double.class },
1004 ClassUtils.toClass(new Object[] { "Test", null, Double.valueOf(99d) })));
1005 }
1006
1007 public void test_getShortCanonicalName_Object() {
1008 assertEquals("<null>", ClassUtils.getShortCanonicalName(null, "<null>"));
1009 assertEquals("ClassUtils", ClassUtils.getShortCanonicalName(new ClassUtils(), "<null>"));
1010 assertEquals("ClassUtils[]", ClassUtils.getShortCanonicalName(new ClassUtils[0], "<null>"));
1011 assertEquals("ClassUtils[][]", ClassUtils.getShortCanonicalName(new ClassUtils[0][0], "<null>"));
1012 assertEquals("int[]", ClassUtils.getShortCanonicalName(new int[0], "<null>"));
1013 assertEquals("int[][]", ClassUtils.getShortCanonicalName(new int[0][0], "<null>"));
1014
1015 // Inner types
1016 class Named extends Object {};
1017 assertEquals("ClassUtilsTest.6", ClassUtils.getShortCanonicalName(new Object(){}, "<null>"));
1018 assertEquals("ClassUtilsTest.5Named", ClassUtils.getShortCanonicalName(new Named(), "<null>"));
1019 assertEquals("ClassUtilsTest.Inner", ClassUtils.getShortCanonicalName(new Inner(), "<null>"));
1020 }
1021
1022 public void test_getShortCanonicalName_Class() {
1023 assertEquals("ClassUtils", ClassUtils.getShortCanonicalName(ClassUtils.class));
1024 assertEquals("ClassUtils[]", ClassUtils.getShortCanonicalName(ClassUtils[].class));
1025 assertEquals("ClassUtils[][]", ClassUtils.getShortCanonicalName(ClassUtils[][].class));
1026 assertEquals("int[]", ClassUtils.getShortCanonicalName(int[].class));
1027 assertEquals("int[][]", ClassUtils.getShortCanonicalName(int[][].class));
1028
1029 // Inner types
1030 class Named extends Object {};
1031 assertEquals("ClassUtilsTest.7", ClassUtils.getShortCanonicalName(new Object(){}.getClass()));
1032 assertEquals("ClassUtilsTest.6Named", ClassUtils.getShortCanonicalName(Named.class));
1033 assertEquals("ClassUtilsTest.Inner", ClassUtils.getShortCanonicalName(Inner.class));
1034 }
1035
1036 public void test_getShortCanonicalName_String() {
1037 assertEquals("ClassUtils", ClassUtils.getShortCanonicalName("org.apache.commons.lang3.ClassUtils"));
1038 assertEquals("ClassUtils[]", ClassUtils.getShortCanonicalName("[Lorg.apache.commons.lang3.ClassUtils;"));
1039 assertEquals("ClassUtils[][]", ClassUtils.getShortCanonicalName("[[Lorg.apache.commons.lang3.ClassUtils;"));
1040 assertEquals("ClassUtils[]", ClassUtils.getShortCanonicalName("org.apache.commons.lang3.ClassUtils[]"));
1041 assertEquals("ClassUtils[][]", ClassUtils.getShortCanonicalName("org.apache.commons.lang3.ClassUtils[][]"));
1042 assertEquals("int[]", ClassUtils.getShortCanonicalName("[I"));
1043 assertEquals("int[][]", ClassUtils.getShortCanonicalName("[[I"));
1044 assertEquals("int[]", ClassUtils.getShortCanonicalName("int[]"));
1045 assertEquals("int[][]", ClassUtils.getShortCanonicalName("int[][]"));
1046
1047 // Inner types
1048 assertEquals("ClassUtilsTest.6", ClassUtils.getShortCanonicalName("org.apache.commons.lang3.ClassUtilsTest$6"));
1049 assertEquals("ClassUtilsTest.5Named", ClassUtils.getShortCanonicalName("org.apache.commons.lang3.ClassUtilsTest$5Named"));
1050 assertEquals("ClassUtilsTest.Inner", ClassUtils.getShortCanonicalName("org.apache.commons.lang3.ClassUtilsTest$Inner"));
1051 }
1052
1053 public void test_getPackageCanonicalName_Object() {
1054 assertEquals("<null>", ClassUtils.getPackageCanonicalName(null, "<null>"));
1055 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(new ClassUtils(), "<null>"));
1056 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(new ClassUtils[0], "<null>"));
1057 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(new ClassUtils[0][0], "<null>"));
1058 assertEquals("", ClassUtils.getPackageCanonicalName(new int[0], "<null>"));
1059 assertEquals("", ClassUtils.getPackageCanonicalName(new int[0][0], "<null>"));
1060
1061 // Inner types
1062 class Named extends Object {};
1063 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(new Object(){}, "<null>"));
1064 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(new Named(), "<null>"));
1065 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(new Inner(), "<null>"));
1066 }
1067
1068 public void test_getPackageCanonicalName_Class() {
1069 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(ClassUtils.class));
1070 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(ClassUtils[].class));
1071 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(ClassUtils[][].class));
1072 assertEquals("", ClassUtils.getPackageCanonicalName(int[].class));
1073 assertEquals("", ClassUtils.getPackageCanonicalName(int[][].class));
1074
1075 // Inner types
1076 class Named extends Object {};
1077 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(new Object(){}.getClass()));
1078 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(Named.class));
1079 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName(Inner.class));
1080 }
1081
1082 public void test_getPackageCanonicalName_String() {
1083 assertEquals("org.apache.commons.lang3",
1084 ClassUtils.getPackageCanonicalName("org.apache.commons.lang3.ClassUtils"));
1085 assertEquals("org.apache.commons.lang3",
1086 ClassUtils.getPackageCanonicalName("[Lorg.apache.commons.lang3.ClassUtils;"));
1087 assertEquals("org.apache.commons.lang3",
1088 ClassUtils.getPackageCanonicalName("[[Lorg.apache.commons.lang3.ClassUtils;"));
1089 assertEquals("org.apache.commons.lang3",
1090 ClassUtils.getPackageCanonicalName("org.apache.commons.lang3.ClassUtils[]"));
1091 assertEquals("org.apache.commons.lang3",
1092 ClassUtils.getPackageCanonicalName("org.apache.commons.lang3.ClassUtils[][]"));
1093 assertEquals("", ClassUtils.getPackageCanonicalName("[I"));
1094 assertEquals("", ClassUtils.getPackageCanonicalName("[[I"));
1095 assertEquals("", ClassUtils.getPackageCanonicalName("int[]"));
1096 assertEquals("", ClassUtils.getPackageCanonicalName("int[][]"));
1097
1098 // Inner types
1099 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName("org.apache.commons.lang3.ClassUtilsTest$6"));
1100 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName("org.apache.commons.lang3.ClassUtilsTest$5Named"));
1101 assertEquals("org.apache.commons.lang3", ClassUtils.getPackageCanonicalName("org.apache.commons.lang3.ClassUtilsTest$Inner"));
1102 }
1103
1104 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one
2 * or more contributor license agreements. See the NOTICE file
3 * distributed with this work for additional information
4 * regarding copyright ownership. The ASF licenses this file
5 * to you under the Apache License, Version 2.0 (the
6 * "License"); you may not use this file except in compliance
7 * with the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 package org.apache.commons.lang3;
19
20 import static org.junit.Assert.*;
21
22 import java.util.ArrayList;
23 import java.util.EnumSet;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.junit.Test;
28
29 /**
30 *
31 * @version $Id: EnumUtilsTest.java 1149320 2011-07-21 19:11:47Z mbenson $
32 */
33 public class EnumUtilsTest {
34
35 @Test
36 public void testConstructable() {
37 // enforce public constructor
38 new EnumUtils();
39 }
40
41 @Test
42 public void test_getEnumMap() {
43 Map<String, Traffic> test = EnumUtils.getEnumMap(Traffic.class);
44 assertEquals( "getEnumMap not created correctly", "{RED=RED, AMBER=AMBER, GREEN=GREEN}", test.toString());
45 assertEquals(3, test.size());
46 assertEquals(true, test.containsKey("RED"));
47 assertEquals(Traffic.RED, test.get("RED"));
48 assertEquals(true, test.containsKey("AMBER"));
49 assertEquals(Traffic.AMBER, test.get("AMBER"));
50 assertEquals(true, test.containsKey("GREEN"));
51 assertEquals(Traffic.GREEN, test.get("GREEN"));
52 assertEquals(false, test.containsKey("PURPLE"));
53 }
54
55 @Test
56 public void test_getEnumList() {
57 List<Traffic> test = EnumUtils.getEnumList(Traffic.class);
58 assertEquals(3, test.size());
59 assertEquals(Traffic.RED, test.get(0));
60 assertEquals(Traffic.AMBER, test.get(1));
61 assertEquals(Traffic.GREEN, test.get(2));
62 }
63
64 @Test
65 public void test_isEnum() {
66 assertEquals(true, EnumUtils.isValidEnum(Traffic.class, "RED"));
67 assertEquals(true, EnumUtils.isValidEnum(Traffic.class, "AMBER"));
68 assertEquals(true, EnumUtils.isValidEnum(Traffic.class, "GREEN"));
69 assertEquals(false, EnumUtils.isValidEnum(Traffic.class, "PURPLE"));
70 assertEquals(false, EnumUtils.isValidEnum(Traffic.class, null));
71 }
72
73 @Test(expected=NullPointerException.class)
74 public void test_isEnum_nullClass() {
75 EnumUtils.isValidEnum((Class<Traffic>) null, "PURPLE");
76 }
77
78 @Test
79 public void test_getEnum() {
80 assertEquals(Traffic.RED, EnumUtils.getEnum(Traffic.class, "RED"));
81 assertEquals(Traffic.AMBER, EnumUtils.getEnum(Traffic.class, "AMBER"));
82 assertEquals(Traffic.GREEN, EnumUtils.getEnum(Traffic.class, "GREEN"));
83 assertEquals(null, EnumUtils.getEnum(Traffic.class, "PURPLE"));
84 assertEquals(null, EnumUtils.getEnum(Traffic.class, null));
85 }
86
87 @Test(expected=NullPointerException.class)
88 public void test_getEnum_nullClass() {
89 EnumUtils.getEnum((Class<Traffic>) null, "PURPLE");
90 }
91
92 @Test(expected=NullPointerException.class)
93 public void test_generateBitVector_nullClass() {
94 EnumUtils.generateBitVector(null, EnumSet.of(Traffic.RED));
95 }
96
97 @Test(expected=NullPointerException.class)
98 public void test_generateBitVector_nullIterable() {
99 EnumUtils.generateBitVector(null, (Iterable<Traffic>) null);
100 }
101
102 @Test(expected=NullPointerException.class)
103 public void test_generateBitVector_nullClassWithArray() {
104 EnumUtils.generateBitVector(null, Traffic.RED);
105 }
106
107 @Test(expected=NullPointerException.class)
108 public void test_generateBitVector_nullArray() {
109 EnumUtils.generateBitVector(null, (Traffic[]) null);
110 }
111
112 @Test(expected=IllegalArgumentException.class)
113 public void test_generateBitVector_longClass() {
114 EnumUtils.generateBitVector(TooMany.class, EnumSet.of(TooMany.A1));
115 }
116
117 @Test(expected=IllegalArgumentException.class)
118 public void test_generateBitVector_longClassWithArray() {
119 EnumUtils.generateBitVector(TooMany.class, TooMany.A1);
120 }
121
122 @SuppressWarnings("unchecked")
123 @Test(expected=IllegalArgumentException.class)
124 public void test_generateBitVector_nonEnumClass() {
125 @SuppressWarnings("rawtypes")
126 Class rawType = Object.class;
127 @SuppressWarnings("rawtypes")
128 List rawList = new ArrayList();
129 EnumUtils.generateBitVector(rawType, rawList);
130 }
131
132 @SuppressWarnings("unchecked")
133 @Test(expected=IllegalArgumentException.class)
134 public void test_generateBitVector_nonEnumClassWithArray() {
135 @SuppressWarnings("rawtypes")
136 Class rawType = Object.class;
137 EnumUtils.generateBitVector(rawType);
138 }
139
140 @Test
141 public void test_generateBitVector() {
142 assertEquals(0L, EnumUtils.generateBitVector(Traffic.class, EnumSet.noneOf(Traffic.class)));
143 assertEquals(1L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.RED)));
144 assertEquals(2L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.AMBER)));
145 assertEquals(4L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.GREEN)));
146 assertEquals(3L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.RED, Traffic.AMBER)));
147 assertEquals(5L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.RED, Traffic.GREEN)));
148 assertEquals(6L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.AMBER, Traffic.GREEN)));
149 assertEquals(7L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.RED, Traffic.AMBER, Traffic.GREEN)));
150 }
151
152 @Test
153 public void test_generateBitVectorFromArray() {
154 assertEquals(0L, EnumUtils.generateBitVector(Traffic.class));
155 assertEquals(1L, EnumUtils.generateBitVector(Traffic.class, Traffic.RED));
156 assertEquals(2L, EnumUtils.generateBitVector(Traffic.class, Traffic.AMBER));
157 assertEquals(4L, EnumUtils.generateBitVector(Traffic.class, Traffic.GREEN));
158 assertEquals(3L, EnumUtils.generateBitVector(Traffic.class, Traffic.RED, Traffic.AMBER));
159 assertEquals(5L, EnumUtils.generateBitVector(Traffic.class, Traffic.RED, Traffic.GREEN));
160 assertEquals(6L, EnumUtils.generateBitVector(Traffic.class, Traffic.AMBER, Traffic.GREEN));
161 assertEquals(7L, EnumUtils.generateBitVector(Traffic.class, Traffic.RED, Traffic.AMBER, Traffic.GREEN));
162 //gracefully handles duplicates:
163 assertEquals(7L, EnumUtils.generateBitVector(Traffic.class, Traffic.RED, Traffic.AMBER, Traffic.GREEN, Traffic.GREEN));
164 }
165
166 @Test(expected=NullPointerException.class)
167 public void test_processBitVector_nullClass() {
168 final Class<Traffic> empty = null;
169 EnumUtils.processBitVector(empty, 0L);
170 }
171
172 @Test(expected=IllegalArgumentException.class)
173 public void test_processBitVector_longClass() {
174 EnumUtils.processBitVector(TooMany.class, 0L);
175 }
176
177 @Test
178 public void test_processBitVector() {
179 assertEquals(EnumSet.noneOf(Traffic.class), EnumUtils.processBitVector(Traffic.class, 0L));
180 assertEquals(EnumSet.of(Traffic.RED), EnumUtils.processBitVector(Traffic.class, 1L));
181 assertEquals(EnumSet.of(Traffic.AMBER), EnumUtils.processBitVector(Traffic.class, 2L));
182 assertEquals(EnumSet.of(Traffic.RED, Traffic.AMBER), EnumUtils.processBitVector(Traffic.class, 3L));
183 assertEquals(EnumSet.of(Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 4L));
184 assertEquals(EnumSet.of(Traffic.RED, Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 5L));
185 assertEquals(EnumSet.of(Traffic.AMBER, Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 6L));
186 assertEquals(EnumSet.of(Traffic.RED, Traffic.AMBER, Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 7L));
187 }
188 }
189
190 enum Traffic {
191 RED, AMBER, GREEN
192 }
193
194 enum TooMany {
195 A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
196 A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,
197 A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2;
198 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one
2 * or more contributor license agreements. See the NOTICE file
3 * distributed with this work for additional information
4 * regarding copyright ownership. The ASF licenses this file
5 * to you under the Apache License, Version 2.0 (the
6 * "License"); you may not use this file except in compliance
7 * with the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 package org.apache.commons.lang3;
19
20 import static org.apache.commons.lang3.JavaVersion.JAVA_0_9;
21 import static org.apache.commons.lang3.JavaVersion.JAVA_1_1;
22 import static org.apache.commons.lang3.JavaVersion.JAVA_1_2;
23 import static org.apache.commons.lang3.JavaVersion.JAVA_1_3;
24 import static org.apache.commons.lang3.JavaVersion.JAVA_1_4;
25 import static org.apache.commons.lang3.JavaVersion.JAVA_1_5;
26 import static org.apache.commons.lang3.JavaVersion.JAVA_1_6;
27 import static org.apache.commons.lang3.JavaVersion.JAVA_1_7;
28 import static org.apache.commons.lang3.JavaVersion.JAVA_1_8;
29 import static org.apache.commons.lang3.JavaVersion.get;
30 import static org.apache.commons.lang3.JavaVersion.getJavaVersion;
31 import junit.framework.TestCase;
32
33 /**
34 * Unit tests {@link org.apache.commons.lang3.JavaVersion}.
35 *
36 * @version $Id: JavaVersionTest.java 918366 2010-03-03 08:56:22Z bayard $
37 */
38 public class JavaVersionTest extends TestCase {
39
40 public void testGetJavaVersion() {
41 assertEquals("0.9 failed", JAVA_0_9, get("0.9"));
42 assertEquals("1.1 failed", JAVA_1_1, get("1.1"));
43 assertEquals("1.2 failed", JAVA_1_2, get("1.2"));
44 assertEquals("1.3 failed", JAVA_1_3, get("1.3"));
45 assertEquals("1.4 failed", JAVA_1_4, get("1.4"));
46 assertEquals("1.5 failed", JAVA_1_5, get("1.5"));
47 assertEquals("1.6 failed", JAVA_1_6, get("1.6"));
48 assertEquals("1.7 failed", JAVA_1_7, get("1.7"));
49 assertEquals("1.8 failed", JAVA_1_8, get("1.8"));
50 assertNull("1.9 unexpectedly worked", get("1.9"));
51 assertEquals("Wrapper method failed", get("1.5"), getJavaVersion("1.5"));
52 }
53
54 public void testAtLeast() {
55 assertFalse("1.2 at least 1.5 passed", JAVA_1_2.atLeast(JAVA_1_5));
56 assertTrue("1.5 at least 1.2 failed", JAVA_1_5.atLeast(JAVA_1_2));
57 assertFalse("1.6 at least 1.7 passed", JAVA_1_6.atLeast(JAVA_1_7));
58
59 assertTrue("0.9 at least 1.5 failed", JAVA_0_9.atLeast(JAVA_1_5));
60 assertFalse("0.9 at least 1.6 passed", JAVA_0_9.atLeast(JAVA_1_6));
61 }
62
63 public void testToString() {
64 assertEquals("1.2", JAVA_1_2.toString());
65 }
66
67 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import static org.apache.commons.lang3.JavaVersion.JAVA_1_4;
19
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Modifier;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Set;
29
30 import junit.framework.TestCase;
31
32 /**
33 * Unit tests for {@link LocaleUtils}.
34 *
35 * @version $Id: LocaleUtilsTest.java 1144929 2011-07-10 18:26:16Z ggregory $
36 */
37 public class LocaleUtilsTest extends TestCase {
38
39 private static final Locale LOCALE_EN = new Locale("en", "");
40 private static final Locale LOCALE_EN_US = new Locale("en", "US");
41 private static final Locale LOCALE_EN_US_ZZZZ = new Locale("en", "US", "ZZZZ");
42 private static final Locale LOCALE_FR = new Locale("fr", "");
43 private static final Locale LOCALE_FR_CA = new Locale("fr", "CA");
44 private static final Locale LOCALE_QQ = new Locale("qq", "");
45 private static final Locale LOCALE_QQ_ZZ = new Locale("qq", "ZZ");
46
47 /**
48 * Constructor.
49 *
50 * @param name
51 */
52 public LocaleUtilsTest(String name) {
53 super(name);
54 }
55
56 @Override
57 public void setUp() throws Exception {
58 super.setUp();
59
60 // Testing #LANG-304. Must be called before availableLocaleSet is called.
61 LocaleUtils.isAvailableLocale(Locale.getDefault());
62 }
63
64 //-----------------------------------------------------------------------
65 /**
66 * Test that constructors are public, and work, etc.
67 */
68 public void testConstructor() {
69 assertNotNull(new LocaleUtils());
70 Constructor<?>[] cons = LocaleUtils.class.getDeclaredConstructors();
71 assertEquals(1, cons.length);
72 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
73 assertEquals(true, Modifier.isPublic(LocaleUtils.class.getModifiers()));
74 assertEquals(false, Modifier.isFinal(LocaleUtils.class.getModifiers()));
75 }
76
77 //-----------------------------------------------------------------------
78 /**
79 * Pass in a valid language, test toLocale.
80 *
81 * @param language the language string
82 */
83 private void assertValidToLocale(String language) {
84 Locale locale = LocaleUtils.toLocale(language);
85 assertNotNull("valid locale", locale);
86 assertEquals(language, locale.getLanguage());
87 //country and variant are empty
88 assertTrue(locale.getCountry() == null || locale.getCountry().length() == 0);
89 assertTrue(locale.getVariant() == null || locale.getVariant().length() == 0);
90 }
91
92 /**
93 * Pass in a valid language, test toLocale.
94 *
95 * @param localeString to pass to toLocale()
96 * @param language of the resulting Locale
97 * @param country of the resulting Locale
98 */
99 private void assertValidToLocale(String localeString, String language, String country) {
100 Locale locale = LocaleUtils.toLocale(localeString);
101 assertNotNull("valid locale", locale);
102 assertEquals(language, locale.getLanguage());
103 assertEquals(country, locale.getCountry());
104 //variant is empty
105 assertTrue(locale.getVariant() == null || locale.getVariant().length() == 0);
106 }
107
108 /**
109 * Pass in a valid language, test toLocale.
110 *
111 * @param localeString to pass to toLocale()
112 * @param language of the resulting Locale
113 * @param country of the resulting Locale
114 * @param variant of the resulting Locale
115 */
116 private void assertValidToLocale(
117 String localeString, String language,
118 String country, String variant) {
119 Locale locale = LocaleUtils.toLocale(localeString);
120 assertNotNull("valid locale", locale);
121 assertEquals(language, locale.getLanguage());
122 assertEquals(country, locale.getCountry());
123 assertEquals(variant, locale.getVariant());
124
125 }
126
127 /**
128 * Test toLocale() method.
129 */
130 public void testToLocale_1Part() {
131 assertEquals(null, LocaleUtils.toLocale((String) null));
132
133 assertValidToLocale("us");
134 assertValidToLocale("fr");
135 assertValidToLocale("de");
136 assertValidToLocale("zh");
137 // Valid format but lang doesnt exist, should make instance anyway
138 assertValidToLocale("qq");
139
140 try {
141 LocaleUtils.toLocale("Us");
142 fail("Should fail if not lowercase");
143 } catch (IllegalArgumentException iae) {}
144 try {
145 LocaleUtils.toLocale("US");
146 fail("Should fail if not lowercase");
147 } catch (IllegalArgumentException iae) {}
148 try {
149 LocaleUtils.toLocale("uS");
150 fail("Should fail if not lowercase");
151 } catch (IllegalArgumentException iae) {}
152 try {
153 LocaleUtils.toLocale("u#");
154 fail("Should fail if not lowercase");
155 } catch (IllegalArgumentException iae) {}
156
157 try {
158 LocaleUtils.toLocale("u");
159 fail("Must be 2 chars if less than 5");
160 } catch (IllegalArgumentException iae) {}
161
162 try {
163 LocaleUtils.toLocale("uuu");
164 fail("Must be 2 chars if less than 5");
165 } catch (IllegalArgumentException iae) {}
166
167 try {
168 LocaleUtils.toLocale("uu_U");
169 fail("Must be 2 chars if less than 5");
170 } catch (IllegalArgumentException iae) {}
171 }
172
173 /**
174 * Test toLocale() method.
175 */
176 public void testToLocale_2Part() {
177 assertValidToLocale("us_EN", "us", "EN");
178 //valid though doesnt exist
179 assertValidToLocale("us_ZH", "us", "ZH");
180
181 try {
182 LocaleUtils.toLocale("us-EN");
183 fail("Should fail as not underscore");
184 } catch (IllegalArgumentException iae) {}
185 try {
186 LocaleUtils.toLocale("us_En");
187 fail("Should fail second part not uppercase");
188 } catch (IllegalArgumentException iae) {}
189 try {
190 LocaleUtils.toLocale("us_en");
191 fail("Should fail second part not uppercase");
192 } catch (IllegalArgumentException iae) {}
193 try {
194 LocaleUtils.toLocale("us_eN");
195 fail("Should fail second part not uppercase");
196 } catch (IllegalArgumentException iae) {}
197 try {
198 LocaleUtils.toLocale("uS_EN");
199 fail("Should fail first part not lowercase");
200 } catch (IllegalArgumentException iae) {}
201 try {
202 LocaleUtils.toLocale("us_E3");
203 fail("Should fail second part not uppercase");
204 } catch (IllegalArgumentException iae) {}
205 }
206
207 /**
208 * Test toLocale() method.
209 */
210 public void testToLocale_3Part() {
211 assertValidToLocale("us_EN_A", "us", "EN", "A");
212 // this isn't pretty, but was caused by a jdk bug it seems
213 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4210525
214 if (SystemUtils.isJavaVersionAtLeast(JAVA_1_4)) {
215 assertValidToLocale("us_EN_a", "us", "EN", "a");
216 assertValidToLocale("us_EN_SFsafdFDsdfF", "us", "EN", "SFsafdFDsdfF");
217 } else {
218 assertValidToLocale("us_EN_a", "us", "EN", "A");
219 assertValidToLocale("us_EN_SFsafdFDsdfF", "us", "EN", "SFSAFDFDSDFF");
220 }
221
222 try {
223 LocaleUtils.toLocale("us_EN-a");
224 fail("Should fail as not underscore");
225 } catch (IllegalArgumentException iae) {}
226 try {
227 LocaleUtils.toLocale("uu_UU_");
228 fail("Must be 3, 5 or 7+ in length");
229 } catch (IllegalArgumentException iae) {}
230 }
231
232 //-----------------------------------------------------------------------
233 /**
234 * Helper method for local lookups.
235 *
236 * @param locale the input locale
237 * @param defaultLocale the input default locale
238 * @param expected expected results
239 */
240 private void assertLocaleLookupList(Locale locale, Locale defaultLocale, Locale[] expected) {
241 List<Locale> localeList = defaultLocale == null ?
242 LocaleUtils.localeLookupList(locale) :
243 LocaleUtils.localeLookupList(locale, defaultLocale);
244
245 assertEquals(expected.length, localeList.size());
246 assertEquals(Arrays.asList(expected), localeList);
247 assertUnmodifiableCollection(localeList);
248 }
249
250 //-----------------------------------------------------------------------
251 /**
252 * Test localeLookupList() method.
253 */
254 public void testLocaleLookupList_Locale() {
255 assertLocaleLookupList(null, null, new Locale[0]);
256 assertLocaleLookupList(LOCALE_QQ, null, new Locale[]{LOCALE_QQ});
257 assertLocaleLookupList(LOCALE_EN, null, new Locale[]{LOCALE_EN});
258 assertLocaleLookupList(LOCALE_EN, null, new Locale[]{LOCALE_EN});
259 assertLocaleLookupList(LOCALE_EN_US, null,
260 new Locale[] {
261 LOCALE_EN_US,
262 LOCALE_EN});
263 assertLocaleLookupList(LOCALE_EN_US_ZZZZ, null,
264 new Locale[] {
265 LOCALE_EN_US_ZZZZ,
266 LOCALE_EN_US,
267 LOCALE_EN});
268 }
269
270 /**
271 * Test localeLookupList() method.
272 */
273 public void testLocaleLookupList_LocaleLocale() {
274 assertLocaleLookupList(LOCALE_QQ, LOCALE_QQ,
275 new Locale[]{LOCALE_QQ});
276 assertLocaleLookupList(LOCALE_EN, LOCALE_EN,
277 new Locale[]{LOCALE_EN});
278
279 assertLocaleLookupList(LOCALE_EN_US, LOCALE_EN_US,
280 new Locale[]{
281 LOCALE_EN_US,
282 LOCALE_EN});
283 assertLocaleLookupList(LOCALE_EN_US, LOCALE_QQ,
284 new Locale[] {
285 LOCALE_EN_US,
286 LOCALE_EN,
287 LOCALE_QQ});
288 assertLocaleLookupList(LOCALE_EN_US, LOCALE_QQ_ZZ,
289 new Locale[] {
290 LOCALE_EN_US,
291 LOCALE_EN,
292 LOCALE_QQ_ZZ});
293
294 assertLocaleLookupList(LOCALE_EN_US_ZZZZ, null,
295 new Locale[] {
296 LOCALE_EN_US_ZZZZ,
297 LOCALE_EN_US,
298 LOCALE_EN});
299 assertLocaleLookupList(LOCALE_EN_US_ZZZZ, LOCALE_EN_US_ZZZZ,
300 new Locale[] {
301 LOCALE_EN_US_ZZZZ,
302 LOCALE_EN_US,
303 LOCALE_EN});
304 assertLocaleLookupList(LOCALE_EN_US_ZZZZ, LOCALE_QQ,
305 new Locale[] {
306 LOCALE_EN_US_ZZZZ,
307 LOCALE_EN_US,
308 LOCALE_EN,
309 LOCALE_QQ});
310 assertLocaleLookupList(LOCALE_EN_US_ZZZZ, LOCALE_QQ_ZZ,
311 new Locale[] {
312 LOCALE_EN_US_ZZZZ,
313 LOCALE_EN_US,
314 LOCALE_EN,
315 LOCALE_QQ_ZZ});
316 assertLocaleLookupList(LOCALE_FR_CA, LOCALE_EN,
317 new Locale[] {
318 LOCALE_FR_CA,
319 LOCALE_FR,
320 LOCALE_EN});
321 }
322
323 //-----------------------------------------------------------------------
324 /**
325 * Test availableLocaleList() method.
326 */
327 public void testAvailableLocaleList() {
328 List<Locale> list = LocaleUtils.availableLocaleList();
329 List<Locale> list2 = LocaleUtils.availableLocaleList();
330 assertNotNull(list);
331 assertSame(list, list2);
332 assertUnmodifiableCollection(list);
333
334 Locale[] jdkLocaleArray = Locale.getAvailableLocales();
335 List<Locale> jdkLocaleList = Arrays.asList(jdkLocaleArray);
336 assertEquals(jdkLocaleList, list);
337 }
338
339 //-----------------------------------------------------------------------
340 /**
341 * Test availableLocaleSet() method.
342 */
343 public void testAvailableLocaleSet() {
344 Set<Locale> set = LocaleUtils.availableLocaleSet();
345 Set<Locale> set2 = LocaleUtils.availableLocaleSet();
346 assertNotNull(set);
347 assertSame(set, set2);
348 assertUnmodifiableCollection(set);
349
350 Locale[] jdkLocaleArray = Locale.getAvailableLocales();
351 List<Locale> jdkLocaleList = Arrays.asList(jdkLocaleArray);
352 Set<Locale> jdkLocaleSet = new HashSet<Locale>(jdkLocaleList);
353 assertEquals(jdkLocaleSet, set);
354 }
355
356 //-----------------------------------------------------------------------
357 /**
358 * Test availableLocaleSet() method.
359 */
360 public void testIsAvailableLocale() {
361 Set<Locale> set = LocaleUtils.availableLocaleSet();
362 assertEquals(set.contains(LOCALE_EN), LocaleUtils.isAvailableLocale(LOCALE_EN));
363 assertEquals(set.contains(LOCALE_EN_US), LocaleUtils.isAvailableLocale(LOCALE_EN_US));
364 assertEquals(set.contains(LOCALE_EN_US_ZZZZ), LocaleUtils.isAvailableLocale(LOCALE_EN_US_ZZZZ));
365 assertEquals(set.contains(LOCALE_FR), LocaleUtils.isAvailableLocale(LOCALE_FR));
366 assertEquals(set.contains(LOCALE_FR_CA), LocaleUtils.isAvailableLocale(LOCALE_FR_CA));
367 assertEquals(set.contains(LOCALE_QQ), LocaleUtils.isAvailableLocale(LOCALE_QQ));
368 assertEquals(set.contains(LOCALE_QQ_ZZ), LocaleUtils.isAvailableLocale(LOCALE_QQ_ZZ));
369 }
370
371 //-----------------------------------------------------------------------
372 /**
373 * Make sure the language by country is correct. It checks that
374 * the LocaleUtils.languagesByCountry(country) call contains the
375 * array of languages passed in. It may contain more due to JVM
376 * variations.
377 *
378 * @param country
379 * @param languages array of languages that should be returned
380 */
381 private void assertLanguageByCountry(String country, String[] languages) {
382 List<Locale> list = LocaleUtils.languagesByCountry(country);
383 List<Locale> list2 = LocaleUtils.languagesByCountry(country);
384 assertNotNull(list);
385 assertSame(list, list2);
386 //search through langauges
387 for (String language : languages) {
388 Iterator<Locale> iterator = list.iterator();
389 boolean found = false;
390 // see if it was returned by the set
391 while (iterator.hasNext()) {
392 Locale locale = iterator.next();
393 // should have an en empty variant
394 assertTrue(locale.getVariant() == null
395 || locale.getVariant().length() == 0);
396 assertEquals(country, locale.getCountry());
397 if (language.equals(locale.getLanguage())) {
398 found = true;
399 break;
400 }
401 }
402 if (!found) {
403 fail("Cound not find language: " + language
404 + " for country: " + country);
405 }
406 }
407 assertUnmodifiableCollection(list);
408 }
409
410 /**
411 * Test languagesByCountry() method.
412 */
413 public void testLanguagesByCountry() {
414 assertLanguageByCountry(null, new String[0]);
415 assertLanguageByCountry("GB", new String[]{"en"});
416 assertLanguageByCountry("ZZ", new String[0]);
417 assertLanguageByCountry("CH", new String[]{"fr", "de", "it"});
418 }
419
420 //-----------------------------------------------------------------------
421 /**
422 * Make sure the country by language is correct. It checks that
423 * the LocaleUtils.countryByLanguage(language) call contains the
424 * array of countries passed in. It may contain more due to JVM
425 * variations.
426 *
427 *
428 * @param language
429 * @param countries array of countries that should be returned
430 */
431 private void assertCountriesByLanguage(String language, String[] countries) {
432 List<Locale> list = LocaleUtils.countriesByLanguage(language);
433 List<Locale> list2 = LocaleUtils.countriesByLanguage(language);
434 assertNotNull(list);
435 assertSame(list, list2);
436 //search through langauges
437 for (String countrie : countries) {
438 Iterator<Locale> iterator = list.iterator();
439 boolean found = false;
440 // see if it was returned by the set
441 while (iterator.hasNext()) {
442 Locale locale = iterator.next();
443 // should have an en empty variant
444 assertTrue(locale.getVariant() == null
445 || locale.getVariant().length() == 0);
446 assertEquals(language, locale.getLanguage());
447 if (countrie.equals(locale.getCountry())) {
448 found = true;
449 break;
450 }
451 }
452 if (!found) {
453 fail("Cound not find language: " + countrie
454 + " for country: " + language);
455 }
456 }
457 assertUnmodifiableCollection(list);
458 }
459
460 /**
461 * Test countriesByLanguage() method.
462 */
463 public void testCountriesByLanguage() {
464 assertCountriesByLanguage(null, new String[0]);
465 assertCountriesByLanguage("de", new String[]{"DE", "CH", "AT", "LU"});
466 assertCountriesByLanguage("zz", new String[0]);
467 assertCountriesByLanguage("it", new String[]{"IT", "CH"});
468 }
469
470 /**
471 * @param coll the collection to check
472 */
473 private static void assertUnmodifiableCollection(Collection<?> coll) {
474 try {
475 coll.add(null);
476 fail();
477 } catch (UnsupportedOperationException ex) {}
478 }
479
480 /**
481 * Tests #LANG-328 - only language+variant
482 */
483 public void testLang328() {
484 assertValidToLocale("fr__POSIX", "fr", "", "POSIX");
485 }
486
487 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import static org.junit.Assert.*;
19
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Modifier;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Calendar;
25 import java.util.Comparator;
26 import java.util.Date;
27 import java.util.List;
28
29 import org.apache.commons.lang3.exception.CloneFailedException;
30 import org.apache.commons.lang3.mutable.MutableObject;
31 import org.junit.Test;
32
33 /**
34 * Unit tests {@link org.apache.commons.lang3.ObjectUtils}.
35 *
36 * @version $Id: ObjectUtilsTest.java 1153484 2011-08-03 13:39:42Z ggregory $
37 */
38 public class ObjectUtilsTest {
39 private static final String FOO = "foo";
40 private static final String BAR = "bar";
41
42 //-----------------------------------------------------------------------
43 @Test
44 public void testConstructor() {
45 assertNotNull(new ObjectUtils());
46 Constructor<?>[] cons = ObjectUtils.class.getDeclaredConstructors();
47 assertEquals(1, cons.length);
48 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
49 assertEquals(true, Modifier.isPublic(ObjectUtils.class.getModifiers()));
50 assertEquals(false, Modifier.isFinal(ObjectUtils.class.getModifiers()));
51 }
52
53 //-----------------------------------------------------------------------
54 @Test
55 public void testIsNull() {
56 Object o = FOO;
57 Object dflt = BAR;
58 assertSame("dflt was not returned when o was null", dflt, ObjectUtils.defaultIfNull(null, dflt));
59 assertSame("dflt was returned when o was not null", o, ObjectUtils.defaultIfNull(o, dflt));
60 }
61
62 @Test
63 public void testFirstNonNull() {
64 assertEquals(null, ObjectUtils.firstNonNull(null, null));
65 assertEquals("", ObjectUtils.firstNonNull(null, ""));
66 String firstNonNullGenerics = ObjectUtils.firstNonNull(null, null, "123", "456");
67 assertEquals("123", firstNonNullGenerics);
68 assertEquals("123", ObjectUtils.firstNonNull("123", null, "456", null));
69 assertEquals(null, ObjectUtils.firstNonNull());
70 assertSame(Boolean.TRUE, ObjectUtils.firstNonNull(Boolean.TRUE));
71 assertNull(ObjectUtils.firstNonNull());
72 assertNull(ObjectUtils.firstNonNull(null, null));
73 // assertSame("123", ObjectUtils.firstNonNull(null, ObjectUtils.NULL, "123", "456"));
74 // assertSame("456", ObjectUtils.firstNonNull(ObjectUtils.NULL, "456", "123", null));
75 // assertNull(ObjectUtils.firstNonNull(null, null, ObjectUtils.NULL));
76 assertNull(ObjectUtils.firstNonNull((Object) null));
77 assertNull(ObjectUtils.firstNonNull((Object[]) null));
78 }
79
80 //-----------------------------------------------------------------------
81 @Test
82 public void testEquals() {
83 assertTrue("ObjectUtils.equals(null, null) returned false", ObjectUtils.equals(null, null));
84 assertTrue("ObjectUtils.equals(\"foo\", null) returned true", !ObjectUtils.equals(FOO, null));
85 assertTrue("ObjectUtils.equals(null, \"bar\") returned true", !ObjectUtils.equals(null, BAR));
86 assertTrue("ObjectUtils.equals(\"foo\", \"bar\") returned true", !ObjectUtils.equals(FOO, BAR));
87 assertTrue("ObjectUtils.equals(\"foo\", \"foo\") returned false", ObjectUtils.equals(FOO, FOO));
88 }
89
90 @Test
91 public void testNotEqual() {
92 assertFalse("ObjectUtils.notEqual(null, null) returned false", ObjectUtils.notEqual(null, null));
93 assertTrue("ObjectUtils.notEqual(\"foo\", null) returned true", ObjectUtils.notEqual(FOO, null));
94 assertTrue("ObjectUtils.notEqual(null, \"bar\") returned true", ObjectUtils.notEqual(null, BAR));
95 assertTrue("ObjectUtils.notEqual(\"foo\", \"bar\") returned true", ObjectUtils.notEqual(FOO, BAR));
96 assertFalse("ObjectUtils.notEqual(\"foo\", \"foo\") returned false", ObjectUtils.notEqual(FOO, FOO));
97 }
98
99 @Test
100 public void testHashCode() {
101 assertEquals(0, ObjectUtils.hashCode(null));
102 assertEquals("a".hashCode(), ObjectUtils.hashCode("a"));
103 }
104
105 @Test
106 public void testHashCodeMulti_multiple_emptyArray() {
107 Object[] array = new Object[0];
108 assertEquals(1, ObjectUtils.hashCodeMulti(array));
109 }
110
111 @Test
112 public void testHashCodeMulti_multiple_nullArray() {
113 Object[] array = null;
114 assertEquals(1, ObjectUtils.hashCodeMulti(array));
115 }
116
117 @Test
118 public void testHashCodeMulti_multiple_likeList() {
119 List<Object> list0 = new ArrayList<Object>(Arrays.asList());
120 assertEquals(list0.hashCode(), ObjectUtils.hashCodeMulti());
121
122 List<Object> list1 = new ArrayList<Object>(Arrays.asList("a"));
123 assertEquals(list1.hashCode(), ObjectUtils.hashCodeMulti("a"));
124
125 List<Object> list2 = new ArrayList<Object>(Arrays.asList("a", "b"));
126 assertEquals(list2.hashCode(), ObjectUtils.hashCodeMulti("a", "b"));
127
128 List<Object> list3 = new ArrayList<Object>(Arrays.asList("a", "b", "c"));
129 assertEquals(list3.hashCode(), ObjectUtils.hashCodeMulti("a", "b", "c"));
130 }
131
132 // /**
133 // * Show that java.util.Date and java.sql.Timestamp are apples and oranges.
134 // * Prompted by an email discussion.
135 // *
136 // * The behavior is different b/w Sun Java 1.3.1_10 and 1.4.2_03.
137 // */
138 // public void testDateEqualsJava() {
139 // long now = 1076957313284L; // Feb 16, 2004 10:49... PST
140 // java.util.Date date = new java.util.Date(now);
141 // java.sql.Timestamp realTimestamp = new java.sql.Timestamp(now);
142 // java.util.Date timestamp = realTimestamp;
143 // // sanity check 1:
144 // assertEquals(284000000, realTimestamp.getNanos());
145 // assertEquals(1076957313284L, date.getTime());
146 // //
147 // // On Sun 1.3.1_10:
148 // //junit.framework.AssertionFailedError: expected:<1076957313284> but was:<1076957313000>
149 // //
150 // //assertEquals(1076957313284L, timestamp.getTime());
151 // //
152 // //junit.framework.AssertionFailedError: expected:<1076957313284> but was:<1076957313000>
153 // //
154 // //assertEquals(1076957313284L, realTimestamp.getTime());
155 // // sanity check 2:
156 // assertEquals(date.getDay(), realTimestamp.getDay());
157 // assertEquals(date.getHours(), realTimestamp.getHours());
158 // assertEquals(date.getMinutes(), realTimestamp.getMinutes());
159 // assertEquals(date.getMonth(), realTimestamp.getMonth());
160 // assertEquals(date.getSeconds(), realTimestamp.getSeconds());
161 // assertEquals(date.getTimezoneOffset(), realTimestamp.getTimezoneOffset());
162 // assertEquals(date.getYear(), realTimestamp.getYear());
163 // //
164 // // Time values are == and equals() on Sun 1.4.2_03 but NOT on Sun 1.3.1_10:
165 // //
166 // //assertFalse("Sanity check failed: date.getTime() == timestamp.getTime()", date.getTime() == timestamp.getTime());
167 // //assertFalse("Sanity check failed: timestamp.equals(date)", timestamp.equals(date));
168 // //assertFalse("Sanity check failed: date.equals(timestamp)", date.equals(timestamp));
169 // // real test:
170 // //assertFalse("java.util.Date and java.sql.Timestamp should be equal", ObjectUtils.equals(date, timestamp));
171 // }
172
173 @Test
174 public void testIdentityToString() {
175 assertEquals(null, ObjectUtils.identityToString(null));
176 assertEquals(
177 "java.lang.String@" + Integer.toHexString(System.identityHashCode(FOO)),
178 ObjectUtils.identityToString(FOO));
179 Integer i = Integer.valueOf(90);
180 String expected = "java.lang.Integer@" + Integer.toHexString(System.identityHashCode(i));
181 assertEquals(expected, ObjectUtils.identityToString(i));
182 StringBuffer buffer = new StringBuffer();
183 ObjectUtils.identityToString(buffer, i);
184 assertEquals(expected, buffer.toString());
185
186 try {
187 ObjectUtils.identityToString(null, "tmp");
188 fail("NullPointerException expected");
189 } catch(NullPointerException npe) {
190 }
191 try {
192 ObjectUtils.identityToString(new StringBuffer(), null);
193 fail("NullPointerException expected");
194 } catch(NullPointerException npe) {
195 }
196 }
197
198 @Test
199 public void testToString_Object() {
200 assertEquals("", ObjectUtils.toString((Object) null) );
201 assertEquals(Boolean.TRUE.toString(), ObjectUtils.toString(Boolean.TRUE) );
202 }
203
204 @Test
205 public void testToString_ObjectString() {
206 assertEquals(BAR, ObjectUtils.toString((Object) null, BAR) );
207 assertEquals(Boolean.TRUE.toString(), ObjectUtils.toString(Boolean.TRUE, BAR) );
208 }
209
210 @Test
211 public void testNull() {
212 assertNotNull(ObjectUtils.NULL);
213 assertTrue(ObjectUtils.NULL instanceof ObjectUtils.Null);
214 assertSame(ObjectUtils.NULL, SerializationUtils.clone(ObjectUtils.NULL));
215 }
216
217 @Test
218 public void testMax() {
219 Calendar calendar = Calendar.getInstance();
220 Date nonNullComparable1 = calendar.getTime();
221 Date nonNullComparable2 = calendar.getTime();
222 String[] nullAray = null;
223
224 calendar.set( Calendar.YEAR, calendar.get( Calendar.YEAR ) -1 );
225 Date minComparable = calendar.getTime();
226
227 assertNotSame( nonNullComparable1, nonNullComparable2 );
228
229 assertNull(ObjectUtils.max( (String) null ) );
230 assertNull(ObjectUtils.max( nullAray ) );
231 assertSame( nonNullComparable1, ObjectUtils.max( null, nonNullComparable1 ) );
232 assertSame( nonNullComparable1, ObjectUtils.max( nonNullComparable1, null ) );
233 assertSame( nonNullComparable1, ObjectUtils.max( null, nonNullComparable1, null ) );
234 assertSame( nonNullComparable1, ObjectUtils.max( nonNullComparable1, nonNullComparable2 ) );
235 assertSame( nonNullComparable2, ObjectUtils.max( nonNullComparable2, nonNullComparable1 ) );
236 assertSame( nonNullComparable1, ObjectUtils.max( nonNullComparable1, minComparable ) );
237 assertSame( nonNullComparable1, ObjectUtils.max( minComparable, nonNullComparable1 ) );
238 assertSame( nonNullComparable1, ObjectUtils.max( null, minComparable, null, nonNullComparable1 ) );
239
240 assertNull( ObjectUtils.max((String)null, (String)null) );
241 }
242
243 @Test
244 public void testMin() {
245 Calendar calendar = Calendar.getInstance();
246 Date nonNullComparable1 = calendar.getTime();
247 Date nonNullComparable2 = calendar.getTime();
248 String[] nullAray = null;
249
250 calendar.set( Calendar.YEAR, calendar.get( Calendar.YEAR ) -1 );
251 Date minComparable = calendar.getTime();
252
253 assertNotSame( nonNullComparable1, nonNullComparable2 );
254
255 assertNull(ObjectUtils.min( (String) null ) );
256 assertNull(ObjectUtils.min( nullAray ) );
257 assertSame( nonNullComparable1, ObjectUtils.min( null, nonNullComparable1 ) );
258 assertSame( nonNullComparable1, ObjectUtils.min( nonNullComparable1, null ) );
259 assertSame( nonNullComparable1, ObjectUtils.min( null, nonNullComparable1, null ) );
260 assertSame( nonNullComparable1, ObjectUtils.min( nonNullComparable1, nonNullComparable2 ) );
261 assertSame( nonNullComparable2, ObjectUtils.min( nonNullComparable2, nonNullComparable1 ) );
262 assertSame( minComparable, ObjectUtils.min( nonNullComparable1, minComparable ) );
263 assertSame( minComparable, ObjectUtils.min( minComparable, nonNullComparable1 ) );
264 assertSame( minComparable, ObjectUtils.min( null, nonNullComparable1, null, minComparable ) );
265
266 assertNull( ObjectUtils.min((String)null, (String)null) );
267 }
268
269 /**
270 * Tests {@link ObjectUtils#compare(Comparable, Comparable, boolean)}.
271 */
272 @Test
273 public void testCompare() {
274 Integer one = Integer.valueOf(1);
275 Integer two = Integer.valueOf(2);
276 Integer nullValue = null;
277
278 assertEquals("Null Null false", 0, ObjectUtils.compare(nullValue, nullValue));
279 assertEquals("Null Null true", 0, ObjectUtils.compare(nullValue, nullValue, true));
280
281 assertEquals("Null one false", -1, ObjectUtils.compare(nullValue, one));
282 assertEquals("Null one true", 1, ObjectUtils.compare(nullValue, one, true));
283
284 assertEquals("one Null false", 1, ObjectUtils.compare(one, nullValue));
285 assertEquals("one Null true", -1, ObjectUtils.compare(one, nullValue, true));
286
287 assertEquals("one two false", -1, ObjectUtils.compare(one, two));
288 assertEquals("one two true", -1, ObjectUtils.compare(one, two, true));
289 }
290
291 @Test
292 public void testMedian() {
293 assertEquals("foo", ObjectUtils.median("foo"));
294 assertEquals("bar", ObjectUtils.median("foo", "bar"));
295 assertEquals("baz", ObjectUtils.median("foo", "bar", "baz"));
296 assertEquals("baz", ObjectUtils.median("foo", "bar", "baz", "blah"));
297 assertEquals("blah", ObjectUtils.median("foo", "bar", "baz", "blah", "wah"));
298 assertEquals(Integer.valueOf(5),
299 ObjectUtils.median(Integer.valueOf(1), Integer.valueOf(5), Integer.valueOf(10)));
300 assertEquals(
301 Integer.valueOf(7),
302 ObjectUtils.median(Integer.valueOf(5), Integer.valueOf(6), Integer.valueOf(7), Integer.valueOf(8),
303 Integer.valueOf(9)));
304 assertEquals(Integer.valueOf(6),
305 ObjectUtils.median(Integer.valueOf(5), Integer.valueOf(6), Integer.valueOf(7), Integer.valueOf(8)));
306 }
307
308 @Test(expected = NullPointerException.class)
309 public void testMedian_nullItems() {
310 ObjectUtils.median((String[]) null);
311 }
312
313 @Test(expected = IllegalArgumentException.class)
314 public void testMedian_emptyItems() {
315 ObjectUtils.<String> median();
316 }
317
318 @Test
319 public void testComparatorMedian() {
320 CharSequenceComparator cmp = new CharSequenceComparator();
321 NonComparableCharSequence foo = new NonComparableCharSequence("foo");
322 NonComparableCharSequence bar = new NonComparableCharSequence("bar");
323 NonComparableCharSequence baz = new NonComparableCharSequence("baz");
324 NonComparableCharSequence blah = new NonComparableCharSequence("blah");
325 NonComparableCharSequence wah = new NonComparableCharSequence("wah");
326 assertSame(foo, ObjectUtils.median(cmp, foo));
327 assertSame(bar, ObjectUtils.median(cmp, foo, bar));
328 assertSame(baz, ObjectUtils.median(cmp, foo, bar, baz));
329 assertSame(baz, ObjectUtils.median(cmp, foo, bar, baz, blah));
330 assertSame(blah, ObjectUtils.median(cmp, foo, bar, baz, blah, wah));
331 }
332
333 @Test(expected = NullPointerException.class)
334 public void testComparatorMedian_nullComparator() {
335 ObjectUtils.median((Comparator<CharSequence>) null, new NonComparableCharSequence("foo"));
336 }
337
338 @Test(expected = NullPointerException.class)
339 public void testComparatorMedian_nullItems() {
340 ObjectUtils.median(new CharSequenceComparator(), (CharSequence[]) null);
341 }
342
343 @Test(expected = IllegalArgumentException.class)
344 public void testComparatorMedian_emptyItems() {
345 ObjectUtils.median(new CharSequenceComparator());
346 }
347
348 @SuppressWarnings("unchecked")
349 @Test
350 public void testMode() {
351 assertNull(ObjectUtils.mode((Object[]) null));
352 assertNull(ObjectUtils.mode());
353 assertNull(ObjectUtils.mode("foo", "bar", "baz"));
354 assertNull(ObjectUtils.mode("foo", "bar", "baz", "foo", "bar"));
355 assertEquals("foo", ObjectUtils.mode("foo", "bar", "baz", "foo"));
356 assertEquals(Integer.valueOf(9),
357 ObjectUtils.mode("foo", "bar", "baz", Integer.valueOf(9), Integer.valueOf(10), Integer.valueOf(9)));
358 }
359
360 /**
361 * Tests {@link ObjectUtils#clone(Object)} with a cloneable object.
362 */
363 @Test
364 public void testCloneOfCloneable() {
365 final CloneableString string = new CloneableString("apache");
366 final CloneableString stringClone = ObjectUtils.clone(string);
367 assertEquals("apache", stringClone.getValue());
368 }
369
370 /**
371 * Tests {@link ObjectUtils#clone(Object)} with a not cloneable object.
372 */
373 @Test
374 public void testCloneOfNotCloneable() {
375 final String string = new String("apache");
376 assertNull(ObjectUtils.clone(string));
377 }
378
379 /**
380 * Tests {@link ObjectUtils#clone(Object)} with an uncloneable object.
381 */
382 @Test(expected = NoSuchMethodException.class)
383 public void testCloneOfUncloneable() throws Throwable {
384 final UncloneableString string = new UncloneableString("apache");
385 try {
386 ObjectUtils.clone(string);
387 fail("Thrown " + CloneFailedException.class.getName() + " expected");
388 } catch (final CloneFailedException e) {
389 throw e.getCause();
390 }
391 }
392
393 /**
394 * Tests {@link ObjectUtils#clone(Object)} with an object array.
395 */
396 @Test
397 public void testCloneOfStringArray() {
398 assertTrue(Arrays.deepEquals(
399 new String[]{"string"}, ObjectUtils.clone(new String[]{"string"})));
400 }
401
402 /**
403 * Tests {@link ObjectUtils#clone(Object)} with an array of primitives.
404 */
405 @Test
406 public void testCloneOfPrimitiveArray() {
407 assertTrue(Arrays.equals(new int[]{1}, ObjectUtils.clone(new int[]{1})));
408 }
409
410 /**
411 * Tests {@link ObjectUtils#cloneIfPossible(Object)} with a cloneable object.
412 */
413 @Test
414 public void testPossibleCloneOfCloneable() {
415 final CloneableString string = new CloneableString("apache");
416 final CloneableString stringClone = ObjectUtils.cloneIfPossible(string);
417 assertEquals("apache", stringClone.getValue());
418 }
419
420 /**
421 * Tests {@link ObjectUtils#cloneIfPossible(Object)} with a not cloneable object.
422 */
423 @Test
424 public void testPossibleCloneOfNotCloneable() {
425 final String string = new String("apache");
426 assertSame(string, ObjectUtils.cloneIfPossible(string));
427 }
428
429 /**
430 * Tests {@link ObjectUtils#cloneIfPossible(Object)} with an uncloneable object.
431 */
432 @Test(expected = NoSuchMethodException.class)
433 public void testPossibleCloneOfUncloneable() throws Throwable {
434 final UncloneableString string = new UncloneableString("apache");
435 try {
436 ObjectUtils.cloneIfPossible(string);
437 fail("Thrown " + CloneFailedException.class.getName() + " expected");
438 } catch (final CloneFailedException e) {
439 throw e.getCause();
440 }
441 }
442
443 /**
444 * String that is cloneable.
445 */
446 static final class CloneableString extends MutableObject<String> implements Cloneable {
447 private static final long serialVersionUID = 1L;
448 CloneableString(final String s) {
449 super(s);
450 }
451
452 @Override
453 public CloneableString clone() throws CloneNotSupportedException {
454 return (CloneableString)super.clone();
455 }
456 }
457
458 /**
459 * String that is not cloneable.
460 */
461 static final class UncloneableString extends MutableObject<String> implements Cloneable {
462 private static final long serialVersionUID = 1L;
463 UncloneableString(final String s) {
464 super(s);
465 }
466 }
467
468 static final class NonComparableCharSequence implements CharSequence {
469 final String value;
470
471 /**
472 * Create a new NonComparableCharSequence instance.
473 *
474 * @param value
475 */
476 public NonComparableCharSequence(String value) {
477 super();
478 Validate.notNull(value);
479 this.value = value;
480 }
481
482 public char charAt(int arg0) {
483 return value.charAt(arg0);
484 }
485
486 public int length() {
487 return value.length();
488 }
489
490 public CharSequence subSequence(int arg0, int arg1) {
491 return value.subSequence(arg0, arg1);
492 }
493
494 @Override
495 public String toString() {
496 return value;
497 }
498 }
499
500 static final class CharSequenceComparator implements Comparator<CharSequence> {
501
502 public int compare(CharSequence o1, CharSequence o2) {
503 return o1.toString().compareTo(o2.toString());
504 }
505
506 }
507 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.Modifier;
20 import java.util.Random;
21
22 /**
23 * Unit tests {@link org.apache.commons.lang3.RandomStringUtils}.
24 *
25 * @version $Id: RandomStringUtilsTest.java 1088899 2011-04-05 05:31:27Z bayard $
26 */
27 public class RandomStringUtilsTest extends junit.framework.TestCase {
28 /**
29 * Construct a new instance of RandomStringUtilsTest with the specified name
30 */
31 public RandomStringUtilsTest(String name) {
32 super(name);
33 }
34
35 //-----------------------------------------------------------------------
36 public void testConstructor() {
37 assertNotNull(new RandomStringUtils());
38 Constructor<?>[] cons = RandomStringUtils.class.getDeclaredConstructors();
39 assertEquals(1, cons.length);
40 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
41 assertEquals(true, Modifier.isPublic(RandomStringUtils.class.getModifiers()));
42 assertEquals(false, Modifier.isFinal(RandomStringUtils.class.getModifiers()));
43 }
44
45 //-----------------------------------------------------------------------
46 /**
47 * Test the implementation
48 */
49 public void testRandomStringUtils() {
50 String r1 = RandomStringUtils.random(50);
51 assertEquals("random(50) length", 50, r1.length());
52 String r2 = RandomStringUtils.random(50);
53 assertEquals("random(50) length", 50, r2.length());
54 assertTrue("!r1.equals(r2)", !r1.equals(r2));
55
56 r1 = RandomStringUtils.randomAscii(50);
57 assertEquals("randomAscii(50) length", 50, r1.length());
58 for(int i = 0; i < r1.length(); i++) {
59 assertTrue("char between 32 and 127", r1.charAt(i) >= 32 && r1.charAt(i) <= 127);
60 }
61 r2 = RandomStringUtils.randomAscii(50);
62 assertTrue("!r1.equals(r2)", !r1.equals(r2));
63
64 r1 = RandomStringUtils.randomAlphabetic(50);
65 assertEquals("randomAlphabetic(50)", 50, r1.length());
66 for(int i = 0; i < r1.length(); i++) {
67 assertEquals("r1 contains alphabetic", true, Character.isLetter(r1.charAt(i)) && !Character.isDigit(r1.charAt(i)));
68 }
69 r2 = RandomStringUtils.randomAlphabetic(50);
70 assertTrue("!r1.equals(r2)", !r1.equals(r2));
71
72 r1 = RandomStringUtils.randomAlphanumeric(50);
73 assertEquals("randomAlphanumeric(50)", 50, r1.length());
74 for(int i = 0; i < r1.length(); i++) {
75 assertEquals("r1 contains alphanumeric", true, Character.isLetterOrDigit(r1.charAt(i)));
76 }
77 r2 = RandomStringUtils.randomAlphabetic(50);
78 assertTrue("!r1.equals(r2)", !r1.equals(r2));
79
80 r1 = RandomStringUtils.randomNumeric(50);
81 assertEquals("randomNumeric(50)", 50, r1.length());
82 for(int i = 0; i < r1.length(); i++) {
83 assertEquals("r1 contains numeric", true, Character.isDigit(r1.charAt(i)) && !Character.isLetter(r1.charAt(i)));
84 }
85 r2 = RandomStringUtils.randomNumeric(50);
86 assertTrue("!r1.equals(r2)", !r1.equals(r2));
87
88 String set = "abcdefg";
89 r1 = RandomStringUtils.random(50, set);
90 assertEquals("random(50, \"abcdefg\")", 50, r1.length());
91 for(int i = 0; i < r1.length(); i++) {
92 assertTrue("random char in set", set.indexOf(r1.charAt(i)) > -1);
93 }
94 r2 = RandomStringUtils.random(50, set);
95 assertTrue("!r1.equals(r2)", !r1.equals(r2));
96
97 r1 = RandomStringUtils.random(50, (String) null);
98 assertEquals("random(50) length", 50, r1.length());
99 r2 = RandomStringUtils.random(50, (String) null);
100 assertEquals("random(50) length", 50, r2.length());
101 assertTrue("!r1.equals(r2)", !r1.equals(r2));
102
103 set = "stuvwxyz";
104 r1 = RandomStringUtils.random(50, set.toCharArray());
105 assertEquals("random(50, \"stuvwxyz\")", 50, r1.length());
106 for(int i = 0; i < r1.length(); i++) {
107 assertTrue("random char in set", set.indexOf(r1.charAt(i)) > -1);
108 }
109 r2 = RandomStringUtils.random(50, set);
110 assertTrue("!r1.equals(r2)", !r1.equals(r2));
111
112 r1 = RandomStringUtils.random(50, (char[]) null);
113 assertEquals("random(50) length", 50, r1.length());
114 r2 = RandomStringUtils.random(50, (char[]) null);
115 assertEquals("random(50) length", 50, r2.length());
116 assertTrue("!r1.equals(r2)", !r1.equals(r2));
117
118 long seed = System.currentTimeMillis();
119 r1 = RandomStringUtils.random(50,0,0,true,true,null,new Random(seed));
120 r2 = RandomStringUtils.random(50,0,0,true,true,null,new Random(seed));
121 assertEquals("r1.equals(r2)", r1, r2);
122
123 r1 = RandomStringUtils.random(0);
124 assertEquals("random(0).equals(\"\")", "", r1);
125
126 }
127 public void testExceptions() {
128 try {
129 RandomStringUtils.random(-1);
130 fail();
131 } catch (IllegalArgumentException ex) {}
132 try {
133 RandomStringUtils.random(-1, true, true);
134 fail();
135 } catch (IllegalArgumentException ex) {}
136 try {
137 RandomStringUtils.random(-1, new char[0]);
138 fail();
139 } catch (IllegalArgumentException ex) {}
140 try {
141 RandomStringUtils.random(-1, "");
142 fail();
143 } catch (IllegalArgumentException ex) {}
144 try {
145 RandomStringUtils.random(-1, 'a', 'z', false, false);
146 fail();
147 } catch (IllegalArgumentException ex) {}
148 try {
149 RandomStringUtils.random(-1, 'a', 'z', false, false, new char[0]);
150 fail();
151 } catch (IllegalArgumentException ex) {}
152 try {
153 RandomStringUtils.random(-1, 'a', 'z', false, false, new char[0], new Random());
154 fail();
155 } catch (IllegalArgumentException ex) {}
156 }
157
158 /**
159 * Make sure boundary alphanumeric characters are generated by randomAlphaNumeric
160 * This test will fail randomly with probability = 6 * (61/62)**1000 ~ 5.2E-7
161 */
162 public void testRandomAlphaNumeric() {
163 char[] testChars = {'a', 'z', 'A', 'Z', '0', '9'};
164 boolean[] found = {false, false, false, false, false, false};
165 for (int i = 0; i < 100; i++) {
166 String randString = RandomStringUtils.randomAlphanumeric(10);
167 for (int j = 0; j < testChars.length; j++) {
168 if (randString.indexOf(testChars[j]) > 0) {
169 found[j] = true;
170 }
171 }
172 }
173 for (int i = 0; i < testChars.length; i++) {
174 if (!found[i]) {
175 fail("alphanumeric character not generated in 1000 attempts: "
176 + testChars[i] +" -- repeated failures indicate a problem ");
177 }
178 }
179 }
180
181 /**
182 * Make sure '0' and '9' are generated by randomNumeric
183 * This test will fail randomly with probability = 2 * (9/10)**1000 ~ 3.5E-46
184 */
185 public void testRandomNumeric() {
186 char[] testChars = {'0','9'};
187 boolean[] found = {false, false};
188 for (int i = 0; i < 100; i++) {
189 String randString = RandomStringUtils.randomNumeric(10);
190 for (int j = 0; j < testChars.length; j++) {
191 if (randString.indexOf(testChars[j]) > 0) {
192 found[j] = true;
193 }
194 }
195 }
196 for (int i = 0; i < testChars.length; i++) {
197 if (!found[i]) {
198 fail("digit not generated in 1000 attempts: "
199 + testChars[i] +" -- repeated failures indicate a problem ");
200 }
201 }
202 }
203
204 /**
205 * Make sure boundary alpha characters are generated by randomAlphabetic
206 * This test will fail randomly with probability = 4 * (51/52)**1000 ~ 1.58E-8
207 */
208 public void testRandomAlphabetic() {
209 char[] testChars = {'a', 'z', 'A', 'Z'};
210 boolean[] found = {false, false, false, false};
211 for (int i = 0; i < 100; i++) {
212 String randString = RandomStringUtils.randomAlphabetic(10);
213 for (int j = 0; j < testChars.length; j++) {
214 if (randString.indexOf(testChars[j]) > 0) {
215 found[j] = true;
216 }
217 }
218 }
219 for (int i = 0; i < testChars.length; i++) {
220 if (!found[i]) {
221 fail("alphanumeric character not generated in 1000 attempts: "
222 + testChars[i] +" -- repeated failures indicate a problem ");
223 }
224 }
225 }
226
227 /**
228 * Make sure 32 and 127 are generated by randomNumeric
229 * This test will fail randomly with probability = 2*(95/96)**1000 ~ 5.7E-5
230 */
231 public void testRandomAscii() {
232 char[] testChars = {(char) 32, (char) 126};
233 boolean[] found = {false, false};
234 for (int i = 0; i < 100; i++) {
235 String randString = RandomStringUtils.randomAscii(10);
236 for (int j = 0; j < testChars.length; j++) {
237 if (randString.indexOf(testChars[j]) > 0) {
238 found[j] = true;
239 }
240 }
241 }
242 for (int i = 0; i < testChars.length; i++) {
243 if (!found[i]) {
244 fail("ascii character not generated in 1000 attempts: "
245 + (int) testChars[i] +
246 " -- repeated failures indicate a problem");
247 }
248 }
249 }
250
251 /**
252 * Test homogeneity of random strings generated --
253 * i.e., test that characters show up with expected frequencies
254 * in generated strings. Will fail randomly about 1 in 1000 times.
255 * Repeated failures indicate a problem.
256 */
257 public void testRandomStringUtilsHomog() {
258 String set = "abc";
259 char[] chars = set.toCharArray();
260 String gen = "";
261 int[] counts = {0,0,0};
262 int[] expected = {200,200,200};
263 for (int i = 0; i< 100; i++) {
264 gen = RandomStringUtils.random(6,chars);
265 for (int j = 0; j < 6; j++) {
266 switch (gen.charAt(j)) {
267 case 'a': {counts[0]++; break;}
268 case 'b': {counts[1]++; break;}
269 case 'c': {counts[2]++; break;}
270 default: {fail("generated character not in set");}
271 }
272 }
273 }
274 // Perform chi-square test with df = 3-1 = 2, testing at .001 level
275 assertTrue("test homogeneity -- will fail about 1 in 1000 times",
276 chiSquare(expected,counts) < 13.82);
277 }
278
279 /**
280 * Computes Chi-Square statistic given observed and expected counts
281 * @param observed array of observed frequency counts
282 * @param expected array of expected frequency counts
283 */
284 private double chiSquare(int[] expected, int[] observed) {
285 double sumSq = 0.0d;
286 double dev = 0.0d;
287 for (int i = 0; i < observed.length; i++) {
288 dev = (observed[i] - expected[i]);
289 sumSq += dev * dev / expected[i];
290 }
291 return sumSq;
292 }
293
294 /**
295 * Checks if the string got by {@link RandomStringUtils#random(int)}
296 * can be converted to UTF-8 and back without loss.
297 *
298 * @see <a href="http://issues.apache.org/jira/browse/LANG-100">LANG-100</a>
299 *
300 * @throws Exception
301 */
302 public void testLang100() throws Exception {
303 int size = 5000;
304 String encoding = "UTF-8";
305 String orig = RandomStringUtils.random(size);
306 byte[] bytes = orig.getBytes(encoding);
307 String copy = new String(bytes, encoding);
308
309 // for a verbose compare:
310 for (int i=0; i < orig.length() && i < copy.length(); i++) {
311 char o = orig.charAt(i);
312 char c = copy.charAt(i);
313 assertEquals("differs at " + i + "(" + Integer.toHexString((new Character(o)).hashCode()) + "," +
314 Integer.toHexString((new Character(c)).hashCode()) + ")", o, c);
315 }
316 // compare length also
317 assertEquals(orig.length(), copy.length());
318 // just to be complete
319 assertEquals(orig, copy);
320 }
321 }
322
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3;
18
19 import static org.junit.Assert.*;
20
21 import java.util.Comparator;
22
23 import org.junit.Before;
24 import org.junit.Test;
25
26 /**
27 * <p>
28 * Tests the methods in the {@link org.apache.commons.lang3.Range} class.
29 * </p>
30 *
31 * @version $Id: RangeTest.java 1147537 2011-07-17 06:10:37Z mbenson $
32 */
33 @SuppressWarnings("boxing")
34 public class RangeTest {
35
36 private Range<Byte> byteRange;
37 private Range<Byte> byteRange2;
38 private Range<Byte> byteRange3;
39
40 private Range<Integer> intRange;
41 private Range<Long> longRange;
42 private Range<Float> floatRange;
43 private Range<Double> doubleRange;
44
45 @SuppressWarnings("cast") // intRange
46 @Before
47 public void setUp() {
48 byteRange = Range.between((byte) 0, (byte) 5);
49 byteRange2 = Range.between((byte) 0, (byte) 5);
50 byteRange3 = Range.between((byte) 0, (byte) 10);
51
52 intRange = Range.between((int) 10, (int) 20);
53 longRange = Range.between((long) 10, (long) 20);
54 floatRange = Range.between((float) 10, (float) 20);
55 doubleRange = Range.between((double) 10, (double) 20);
56 }
57
58 //-----------------------------------------------------------------------
59 @SuppressWarnings({ "rawtypes", "unchecked" })
60 @Test
61 public void testComparableConstructors() {
62 Comparable c =
63 new Comparable() {
64 public int compareTo(Object other) {
65 return 1;
66 }
67 };
68 Range r1 = Range.is(c);
69 Range r2 = Range.between(c, c);
70 assertEquals(true, r1.isNaturalOrdering());
71 assertEquals(true, r2.isNaturalOrdering());
72 }
73
74 @Test
75 public void testIsWithCompare(){
76 Comparator<Integer> c = new Comparator<Integer>(){
77 public int compare(Integer o1, Integer o2) {
78 return 0; // all integers are equal
79 }
80 };
81 Range<Integer> ri = Range.is(10);
82 assertFalse("should not contain null",ri.contains(null));
83 assertTrue("should contain 10",ri.contains(10));
84 assertFalse("should not contain 11",ri.contains(11));
85 ri = Range.is(10,c);
86 assertFalse("should not contain null",ri.contains(null));
87 assertTrue("should contain 10",ri.contains(10));
88 assertTrue("should contain 11",ri.contains(11));
89 }
90
91 @Test
92 public void testBetweenWithCompare(){
93 // TODO add tests with a better comparator
94 Comparator<Integer> c = new Comparator<Integer>(){
95 public int compare(Integer o1, Integer o2) {
96 return 0; // all integers are equal
97 }
98 };
99 Range<Integer> rb = Range.between(-10,20);
100 assertFalse("should not contain null",rb.contains(null));
101 assertTrue("should contain 10",rb.contains(10));
102 assertTrue("should contain -10",rb.contains(-10));
103 assertFalse("should not contain 21",rb.contains(21));
104 assertFalse("should not contain -11",rb.contains(-11));
105 rb = Range.between(-10,20,c);
106 assertFalse("should not contain null",rb.contains(null));
107 assertTrue("should contain 10",rb.contains(10));
108 assertTrue("should contain -10",rb.contains(-10));
109 assertTrue("should contain 21",rb.contains(21));
110 assertTrue("should contain -11",rb.contains(-11));
111 }
112
113 //-----------------------------------------------------------------------
114 @Test
115 public void testRangeOfChars() {
116 Range<Character> chars = Range.between('a', 'z');
117 assertTrue(chars.contains('b'));
118 assertFalse(chars.contains('B'));
119 }
120
121 //-----------------------------------------------------------------------
122 @Test
123 public void testEqualsObject() {
124 assertEquals(byteRange, byteRange);
125 assertEquals(byteRange, byteRange2);
126 assertEquals(byteRange2, byteRange2);
127 assertTrue(byteRange.equals(byteRange));
128 assertTrue(byteRange2.equals(byteRange2));
129 assertTrue(byteRange3.equals(byteRange3));
130 assertFalse(byteRange2.equals(byteRange3));
131 assertFalse(byteRange2.equals(null));
132 assertFalse(byteRange2.equals("Ni!"));
133 }
134
135 @Test
136 public void testHashCode() {
137 assertEquals(byteRange.hashCode(), byteRange2.hashCode());
138 assertFalse(byteRange.hashCode() == byteRange3.hashCode());
139
140 assertEquals(intRange.hashCode(), intRange.hashCode());
141 assertTrue(intRange.hashCode() != 0);
142 }
143
144 @Test
145 public void testToString() {
146 assertNotNull(byteRange.toString());
147
148 String str = intRange.toString();
149 assertEquals("[10..20]", str);
150 assertEquals("[-20..-10]", Range.between(-20, -10).toString());
151 }
152
153 @Test
154 public void testToStringFormat() {
155 String str = intRange.toString("From %1$s to %2$s");
156 assertEquals("From 10 to 20", str);
157 }
158
159 //-----------------------------------------------------------------------
160 @Test
161 public void testGetMinimum() {
162 assertEquals(10, (int) intRange.getMinimum());
163 assertEquals(10L, (long) longRange.getMinimum());
164 assertEquals(10f, floatRange.getMinimum(), 0.00001f);
165 assertEquals(10d, doubleRange.getMinimum(), 0.00001d);
166 }
167
168 @Test
169 public void testGetMaximum() {
170 assertEquals(20, (int) intRange.getMaximum());
171 assertEquals(20L, (long) longRange.getMaximum());
172 assertEquals(20f, floatRange.getMaximum(), 0.00001f);
173 assertEquals(20d, doubleRange.getMaximum(), 0.00001d);
174 }
175
176 @Test
177 public void testContains() {
178 assertFalse(intRange.contains(null));
179
180 assertFalse(intRange.contains(5));
181 assertTrue(intRange.contains(10));
182 assertTrue(intRange.contains(15));
183 assertTrue(intRange.contains(20));
184 assertFalse(intRange.contains(25));
185 }
186
187 @Test
188 public void testIsAfter() {
189 assertFalse(intRange.isAfter(null));
190
191 assertTrue(intRange.isAfter(5));
192 assertFalse(intRange.isAfter(10));
193 assertFalse(intRange.isAfter(15));
194 assertFalse(intRange.isAfter(20));
195 assertFalse(intRange.isAfter(25));
196 }
197
198 @Test
199 public void testIsStartedBy() {
200 assertFalse(intRange.isStartedBy(null));
201
202 assertFalse(intRange.isStartedBy(5));
203 assertTrue(intRange.isStartedBy(10));
204 assertFalse(intRange.isStartedBy(15));
205 assertFalse(intRange.isStartedBy(20));
206 assertFalse(intRange.isStartedBy(25));
207 }
208
209 @Test
210 public void testIsEndedBy() {
211 assertFalse(intRange.isEndedBy(null));
212
213 assertFalse(intRange.isEndedBy(5));
214 assertFalse(intRange.isEndedBy(10));
215 assertFalse(intRange.isEndedBy(15));
216 assertTrue(intRange.isEndedBy(20));
217 assertFalse(intRange.isEndedBy(25));
218 }
219
220 @Test
221 public void testIsBefore() {
222 assertFalse(intRange.isBefore(null));
223
224 assertFalse(intRange.isBefore(5));
225 assertFalse(intRange.isBefore(10));
226 assertFalse(intRange.isBefore(15));
227 assertFalse(intRange.isBefore(20));
228 assertTrue(intRange.isBefore(25));
229 }
230
231 @Test
232 public void testElementCompareTo() {
233 try {
234 intRange.elementCompareTo(null);
235 fail("NullPointerException should have been thrown");
236 } catch(NullPointerException npe) {
237 // expected
238 }
239
240 assertEquals(-1, intRange.elementCompareTo(5));
241 assertEquals(0, intRange.elementCompareTo(10));
242 assertEquals(0, intRange.elementCompareTo(15));
243 assertEquals(0, intRange.elementCompareTo(20));
244 assertEquals(1, intRange.elementCompareTo(25));
245 }
246
247 //-----------------------------------------------------------------------
248 @Test
249 public void testContainsRange() {
250
251 // null handling
252 assertFalse(intRange.containsRange(null));
253
254 // easy inside range
255 assertTrue(intRange.containsRange(Range.between(12, 18)));
256
257 // outside range on each side
258 assertFalse(intRange.containsRange(Range.between(32, 45)));
259 assertFalse(intRange.containsRange(Range.between(2, 8)));
260
261 // equals range
262 assertTrue(intRange.containsRange(Range.between(10, 20)));
263
264 // overlaps
265 assertFalse(intRange.containsRange(Range.between(9, 14)));
266 assertFalse(intRange.containsRange(Range.between(16, 21)));
267
268 // touches lower boundary
269 assertTrue(intRange.containsRange(Range.between(10, 19)));
270 assertFalse(intRange.containsRange(Range.between(10, 21)));
271
272 // touches upper boundary
273 assertTrue(intRange.containsRange(Range.between(11, 20)));
274 assertFalse(intRange.containsRange(Range.between(9, 20)));
275
276 // negative
277 assertFalse(intRange.containsRange(Range.between(-11, -18)));
278 }
279
280 @Test
281 public void testIsAfterRange() {
282 assertFalse(intRange.isAfterRange(null));
283
284 assertTrue(intRange.isAfterRange(Range.between(5, 9)));
285
286 assertFalse(intRange.isAfterRange(Range.between(5, 10)));
287 assertFalse(intRange.isAfterRange(Range.between(5, 20)));
288 assertFalse(intRange.isAfterRange(Range.between(5, 25)));
289 assertFalse(intRange.isAfterRange(Range.between(15, 25)));
290
291 assertFalse(intRange.isAfterRange(Range.between(21, 25)));
292
293 assertFalse(intRange.isAfterRange(Range.between(10, 20)));
294 }
295
296 @Test
297 public void testIsOverlappedBy() {
298
299 // null handling
300 assertFalse(intRange.isOverlappedBy(null));
301
302 // easy inside range
303 assertTrue(intRange.isOverlappedBy(Range.between(12, 18)));
304
305 // outside range on each side
306 assertFalse(intRange.isOverlappedBy(Range.between(32, 45)));
307 assertFalse(intRange.isOverlappedBy(Range.between(2, 8)));
308
309 // equals range
310 assertTrue(intRange.isOverlappedBy(Range.between(10, 20)));
311
312 // overlaps
313 assertTrue(intRange.isOverlappedBy(Range.between(9, 14)));
314 assertTrue(intRange.isOverlappedBy(Range.between(16, 21)));
315
316 // touches lower boundary
317 assertTrue(intRange.isOverlappedBy(Range.between(10, 19)));
318 assertTrue(intRange.isOverlappedBy(Range.between(10, 21)));
319
320 // touches upper boundary
321 assertTrue(intRange.isOverlappedBy(Range.between(11, 20)));
322 assertTrue(intRange.isOverlappedBy(Range.between(9, 20)));
323
324 // negative
325 assertFalse(intRange.isOverlappedBy(Range.between(-11, -18)));
326 }
327
328 @Test
329 public void testIsBeforeRange() {
330 assertFalse(intRange.isBeforeRange(null));
331
332 assertFalse(intRange.isBeforeRange(Range.between(5, 9)));
333
334 assertFalse(intRange.isBeforeRange(Range.between(5, 10)));
335 assertFalse(intRange.isBeforeRange(Range.between(5, 20)));
336 assertFalse(intRange.isBeforeRange(Range.between(5, 25)));
337 assertFalse(intRange.isBeforeRange(Range.between(15, 25)));
338
339 assertTrue(intRange.isBeforeRange(Range.between(21, 25)));
340
341 assertFalse(intRange.isBeforeRange(Range.between(10, 20)));
342 }
343
344 @Test
345 public void testIntersectionWith() {
346 assertSame(intRange, intRange.intersectionWith(intRange));
347 assertSame(byteRange, byteRange.intersectionWith(byteRange));
348 assertSame(longRange, longRange.intersectionWith(longRange));
349 assertSame(floatRange, floatRange.intersectionWith(floatRange));
350 assertSame(doubleRange, doubleRange.intersectionWith(doubleRange));
351
352 assertEquals(Range.between(10, 15), intRange.intersectionWith(Range.between(5, 15)));
353 }
354
355 @Test(expected = IllegalArgumentException.class)
356 public void testIntersectionWithNull() {
357 intRange.intersectionWith(null);
358 }
359
360 @Test(expected = IllegalArgumentException.class)
361 public void testIntersectionWithNonOverlapping() {
362 intRange.intersectionWith(Range.between(0, 9));
363 }
364
365 //-----------------------------------------------------------------------
366 @Test
367 public void testSerializing() {
368 SerializationUtils.clone(intRange);
369 }
370
371 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.io.ByteArrayInputStream;
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.ObjectInputStream;
23 import java.io.ObjectOutputStream;
24 import java.io.OutputStream;
25 import java.io.Serializable;
26 import java.lang.reflect.Constructor;
27 import java.lang.reflect.Modifier;
28 import java.util.HashMap;
29
30 import junit.framework.TestCase;
31
32 /**
33 * Unit tests {@link org.apache.commons.lang3.SerializationUtils}.
34 *
35 * @version $Id: SerializationUtilsTest.java 1153484 2011-08-03 13:39:42Z ggregory $
36 */
37 public class SerializationUtilsTest extends TestCase {
38
39 static final String CLASS_NOT_FOUND_MESSAGE = "ClassNotFoundSerialization.readObject fake exception";
40 protected static final String SERIALIZE_IO_EXCEPTION_MESSAGE = "Anonymous OutputStream I/O exception";
41
42 private String iString;
43 private Integer iInteger;
44 private HashMap<Object, Object> iMap;
45
46 public SerializationUtilsTest(String name) {
47 super(name);
48 }
49
50 @Override
51 protected void setUp() throws Exception {
52 super.setUp();
53
54 iString = "foo";
55 iInteger = Integer.valueOf(7);
56 iMap = new HashMap<Object, Object>();
57 iMap.put("FOO", iString);
58 iMap.put("BAR", iInteger);
59 }
60
61 //-----------------------------------------------------------------------
62 public void testConstructor() {
63 assertNotNull(new SerializationUtils());
64 Constructor<?>[] cons = SerializationUtils.class.getDeclaredConstructors();
65 assertEquals(1, cons.length);
66 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
67 assertEquals(true, Modifier.isPublic(SerializationUtils.class.getModifiers()));
68 assertEquals(false, Modifier.isFinal(SerializationUtils.class.getModifiers()));
69 }
70
71 public void testException() {
72 SerializationException serEx;
73 Exception ex = new Exception();
74
75 serEx = new SerializationException();
76 assertSame(null, serEx.getMessage());
77 assertSame(null, serEx.getCause());
78
79 serEx = new SerializationException("Message");
80 assertSame("Message", serEx.getMessage());
81 assertSame(null, serEx.getCause());
82
83 serEx = new SerializationException(ex);
84 assertEquals("java.lang.Exception", serEx.getMessage());
85 assertSame(ex, serEx.getCause());
86
87 serEx = new SerializationException("Message", ex);
88 assertSame("Message", serEx.getMessage());
89 assertSame(ex, serEx.getCause());
90 }
91
92 //-----------------------------------------------------------------------
93 public void testSerializeStream() throws Exception {
94 ByteArrayOutputStream streamTest = new ByteArrayOutputStream();
95 SerializationUtils.serialize(iMap, streamTest);
96
97 ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
98 ObjectOutputStream oos = new ObjectOutputStream(streamReal);
99 oos.writeObject(iMap);
100 oos.flush();
101 oos.close();
102
103 byte[] testBytes = streamTest.toByteArray();
104 byte[] realBytes = streamReal.toByteArray();
105 assertEquals(testBytes.length, realBytes.length);
106 for (int i = 0; i < realBytes.length; i++) {
107 assertEquals(realBytes[i], testBytes[i]);
108 }
109 }
110
111 public void testSerializeStreamUnserializable() throws Exception {
112 ByteArrayOutputStream streamTest = new ByteArrayOutputStream();
113 try {
114 iMap.put(new Object(), new Object());
115 SerializationUtils.serialize(iMap, streamTest);
116 } catch (SerializationException ex) {
117 return;
118 }
119 fail();
120 }
121
122 public void testSerializeStreamNullObj() throws Exception {
123 ByteArrayOutputStream streamTest = new ByteArrayOutputStream();
124 SerializationUtils.serialize(null, streamTest);
125
126 ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
127 ObjectOutputStream oos = new ObjectOutputStream(streamReal);
128 oos.writeObject(null);
129 oos.flush();
130 oos.close();
131
132 byte[] testBytes = streamTest.toByteArray();
133 byte[] realBytes = streamReal.toByteArray();
134 assertEquals(testBytes.length, realBytes.length);
135 for (int i = 0; i < realBytes.length; i++) {
136 assertEquals(realBytes[i], testBytes[i]);
137 }
138 }
139
140 public void testSerializeStreamObjNull() throws Exception {
141 try {
142 SerializationUtils.serialize(iMap, null);
143 } catch (IllegalArgumentException ex) {
144 return;
145 }
146 fail();
147 }
148
149 public void testSerializeStreamNullNull() throws Exception {
150 try {
151 SerializationUtils.serialize(null, null);
152 } catch (IllegalArgumentException ex) {
153 return;
154 }
155 fail();
156 }
157
158 public void testSerializeIOException() throws Exception {
159 // forces an IOException when the ObjectOutputStream is created, to test not closing the stream
160 // in the finally block
161 OutputStream streamTest = new OutputStream() {
162 @Override
163 public void write(int arg0) throws IOException {
164 throw new IOException(SERIALIZE_IO_EXCEPTION_MESSAGE);
165 }
166 };
167 try {
168 SerializationUtils.serialize(iMap, streamTest);
169 }
170 catch(SerializationException e) {
171 assertEquals("java.io.IOException: " + SERIALIZE_IO_EXCEPTION_MESSAGE, e.getMessage());
172 }
173 }
174
175 //-----------------------------------------------------------------------
176
177 public void testDeserializeStream() throws Exception {
178 ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
179 ObjectOutputStream oos = new ObjectOutputStream(streamReal);
180 oos.writeObject(iMap);
181 oos.flush();
182 oos.close();
183
184 ByteArrayInputStream inTest = new ByteArrayInputStream(streamReal.toByteArray());
185 Object test = SerializationUtils.deserialize(inTest);
186 assertNotNull(test);
187 assertTrue(test instanceof HashMap<?, ?>);
188 assertTrue(test != iMap);
189 HashMap<?, ?> testMap = (HashMap<?, ?>) test;
190 assertEquals(iString, testMap.get("FOO"));
191 assertTrue(iString != testMap.get("FOO"));
192 assertEquals(iInteger, testMap.get("BAR"));
193 assertTrue(iInteger != testMap.get("BAR"));
194 assertEquals(iMap, testMap);
195 }
196
197 public void testDeserializeStreamOfNull() throws Exception {
198 ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
199 ObjectOutputStream oos = new ObjectOutputStream(streamReal);
200 oos.writeObject(null);
201 oos.flush();
202 oos.close();
203
204 ByteArrayInputStream inTest = new ByteArrayInputStream(streamReal.toByteArray());
205 Object test = SerializationUtils.deserialize(inTest);
206 assertNull(test);
207 }
208
209 public void testDeserializeStreamNull() throws Exception {
210 try {
211 SerializationUtils.deserialize((InputStream) null);
212 } catch (IllegalArgumentException ex) {
213 return;
214 }
215 fail();
216 }
217
218 public void testDeserializeStreamBadStream() throws Exception {
219 try {
220 SerializationUtils.deserialize(new ByteArrayInputStream(new byte[0]));
221 } catch (SerializationException ex) {
222 return;
223 }
224 fail();
225 }
226
227 public void testDeserializeStreamClassNotFound() throws Exception {
228 ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
229 ObjectOutputStream oos = new ObjectOutputStream(streamReal);
230 oos.writeObject(new ClassNotFoundSerialization());
231 oos.flush();
232 oos.close();
233
234 ByteArrayInputStream inTest = new ByteArrayInputStream(streamReal.toByteArray());
235 try {
236 @SuppressWarnings("unused")
237 Object test = SerializationUtils.deserialize(inTest);
238 } catch(SerializationException se) {
239 assertEquals("java.lang.ClassNotFoundException: " + CLASS_NOT_FOUND_MESSAGE, se.getMessage());
240 }
241 }
242
243 //-----------------------------------------------------------------------
244
245 public void testSerializeBytes() throws Exception {
246 byte[] testBytes = SerializationUtils.serialize(iMap);
247
248 ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
249 ObjectOutputStream oos = new ObjectOutputStream(streamReal);
250 oos.writeObject(iMap);
251 oos.flush();
252 oos.close();
253
254 byte[] realBytes = streamReal.toByteArray();
255 assertEquals(testBytes.length, realBytes.length);
256 for (int i = 0; i < realBytes.length; i++) {
257 assertEquals(realBytes[i], testBytes[i]);
258 }
259 }
260
261 public void testSerializeBytesUnserializable() throws Exception {
262 try {
263 iMap.put(new Object(), new Object());
264 SerializationUtils.serialize(iMap);
265 } catch (SerializationException ex) {
266 return;
267 }
268 fail();
269 }
270
271 public void testSerializeBytesNull() throws Exception {
272 byte[] testBytes = SerializationUtils.serialize(null);
273
274 ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
275 ObjectOutputStream oos = new ObjectOutputStream(streamReal);
276 oos.writeObject(null);
277 oos.flush();
278 oos.close();
279
280 byte[] realBytes = streamReal.toByteArray();
281 assertEquals(testBytes.length, realBytes.length);
282 for (int i = 0; i < realBytes.length; i++) {
283 assertEquals(realBytes[i], testBytes[i]);
284 }
285 }
286
287 //-----------------------------------------------------------------------
288
289 public void testDeserializeBytes() throws Exception {
290 ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
291 ObjectOutputStream oos = new ObjectOutputStream(streamReal);
292 oos.writeObject(iMap);
293 oos.flush();
294 oos.close();
295
296 Object test = SerializationUtils.deserialize(streamReal.toByteArray());
297 assertNotNull(test);
298 assertTrue(test instanceof HashMap<?, ?>);
299 assertTrue(test != iMap);
300 HashMap<?, ?> testMap = (HashMap<?, ?>) test;
301 assertEquals(iString, testMap.get("FOO"));
302 assertTrue(iString != testMap.get("FOO"));
303 assertEquals(iInteger, testMap.get("BAR"));
304 assertTrue(iInteger != testMap.get("BAR"));
305 assertEquals(iMap, testMap);
306 }
307
308 public void testDeserializeBytesOfNull() throws Exception {
309 ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
310 ObjectOutputStream oos = new ObjectOutputStream(streamReal);
311 oos.writeObject(null);
312 oos.flush();
313 oos.close();
314
315 Object test = SerializationUtils.deserialize(streamReal.toByteArray());
316 assertNull(test);
317 }
318
319 public void testDeserializeBytesNull() throws Exception {
320 try {
321 SerializationUtils.deserialize((byte[]) null);
322 } catch (IllegalArgumentException ex) {
323 return;
324 }
325 fail();
326 }
327
328 public void testDeserializeBytesBadStream() throws Exception {
329 try {
330 SerializationUtils.deserialize(new byte[0]);
331 } catch (SerializationException ex) {
332 return;
333 }
334 fail();
335 }
336
337 //-----------------------------------------------------------------------
338
339 public void testClone() throws Exception {
340 Object test = SerializationUtils.clone(iMap);
341 assertNotNull(test);
342 assertTrue(test instanceof HashMap<?,?>);
343 assertTrue(test != iMap);
344 HashMap<?, ?> testMap = (HashMap<?, ?>) test;
345 assertEquals(iString, testMap.get("FOO"));
346 assertTrue(iString != testMap.get("FOO"));
347 assertEquals(iInteger, testMap.get("BAR"));
348 assertTrue(iInteger != testMap.get("BAR"));
349 assertEquals(iMap, testMap);
350 }
351
352 public void testCloneNull() throws Exception {
353 Object test = SerializationUtils.clone(null);
354 assertNull(test);
355 }
356
357 public void testCloneUnserializable() throws Exception {
358 try {
359 iMap.put(new Object(), new Object());
360 SerializationUtils.clone(iMap);
361 } catch (SerializationException ex) {
362 return;
363 }
364 fail();
365 }
366
367 }
368
369 @SuppressWarnings("serial")
370 class ClassNotFoundSerialization implements Serializable
371 {
372
373 private void readObject(ObjectInputStream in) throws ClassNotFoundException {
374 throw new ClassNotFoundException(SerializationUtilsTest.CLASS_NOT_FOUND_MESSAGE);
375 }
376 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertTrue;
21 import static org.junit.Assert.fail;
22
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.io.StringWriter;
26 import java.lang.reflect.Constructor;
27 import java.lang.reflect.Modifier;
28
29 import org.apache.commons.io.IOUtils;
30 import org.junit.Test;
31
32 import org.apache.commons.lang3.text.translate.CharSequenceTranslator;
33 import org.apache.commons.lang3.text.translate.NumericEntityEscaper;
34 import org.apache.commons.lang3.text.translate.NumericEntityUnescaper;
35
36 /**
37 * Unit tests for {@link StringEscapeUtils}.
38 *
39 * @version $Id: StringEscapeUtilsTest.java 1148531 2011-07-19 21:03:42Z ggregory $
40 */
41 public class StringEscapeUtilsTest {
42 private final static String FOO = "foo";
43
44 @Test
45 public void testConstructor() {
46 assertNotNull(new StringEscapeUtils());
47 Constructor<?>[] cons = StringEscapeUtils.class.getDeclaredConstructors();
48 assertEquals(1, cons.length);
49 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
50 assertEquals(true, Modifier.isPublic(StringEscapeUtils.class.getModifiers()));
51 assertEquals(false, Modifier.isFinal(StringEscapeUtils.class.getModifiers()));
52 }
53
54 @Test
55 public void testEscapeJava() throws IOException {
56 assertEquals(null, StringEscapeUtils.escapeJava(null));
57 try {
58 StringEscapeUtils.ESCAPE_JAVA.translate(null, null);
59 fail();
60 } catch (IOException ex) {
61 fail();
62 } catch (IllegalArgumentException ex) {
63 }
64 try {
65 StringEscapeUtils.ESCAPE_JAVA.translate("", null);
66 fail();
67 } catch (IOException ex) {
68 fail();
69 } catch (IllegalArgumentException ex) {
70 }
71
72 assertEscapeJava("empty string", "", "");
73 assertEscapeJava(FOO, FOO);
74 assertEscapeJava("tab", "\\t", "\t");
75 assertEscapeJava("backslash", "\\\\", "\\");
76 assertEscapeJava("single quote should not be escaped", "'", "'");
77 assertEscapeJava("\\\\\\b\\t\\r", "\\\b\t\r");
78 assertEscapeJava("\\u1234", "\u1234");
79 assertEscapeJava("\\u0234", "\u0234");
80 assertEscapeJava("\\u00EF", "\u00ef");
81 assertEscapeJava("\\u0001", "\u0001");
82 assertEscapeJava("Should use capitalized Unicode hex", "\\uABCD", "\uabcd");
83
84 assertEscapeJava("He didn't say, \\\"stop!\\\"",
85 "He didn't say, \"stop!\"");
86 assertEscapeJava("non-breaking space", "This space is non-breaking:" + "\\u00A0",
87 "This space is non-breaking:\u00a0");
88 assertEscapeJava("\\uABCD\\u1234\\u012C",
89 "\uABCD\u1234\u012C");
90 }
91
92 /**
93 * Tests https://issues.apache.org/jira/browse/LANG-421
94 */
95 @Test
96 public void testEscapeJavaWithSlash() {
97 final String input = "String with a slash (/) in it";
98
99 final String expected = input;
100 final String actual = StringEscapeUtils.escapeJava(input);
101
102 /**
103 * In 2.4 StringEscapeUtils.escapeJava(String) escapes '/' characters, which are not a valid character to escape
104 * in a Java string.
105 */
106 assertEquals(expected, actual);
107 }
108
109 private void assertEscapeJava(String escaped, String original) throws IOException {
110 assertEscapeJava(null, escaped, original);
111 }
112
113 private void assertEscapeJava(String message, String expected, String original) throws IOException {
114 String converted = StringEscapeUtils.escapeJava(original);
115 message = "escapeJava(String) failed" + (message == null ? "" : (": " + message));
116 assertEquals(message, expected, converted);
117
118 StringWriter writer = new StringWriter();
119 StringEscapeUtils.ESCAPE_JAVA.translate(original, writer);
120 assertEquals(expected, writer.toString());
121 }
122
123 @Test
124 public void testUnescapeJava() throws IOException {
125 assertEquals(null, StringEscapeUtils.unescapeJava(null));
126 try {
127 StringEscapeUtils.UNESCAPE_JAVA.translate(null, null);
128 fail();
129 } catch (IOException ex) {
130 fail();
131 } catch (IllegalArgumentException ex) {
132 }
133 try {
134 StringEscapeUtils.UNESCAPE_JAVA.translate("", null);
135 fail();
136 } catch (IOException ex) {
137 fail();
138 } catch (IllegalArgumentException ex) {
139 }
140 try {
141 StringEscapeUtils.unescapeJava("\\u02-3");
142 fail();
143 } catch (RuntimeException ex) {
144 }
145
146 assertUnescapeJava("", "");
147 assertUnescapeJava("test", "test");
148 assertUnescapeJava("\ntest\b", "\\ntest\\b");
149 assertUnescapeJava("\u123425foo\ntest\b", "\\u123425foo\\ntest\\b");
150 assertUnescapeJava("'\foo\teste\r", "\\'\\foo\\teste\\r");
151 assertUnescapeJava("", "\\");
152 //foo
153 assertUnescapeJava("lowercase Unicode", "\uABCDx", "\\uabcdx");
154 assertUnescapeJava("uppercase Unicode", "\uABCDx", "\\uABCDx");
155 assertUnescapeJava("Unicode as final character", "\uABCD", "\\uabcd");
156 }
157
158 private void assertUnescapeJava(String unescaped, String original) throws IOException {
159 assertUnescapeJava(null, unescaped, original);
160 }
161
162 private void assertUnescapeJava(String message, String unescaped, String original) throws IOException {
163 String expected = unescaped;
164 String actual = StringEscapeUtils.unescapeJava(original);
165
166 assertEquals("unescape(String) failed" +
167 (message == null ? "" : (": " + message)) +
168 ": expected '" + StringEscapeUtils.escapeJava(expected) +
169 // we escape this so we can see it in the error message
170 "' actual '" + StringEscapeUtils.escapeJava(actual) + "'",
171 expected, actual);
172
173 StringWriter writer = new StringWriter();
174 StringEscapeUtils.UNESCAPE_JAVA.translate(original, writer);
175 assertEquals(unescaped, writer.toString());
176
177 }
178
179 @Test
180 public void testEscapeEcmaScript() {
181 assertEquals(null, StringEscapeUtils.escapeEcmaScript(null));
182 try {
183 StringEscapeUtils.ESCAPE_ECMASCRIPT.translate(null, null);
184 fail();
185 } catch (IOException ex) {
186 fail();
187 } catch (IllegalArgumentException ex) {
188 }
189 try {
190 StringEscapeUtils.ESCAPE_ECMASCRIPT.translate("", null);
191 fail();
192 } catch (IOException ex) {
193 fail();
194 } catch (IllegalArgumentException ex) {
195 }
196
197 assertEquals("He didn\\'t say, \\\"stop!\\\"", StringEscapeUtils.escapeEcmaScript("He didn't say, \"stop!\""));
198 assertEquals("document.getElementById(\\\"test\\\").value = \\'<script>alert(\\'aaa\\');<\\/script>\\';",
199 StringEscapeUtils.escapeEcmaScript("document.getElementById(\"test\").value = '<script>alert('aaa');</script>';"));
200 }
201
202
203 // HTML and XML
204 //--------------------------------------------------------------
205
206 private static final String[][] HTML_ESCAPES = {
207 {"no escaping", "plain text", "plain text"},
208 {"no escaping", "plain text", "plain text"},
209 {"empty string", "", ""},
210 {"null", null, null},
211 {"ampersand", "bread &amp; butter", "bread & butter"},
212 {"quotes", "&quot;bread&quot; &amp; butter", "\"bread\" & butter"},
213 {"final character only", "greater than &gt;", "greater than >"},
214 {"first character only", "&lt; less than", "< less than"},
215 {"apostrophe", "Huntington's chorea", "Huntington's chorea"},
216 {"languages", "English,Fran&ccedil;ais,\u65E5\u672C\u8A9E (nihongo)", "English,Fran\u00E7ais,\u65E5\u672C\u8A9E (nihongo)"},
217 {"8-bit ascii shouldn't number-escape", "\u0080\u009F", "\u0080\u009F"},
218 };
219
220 @Test
221 public void testEscapeHtml() {
222 for (int i = 0; i < HTML_ESCAPES.length; ++i) {
223 String message = HTML_ESCAPES[i][0];
224 String expected = HTML_ESCAPES[i][1];
225 String original = HTML_ESCAPES[i][2];
226 assertEquals(message, expected, StringEscapeUtils.escapeHtml4(original));
227 StringWriter sw = new StringWriter();
228 try {
229 StringEscapeUtils.ESCAPE_HTML4.translate(original, sw);
230 } catch (IOException e) {
231 }
232 String actual = original == null ? null : sw.toString();
233 assertEquals(message, expected, actual);
234 }
235 }
236
237 @Test
238 public void testUnescapeHtml4() {
239 for (int i = 0; i < HTML_ESCAPES.length; ++i) {
240 String message = HTML_ESCAPES[i][0];
241 String expected = HTML_ESCAPES[i][2];
242 String original = HTML_ESCAPES[i][1];
243 assertEquals(message, expected, StringEscapeUtils.unescapeHtml4(original));
244
245 StringWriter sw = new StringWriter();
246 try {
247 StringEscapeUtils.UNESCAPE_HTML4.translate(original, sw);
248 } catch (IOException e) {
249 }
250 String actual = original == null ? null : sw.toString();
251 assertEquals(message, expected, actual);
252 }
253 // \u00E7 is a cedilla (c with wiggle under)
254 // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly
255 // on some locales
256 assertEquals("funny chars pass through OK", "Fran\u00E7ais", StringEscapeUtils.unescapeHtml4("Fran\u00E7ais"));
257
258 assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml4("Hello&;World"));
259 assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml4("Hello&#;World"));
260 assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml4("Hello&# ;World"));
261 assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml4("Hello&##;World"));
262 }
263
264 @Test
265 public void testUnescapeHexCharsHtml() {
266 // Simple easy to grok test
267 assertEquals("hex number unescape", "\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#x80;&#x9F;"));
268 assertEquals("hex number unescape", "\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#X80;&#X9F;"));
269 // Test all Character values:
270 for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
271 Character c1 = new Character(i);
272 Character c2 = new Character((char)(i+1));
273 String expected = c1.toString() + c2.toString();
274 String escapedC1 = "&#x" + Integer.toHexString((c1.charValue())) + ";";
275 String escapedC2 = "&#x" + Integer.toHexString((c2.charValue())) + ";";
276 assertEquals("hex number unescape index " + (int)i, expected, StringEscapeUtils.unescapeHtml4(escapedC1 + escapedC2));
277 }
278 }
279
280 @Test
281 public void testUnescapeUnknownEntity() throws Exception {
282 assertEquals("&zzzz;", StringEscapeUtils.unescapeHtml4("&zzzz;"));
283 }
284
285 @Test
286 public void testEscapeHtmlVersions() throws Exception {
287 assertEquals("&Beta;", StringEscapeUtils.escapeHtml4("\u0392"));
288 assertEquals("\u0392", StringEscapeUtils.unescapeHtml4("&Beta;"));
289
290 // TODO: refine API for escaping/unescaping specific HTML versions
291 }
292
293 @Test
294 public void testEscapeXml() throws Exception {
295 assertEquals("&lt;abc&gt;", StringEscapeUtils.escapeXml("<abc>"));
296 assertEquals("<abc>", StringEscapeUtils.unescapeXml("&lt;abc&gt;"));
297
298 assertEquals("XML should not escape >0x7f values",
299 "\u00A1", StringEscapeUtils.escapeXml("\u00A1"));
300 assertEquals("XML should be able to unescape >0x7f values",
301 "\u00A0", StringEscapeUtils.unescapeXml("&#160;"));
302 assertEquals("XML should be able to unescape >0x7f values with one leading 0",
303 "\u00A0", StringEscapeUtils.unescapeXml("&#0160;"));
304 assertEquals("XML should be able to unescape >0x7f values with two leading 0s",
305 "\u00A0", StringEscapeUtils.unescapeXml("&#00160;"));
306 assertEquals("XML should be able to unescape >0x7f values with three leading 0s",
307 "\u00A0", StringEscapeUtils.unescapeXml("&#000160;"));
308
309 assertEquals("ain't", StringEscapeUtils.unescapeXml("ain&apos;t"));
310 assertEquals("ain&apos;t", StringEscapeUtils.escapeXml("ain't"));
311 assertEquals("", StringEscapeUtils.escapeXml(""));
312 assertEquals(null, StringEscapeUtils.escapeXml(null));
313 assertEquals(null, StringEscapeUtils.unescapeXml(null));
314
315 StringWriter sw = new StringWriter();
316 try {
317 StringEscapeUtils.ESCAPE_XML.translate("<abc>", sw);
318 } catch (IOException e) {
319 }
320 assertEquals("XML was escaped incorrectly", "&lt;abc&gt;", sw.toString() );
321
322 sw = new StringWriter();
323 try {
324 StringEscapeUtils.UNESCAPE_XML.translate("&lt;abc&gt;", sw);
325 } catch (IOException e) {
326 }
327 assertEquals("XML was unescaped incorrectly", "<abc>", sw.toString() );
328 }
329
330 /**
331 * Tests Supplementary characters.
332 * <p>
333 * From http://www.w3.org/International/questions/qa-escapes
334 * </p>
335 * <blockquote>
336 * Supplementary characters are those Unicode characters that have code points higher than the characters in
337 * the Basic Multilingual Plane (BMP). In UTF-16 a supplementary character is encoded using two 16-bit surrogate code points from the
338 * BMP. Because of this, some people think that supplementary characters need to be represented using two escapes, but this is incorrect
339 * – you must use the single, code point value for that character. For example, use &#x233B4; rather than &#xD84C;&#xDFB4;.
340 * </blockquote>
341 * @see <a href="http://www.w3.org/International/questions/qa-escapes">Using character escapes in markup and CSS</a>
342 * @see <a href="https://issues.apache.org/jira/browse/LANG-728">LANG-728</a>
343 */
344 @Test
345 public void testEscapeXmlSupplementaryCharacters() {
346 CharSequenceTranslator escapeXml =
347 StringEscapeUtils.ESCAPE_XML.with( NumericEntityEscaper.between(0x7f, Integer.MAX_VALUE) );
348
349 assertEquals("Supplementary character must be represented using a single escape", "&#144308;",
350 escapeXml.translate("\uD84C\uDFB4"));
351 }
352
353 /**
354 * Reverse of the above.
355 *
356 * @see <a href="https://issues.apache.org/jira/browse/LANG-729">LANG-729</a>
357 */
358 @Test
359 public void testUnescapeXmlSupplementaryCharacters() {
360 assertEquals("Supplementary character must be represented using a single escape", "\uD84C\uDFB4",
361 StringEscapeUtils.unescapeXml("&#144308;") );
362 }
363
364 // Tests issue #38569
365 // http://issues.apache.org/bugzilla/show_bug.cgi?id=38569
366 @Test
367 public void testStandaloneAmphersand() {
368 assertEquals("<P&O>", StringEscapeUtils.unescapeHtml4("&lt;P&O&gt;"));
369 assertEquals("test & <", StringEscapeUtils.unescapeHtml4("test & &lt;"));
370 assertEquals("<P&O>", StringEscapeUtils.unescapeXml("&lt;P&O&gt;"));
371 assertEquals("test & <", StringEscapeUtils.unescapeXml("test & &lt;"));
372 }
373
374 @Test
375 public void testLang313() {
376 assertEquals("& &", StringEscapeUtils.unescapeHtml4("& &amp;"));
377 }
378
379 @Test
380 public void testEscapeCsvString() throws Exception {
381 assertEquals("foo.bar", StringEscapeUtils.escapeCsv("foo.bar"));
382 assertEquals("\"foo,bar\"", StringEscapeUtils.escapeCsv("foo,bar"));
383 assertEquals("\"foo\nbar\"", StringEscapeUtils.escapeCsv("foo\nbar"));
384 assertEquals("\"foo\rbar\"", StringEscapeUtils.escapeCsv("foo\rbar"));
385 assertEquals("\"foo\"\"bar\"", StringEscapeUtils.escapeCsv("foo\"bar"));
386 assertEquals("", StringEscapeUtils.escapeCsv(""));
387 assertEquals(null, StringEscapeUtils.escapeCsv(null));
388 }
389
390 @Test
391 public void testEscapeCsvWriter() throws Exception {
392 checkCsvEscapeWriter("foo.bar", "foo.bar");
393 checkCsvEscapeWriter("\"foo,bar\"", "foo,bar");
394 checkCsvEscapeWriter("\"foo\nbar\"", "foo\nbar");
395 checkCsvEscapeWriter("\"foo\rbar\"", "foo\rbar");
396 checkCsvEscapeWriter("\"foo\"\"bar\"", "foo\"bar");
397 checkCsvEscapeWriter("", null);
398 checkCsvEscapeWriter("", "");
399 }
400
401 private void checkCsvEscapeWriter(String expected, String value) {
402 try {
403 StringWriter writer = new StringWriter();
404 StringEscapeUtils.ESCAPE_CSV.translate(value, writer);
405 assertEquals(expected, writer.toString());
406 } catch (IOException e) {
407 fail("Threw: " + e);
408 }
409 }
410
411 @Test
412 public void testUnescapeCsvString() throws Exception {
413 assertEquals("foo.bar", StringEscapeUtils.unescapeCsv("foo.bar"));
414 assertEquals("foo,bar", StringEscapeUtils.unescapeCsv("\"foo,bar\""));
415 assertEquals("foo\nbar", StringEscapeUtils.unescapeCsv("\"foo\nbar\""));
416 assertEquals("foo\rbar", StringEscapeUtils.unescapeCsv("\"foo\rbar\""));
417 assertEquals("foo\"bar", StringEscapeUtils.unescapeCsv("\"foo\"\"bar\""));
418 assertEquals("", StringEscapeUtils.unescapeCsv(""));
419 assertEquals(null, StringEscapeUtils.unescapeCsv(null));
420
421 assertEquals("\"foo.bar\"", StringEscapeUtils.unescapeCsv("\"foo.bar\""));
422 }
423
424 @Test
425 public void testUnescapeCsvWriter() throws Exception {
426 checkCsvUnescapeWriter("foo.bar", "foo.bar");
427 checkCsvUnescapeWriter("foo,bar", "\"foo,bar\"");
428 checkCsvUnescapeWriter("foo\nbar", "\"foo\nbar\"");
429 checkCsvUnescapeWriter("foo\rbar", "\"foo\rbar\"");
430 checkCsvUnescapeWriter("foo\"bar", "\"foo\"\"bar\"");
431 checkCsvUnescapeWriter("", null);
432 checkCsvUnescapeWriter("", "");
433
434 checkCsvUnescapeWriter("\"foo.bar\"", "\"foo.bar\"");
435 }
436
437 private void checkCsvUnescapeWriter(String expected, String value) {
438 try {
439 StringWriter writer = new StringWriter();
440 StringEscapeUtils.UNESCAPE_CSV.translate(value, writer);
441 assertEquals(expected, writer.toString());
442 } catch (IOException e) {
443 fail("Threw: " + e);
444 }
445 }
446
447 /**
448 * Tests // https://issues.apache.org/jira/browse/LANG-480
449 *
450 * @throws java.io.UnsupportedEncodingException
451 */
452 @Test
453 public void testEscapeHtmlHighUnicode() throws java.io.UnsupportedEncodingException {
454 // this is the utf8 representation of the character:
455 // COUNTING ROD UNIT DIGIT THREE
456 // in Unicode
457 // codepoint: U+1D362
458 byte[] data = new byte[] { (byte)0xF0, (byte)0x9D, (byte)0x8D, (byte)0xA2 };
459
460 String original = new String(data, "UTF8");
461
462 String escaped = StringEscapeUtils.escapeHtml4( original );
463 assertEquals( "High Unicode should not have been escaped", original, escaped);
464
465 String unescaped = StringEscapeUtils.unescapeHtml4( escaped );
466 assertEquals( "High Unicode should have been unchanged", original, unescaped);
467
468 // TODO: I think this should hold, needs further investigation
469 // String unescapedFromEntity = StringEscapeUtils.unescapeHtml4( "&#119650;" );
470 // assertEquals( "High Unicode should have been unescaped", original, unescapedFromEntity);
471 }
472
473 /**
474 * Tests https://issues.apache.org/jira/browse/LANG-339
475 */
476 @Test
477 public void testEscapeHiragana() {
478 // Some random Japanese Unicode characters
479 String original = "\u304B\u304C\u3068";
480 String escaped = StringEscapeUtils.escapeHtml4(original);
481 assertEquals( "Hiragana character Unicode behaviour should not be being escaped by escapeHtml4",
482 original, escaped);
483
484 String unescaped = StringEscapeUtils.unescapeHtml4( escaped );
485
486 assertEquals( "Hiragana character Unicode behaviour has changed - expected no unescaping", escaped, unescaped);
487 }
488
489 /**
490 * Tests https://issues.apache.org/jira/browse/LANG-708
491 *
492 * @throws IOException
493 * if an I/O error occurs
494 */
495 @Test
496 public void testLang708() throws IOException {
497 String input = IOUtils.toString(new FileInputStream("src/test/resources/lang-708-input.txt"), "UTF-8");
498 String escaped = StringEscapeUtils.escapeEcmaScript(input);
499 // just the end:
500 assertTrue(escaped, escaped.endsWith("}]"));
501 // a little more:
502 assertTrue(escaped, escaped.endsWith("\"valueCode\\\":\\\"\\\"}]"));
503 }
504
505 /**
506 * Tests https://issues.apache.org/jira/browse/LANG-720
507 */
508 @Test
509 public void testLang720() {
510 String input = new StringBuilder("\ud842\udfb7").append("A").toString();
511 String escaped = StringEscapeUtils.escapeXml(input);
512 assertEquals(input, escaped);
513 }
514 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.util.Locale;
19
20 import junit.framework.TestCase;
21
22 /**
23 * Unit tests {@link org.apache.commons.lang3.StringUtils} - Substring methods
24 *
25 * @version $Id: StringUtilsEqualsIndexOfTest.java 1144929 2011-07-10 18:26:16Z ggregory $
26 */
27 public class StringUtilsEqualsIndexOfTest extends TestCase {
28 private static final String BAR = "bar";
29 /**
30 * Supplementary character U+20000
31 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
32 */
33 private static final String CharU20000 = "\uD840\uDC00";
34 /**
35 * Supplementary character U+20001
36 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
37 */
38 private static final String CharU20001 = "\uD840\uDC01";
39 /**
40 * Incomplete supplementary character U+20000, high surrogate only.
41 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
42 */
43 private static final String CharUSuppCharHigh = "\uDC00";
44
45 /**
46 * Incomplete supplementary character U+20000, low surrogate only.
47 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
48 */
49 private static final String CharUSuppCharLow = "\uD840";
50
51 private static final String FOO = "foo";
52
53 private static final String FOOBAR = "foobar";
54
55 private static final String[] FOOBAR_SUB_ARRAY = new String[] {"ob", "ba"};
56
57 public StringUtilsEqualsIndexOfTest(String name) {
58 super(name);
59 }
60
61 public void testContains_Char() {
62 assertEquals(false, StringUtils.contains(null, ' '));
63 assertEquals(false, StringUtils.contains("", ' '));
64 assertEquals(false, StringUtils.contains("", null));
65 assertEquals(false, StringUtils.contains(null, null));
66 assertEquals(true, StringUtils.contains("abc", 'a'));
67 assertEquals(true, StringUtils.contains("abc", 'b'));
68 assertEquals(true, StringUtils.contains("abc", 'c'));
69 assertEquals(false, StringUtils.contains("abc", 'z'));
70 }
71
72 public void testContains_String() {
73 assertEquals(false, StringUtils.contains(null, null));
74 assertEquals(false, StringUtils.contains(null, ""));
75 assertEquals(false, StringUtils.contains(null, "a"));
76 assertEquals(false, StringUtils.contains("", null));
77 assertEquals(true, StringUtils.contains("", ""));
78 assertEquals(false, StringUtils.contains("", "a"));
79 assertEquals(true, StringUtils.contains("abc", "a"));
80 assertEquals(true, StringUtils.contains("abc", "b"));
81 assertEquals(true, StringUtils.contains("abc", "c"));
82 assertEquals(true, StringUtils.contains("abc", "abc"));
83 assertEquals(false, StringUtils.contains("abc", "z"));
84 }
85
86 /**
87 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
88 */
89 public void testContains_StringWithBadSupplementaryChars() {
90 // Test edge case: 1/2 of a (broken) supplementary char
91 assertEquals(false, StringUtils.contains(CharUSuppCharHigh, CharU20001));
92 assertEquals(false, StringUtils.contains(CharUSuppCharLow, CharU20001));
93 assertEquals(false, StringUtils.contains(CharU20001, CharUSuppCharHigh));
94 assertEquals(0, CharU20001.indexOf(CharUSuppCharLow));
95 assertEquals(true, StringUtils.contains(CharU20001, CharUSuppCharLow));
96 assertEquals(true, StringUtils.contains(CharU20001 + CharUSuppCharLow + "a", "a"));
97 assertEquals(true, StringUtils.contains(CharU20001 + CharUSuppCharHigh + "a", "a"));
98 }
99
100 /**
101 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
102 */
103 public void testContains_StringWithSupplementaryChars() {
104 assertEquals(true, StringUtils.contains(CharU20000 + CharU20001, CharU20000));
105 assertEquals(true, StringUtils.contains(CharU20000 + CharU20001, CharU20001));
106 assertEquals(true, StringUtils.contains(CharU20000, CharU20000));
107 assertEquals(false, StringUtils.contains(CharU20000, CharU20001));
108 }
109
110 public void testContainsAny_StringCharArray() {
111 assertFalse(StringUtils.containsAny(null, (char[]) null));
112 assertFalse(StringUtils.containsAny(null, new char[0]));
113 assertFalse(StringUtils.containsAny(null, new char[] { 'a', 'b' }));
114
115 assertFalse(StringUtils.containsAny("", (char[]) null));
116 assertFalse(StringUtils.containsAny("", new char[0]));
117 assertFalse(StringUtils.containsAny("", new char[] { 'a', 'b' }));
118
119 assertFalse(StringUtils.containsAny("zzabyycdxx", (char[]) null));
120 assertFalse(StringUtils.containsAny("zzabyycdxx", new char[0]));
121 assertTrue(StringUtils.containsAny("zzabyycdxx", new char[] { 'z', 'a' }));
122 assertTrue(StringUtils.containsAny("zzabyycdxx", new char[] { 'b', 'y' }));
123 assertFalse(StringUtils.containsAny("ab", new char[] { 'z' }));
124 }
125
126 /**
127 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
128 */
129 public void testContainsAny_StringCharArrayWithBadSupplementaryChars() {
130 // Test edge case: 1/2 of a (broken) supplementary char
131 assertEquals(false, StringUtils.containsAny(CharUSuppCharHigh, CharU20001.toCharArray()));
132 assertEquals(false, StringUtils.containsAny("abc" + CharUSuppCharHigh + "xyz", CharU20001.toCharArray()));
133 assertEquals(-1, CharUSuppCharLow.indexOf(CharU20001));
134 assertEquals(false, StringUtils.containsAny(CharUSuppCharLow, CharU20001.toCharArray()));
135 assertEquals(false, StringUtils.containsAny(CharU20001, CharUSuppCharHigh.toCharArray()));
136 assertEquals(0, CharU20001.indexOf(CharUSuppCharLow));
137 assertEquals(true, StringUtils.containsAny(CharU20001, CharUSuppCharLow.toCharArray()));
138 }
139
140 /**
141 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
142 */
143 public void testContainsAny_StringCharArrayWithSupplementaryChars() {
144 assertEquals(true, StringUtils.containsAny(CharU20000 + CharU20001, CharU20000.toCharArray()));
145 assertEquals(true, StringUtils.containsAny("a" + CharU20000 + CharU20001, "a".toCharArray()));
146 assertEquals(true, StringUtils.containsAny(CharU20000 + "a" + CharU20001, "a".toCharArray()));
147 assertEquals(true, StringUtils.containsAny(CharU20000 + CharU20001 + "a", "a".toCharArray()));
148 assertEquals(true, StringUtils.containsAny(CharU20000 + CharU20001, CharU20001.toCharArray()));
149 assertEquals(true, StringUtils.containsAny(CharU20000, CharU20000.toCharArray()));
150 // Sanity check:
151 assertEquals(-1, CharU20000.indexOf(CharU20001));
152 assertEquals(0, CharU20000.indexOf(CharU20001.charAt(0)));
153 assertEquals(-1, CharU20000.indexOf(CharU20001.charAt(1)));
154 // Test:
155 assertEquals(false, StringUtils.containsAny(CharU20000, CharU20001.toCharArray()));
156 assertEquals(false, StringUtils.containsAny(CharU20001, CharU20000.toCharArray()));
157 }
158
159 public void testContainsAny_StringString() {
160 assertFalse(StringUtils.containsAny(null, (String) null));
161 assertFalse(StringUtils.containsAny(null, ""));
162 assertFalse(StringUtils.containsAny(null, "ab"));
163
164 assertFalse(StringUtils.containsAny("", (String) null));
165 assertFalse(StringUtils.containsAny("", ""));
166 assertFalse(StringUtils.containsAny("", "ab"));
167
168 assertFalse(StringUtils.containsAny("zzabyycdxx", (String) null));
169 assertFalse(StringUtils.containsAny("zzabyycdxx", ""));
170 assertTrue(StringUtils.containsAny("zzabyycdxx", "za"));
171 assertTrue(StringUtils.containsAny("zzabyycdxx", "by"));
172 assertFalse(StringUtils.containsAny("ab", "z"));
173 }
174
175 /**
176 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
177 */
178 public void testContainsAny_StringWithBadSupplementaryChars() {
179 // Test edge case: 1/2 of a (broken) supplementary char
180 assertEquals(false, StringUtils.containsAny(CharUSuppCharHigh, CharU20001));
181 assertEquals(-1, CharUSuppCharLow.indexOf(CharU20001));
182 assertEquals(false, StringUtils.containsAny(CharUSuppCharLow, CharU20001));
183 assertEquals(false, StringUtils.containsAny(CharU20001, CharUSuppCharHigh));
184 assertEquals(0, CharU20001.indexOf(CharUSuppCharLow));
185 assertEquals(true, StringUtils.containsAny(CharU20001, CharUSuppCharLow));
186 }
187
188 /**
189 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
190 */
191 public void testContainsAny_StringWithSupplementaryChars() {
192 assertEquals(true, StringUtils.containsAny(CharU20000 + CharU20001, CharU20000));
193 assertEquals(true, StringUtils.containsAny(CharU20000 + CharU20001, CharU20001));
194 assertEquals(true, StringUtils.containsAny(CharU20000, CharU20000));
195 // Sanity check:
196 assertEquals(-1, CharU20000.indexOf(CharU20001));
197 assertEquals(0, CharU20000.indexOf(CharU20001.charAt(0)));
198 assertEquals(-1, CharU20000.indexOf(CharU20001.charAt(1)));
199 // Test:
200 assertEquals(false, StringUtils.containsAny(CharU20000, CharU20001));
201 assertEquals(false, StringUtils.containsAny(CharU20001, CharU20000));
202 }
203
204 public void testContainsIgnoreCase_LocaleIndependence() {
205 Locale orig = Locale.getDefault();
206
207 Locale[] locales = { Locale.ENGLISH, new Locale("tr"), Locale.getDefault() };
208
209 String[][] tdata = {
210 { "i", "I" },
211 { "I", "i" },
212 { "\u03C2", "\u03C3" },
213 { "\u03A3", "\u03C2" },
214 { "\u03A3", "\u03C3" },
215 };
216
217 String[][] fdata = {
218 { "\u00DF", "SS" },
219 };
220
221 try {
222 for (Locale locale : locales) {
223 Locale.setDefault(locale);
224 for (int j = 0; j < tdata.length; j++) {
225 assertTrue(Locale.getDefault() + ": " + j + " " + tdata[j][0] + " " + tdata[j][1], StringUtils
226 .containsIgnoreCase(tdata[j][0], tdata[j][1]));
227 }
228 for (int j = 0; j < fdata.length; j++) {
229 assertFalse(Locale.getDefault() + ": " + j + " " + fdata[j][0] + " " + fdata[j][1], StringUtils
230 .containsIgnoreCase(fdata[j][0], fdata[j][1]));
231 }
232 }
233 } finally {
234 Locale.setDefault(orig);
235 }
236 }
237
238 public void testContainsIgnoreCase_StringString() {
239 assertFalse(StringUtils.containsIgnoreCase(null, null));
240
241 // Null tests
242 assertFalse(StringUtils.containsIgnoreCase(null, ""));
243 assertFalse(StringUtils.containsIgnoreCase(null, "a"));
244 assertFalse(StringUtils.containsIgnoreCase(null, "abc"));
245
246 assertFalse(StringUtils.containsIgnoreCase("", null));
247 assertFalse(StringUtils.containsIgnoreCase("a", null));
248 assertFalse(StringUtils.containsIgnoreCase("abc", null));
249
250 // Match len = 0
251 assertTrue(StringUtils.containsIgnoreCase("", ""));
252 assertTrue(StringUtils.containsIgnoreCase("a", ""));
253 assertTrue(StringUtils.containsIgnoreCase("abc", ""));
254
255 // Match len = 1
256 assertFalse(StringUtils.containsIgnoreCase("", "a"));
257 assertTrue(StringUtils.containsIgnoreCase("a", "a"));
258 assertTrue(StringUtils.containsIgnoreCase("abc", "a"));
259 assertFalse(StringUtils.containsIgnoreCase("", "A"));
260 assertTrue(StringUtils.containsIgnoreCase("a", "A"));
261 assertTrue(StringUtils.containsIgnoreCase("abc", "A"));
262
263 // Match len > 1
264 assertFalse(StringUtils.containsIgnoreCase("", "abc"));
265 assertFalse(StringUtils.containsIgnoreCase("a", "abc"));
266 assertTrue(StringUtils.containsIgnoreCase("xabcz", "abc"));
267 assertFalse(StringUtils.containsIgnoreCase("", "ABC"));
268 assertFalse(StringUtils.containsIgnoreCase("a", "ABC"));
269 assertTrue(StringUtils.containsIgnoreCase("xabcz", "ABC"));
270 }
271
272 public void testContainsNone_CharArray() {
273 String str1 = "a";
274 String str2 = "b";
275 String str3 = "ab.";
276 char[] chars1= {'b'};
277 char[] chars2= {'.'};
278 char[] chars3= {'c', 'd'};
279 char[] emptyChars = new char[0];
280 assertEquals(true, StringUtils.containsNone(null, (char[]) null));
281 assertEquals(true, StringUtils.containsNone("", (char[]) null));
282 assertEquals(true, StringUtils.containsNone(null, emptyChars));
283 assertEquals(true, StringUtils.containsNone(str1, emptyChars));
284 assertEquals(true, StringUtils.containsNone("", emptyChars));
285 assertEquals(true, StringUtils.containsNone("", chars1));
286 assertEquals(true, StringUtils.containsNone(str1, chars1));
287 assertEquals(true, StringUtils.containsNone(str1, chars2));
288 assertEquals(true, StringUtils.containsNone(str1, chars3));
289 assertEquals(false, StringUtils.containsNone(str2, chars1));
290 assertEquals(true, StringUtils.containsNone(str2, chars2));
291 assertEquals(true, StringUtils.containsNone(str2, chars3));
292 assertEquals(false, StringUtils.containsNone(str3, chars1));
293 assertEquals(false, StringUtils.containsNone(str3, chars2));
294 assertEquals(true, StringUtils.containsNone(str3, chars3));
295 }
296
297 /**
298 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
299 */
300 public void testContainsNone_CharArrayWithBadSupplementaryChars() {
301 // Test edge case: 1/2 of a (broken) supplementary char
302 assertEquals(true, StringUtils.containsNone(CharUSuppCharHigh, CharU20001.toCharArray()));
303 assertEquals(-1, CharUSuppCharLow.indexOf(CharU20001));
304 assertEquals(true, StringUtils.containsNone(CharUSuppCharLow, CharU20001.toCharArray()));
305 assertEquals(-1, CharU20001.indexOf(CharUSuppCharHigh));
306 assertEquals(true, StringUtils.containsNone(CharU20001, CharUSuppCharHigh.toCharArray()));
307 assertEquals(0, CharU20001.indexOf(CharUSuppCharLow));
308 assertEquals(false, StringUtils.containsNone(CharU20001, CharUSuppCharLow.toCharArray()));
309 }
310
311 /**
312 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
313 */
314 public void testContainsNone_CharArrayWithSupplementaryChars() {
315 assertEquals(false, StringUtils.containsNone(CharU20000 + CharU20001, CharU20000.toCharArray()));
316 assertEquals(false, StringUtils.containsNone(CharU20000 + CharU20001, CharU20001.toCharArray()));
317 assertEquals(false, StringUtils.containsNone(CharU20000, CharU20000.toCharArray()));
318 // Sanity check:
319 assertEquals(-1, CharU20000.indexOf(CharU20001));
320 assertEquals(0, CharU20000.indexOf(CharU20001.charAt(0)));
321 assertEquals(-1, CharU20000.indexOf(CharU20001.charAt(1)));
322 // Test:
323 assertEquals(true, StringUtils.containsNone(CharU20000, CharU20001.toCharArray()));
324 assertEquals(true, StringUtils.containsNone(CharU20001, CharU20000.toCharArray()));
325 }
326
327 public void testContainsNone_String() {
328 String str1 = "a";
329 String str2 = "b";
330 String str3 = "ab.";
331 String chars1= "b";
332 String chars2= ".";
333 String chars3= "cd";
334 assertEquals(true, StringUtils.containsNone(null, (String) null));
335 assertEquals(true, StringUtils.containsNone("", (String) null));
336 assertEquals(true, StringUtils.containsNone(null, ""));
337 assertEquals(true, StringUtils.containsNone(str1, ""));
338 assertEquals(true, StringUtils.containsNone("", ""));
339 assertEquals(true, StringUtils.containsNone("", chars1));
340 assertEquals(true, StringUtils.containsNone(str1, chars1));
341 assertEquals(true, StringUtils.containsNone(str1, chars2));
342 assertEquals(true, StringUtils.containsNone(str1, chars3));
343 assertEquals(false, StringUtils.containsNone(str2, chars1));
344 assertEquals(true, StringUtils.containsNone(str2, chars2));
345 assertEquals(true, StringUtils.containsNone(str2, chars3));
346 assertEquals(false, StringUtils.containsNone(str3, chars1));
347 assertEquals(false, StringUtils.containsNone(str3, chars2));
348 assertEquals(true, StringUtils.containsNone(str3, chars3));
349 }
350
351 /**
352 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
353 */
354 public void testContainsNone_StringWithBadSupplementaryChars() {
355 // Test edge case: 1/2 of a (broken) supplementary char
356 assertEquals(true, StringUtils.containsNone(CharUSuppCharHigh, CharU20001));
357 assertEquals(-1, CharUSuppCharLow.indexOf(CharU20001));
358 assertEquals(true, StringUtils.containsNone(CharUSuppCharLow, CharU20001));
359 assertEquals(-1, CharU20001.indexOf(CharUSuppCharHigh));
360 assertEquals(true, StringUtils.containsNone(CharU20001, CharUSuppCharHigh));
361 assertEquals(0, CharU20001.indexOf(CharUSuppCharLow));
362 assertEquals(false, StringUtils.containsNone(CharU20001, CharUSuppCharLow));
363 }
364
365 /**
366 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
367 */
368 public void testContainsNone_StringWithSupplementaryChars() {
369 assertEquals(false, StringUtils.containsNone(CharU20000 + CharU20001, CharU20000));
370 assertEquals(false, StringUtils.containsNone(CharU20000 + CharU20001, CharU20001));
371 assertEquals(false, StringUtils.containsNone(CharU20000, CharU20000));
372 // Sanity check:
373 assertEquals(-1, CharU20000.indexOf(CharU20001));
374 assertEquals(0, CharU20000.indexOf(CharU20001.charAt(0)));
375 assertEquals(-1, CharU20000.indexOf(CharU20001.charAt(1)));
376 // Test:
377 assertEquals(true, StringUtils.containsNone(CharU20000, CharU20001));
378 assertEquals(true, StringUtils.containsNone(CharU20001, CharU20000));
379 }
380
381 public void testContainsOnly_CharArray() {
382 String str1 = "a";
383 String str2 = "b";
384 String str3 = "ab";
385 char[] chars1= {'b'};
386 char[] chars2= {'a'};
387 char[] chars3= {'a', 'b'};
388 char[] emptyChars = new char[0];
389 assertEquals(false, StringUtils.containsOnly(null, (char[]) null));
390 assertEquals(false, StringUtils.containsOnly("", (char[]) null));
391 assertEquals(false, StringUtils.containsOnly(null, emptyChars));
392 assertEquals(false, StringUtils.containsOnly(str1, emptyChars));
393 assertEquals(true, StringUtils.containsOnly("", emptyChars));
394 assertEquals(true, StringUtils.containsOnly("", chars1));
395 assertEquals(false, StringUtils.containsOnly(str1, chars1));
396 assertEquals(true, StringUtils.containsOnly(str1, chars2));
397 assertEquals(true, StringUtils.containsOnly(str1, chars3));
398 assertEquals(true, StringUtils.containsOnly(str2, chars1));
399 assertEquals(false, StringUtils.containsOnly(str2, chars2));
400 assertEquals(true, StringUtils.containsOnly(str2, chars3));
401 assertEquals(false, StringUtils.containsOnly(str3, chars1));
402 assertEquals(false, StringUtils.containsOnly(str3, chars2));
403 assertEquals(true, StringUtils.containsOnly(str3, chars3));
404 }
405
406 public void testContainsOnly_String() {
407 String str1 = "a";
408 String str2 = "b";
409 String str3 = "ab";
410 String chars1= "b";
411 String chars2= "a";
412 String chars3= "ab";
413 assertEquals(false, StringUtils.containsOnly(null, (String) null));
414 assertEquals(false, StringUtils.containsOnly("", (String) null));
415 assertEquals(false, StringUtils.containsOnly(null, ""));
416 assertEquals(false, StringUtils.containsOnly(str1, ""));
417 assertEquals(true, StringUtils.containsOnly("", ""));
418 assertEquals(true, StringUtils.containsOnly("", chars1));
419 assertEquals(false, StringUtils.containsOnly(str1, chars1));
420 assertEquals(true, StringUtils.containsOnly(str1, chars2));
421 assertEquals(true, StringUtils.containsOnly(str1, chars3));
422 assertEquals(true, StringUtils.containsOnly(str2, chars1));
423 assertEquals(false, StringUtils.containsOnly(str2, chars2));
424 assertEquals(true, StringUtils.containsOnly(str2, chars3));
425 assertEquals(false, StringUtils.containsOnly(str3, chars1));
426 assertEquals(false, StringUtils.containsOnly(str3, chars2));
427 assertEquals(true, StringUtils.containsOnly(str3, chars3));
428 }
429
430 public void testContainsWhitespace() {
431 assertFalse( StringUtils.containsWhitespace("") );
432 assertTrue( StringUtils.containsWhitespace(" ") );
433 assertFalse( StringUtils.containsWhitespace("a") );
434 assertTrue( StringUtils.containsWhitespace("a ") );
435 assertTrue( StringUtils.containsWhitespace(" a") );
436 assertTrue( StringUtils.containsWhitespace("a\t") );
437 assertTrue( StringUtils.containsWhitespace("\n") );
438 }
439
440 public void testEquals() {
441 assertEquals(true, StringUtils.equals(null, null));
442 assertEquals(true, StringUtils.equals(FOO, FOO));
443 assertEquals(true, StringUtils.equals(FOO, new String(new char[] { 'f', 'o', 'o' })));
444 assertEquals(false, StringUtils.equals(FOO, new String(new char[] { 'f', 'O', 'O' })));
445 assertEquals(false, StringUtils.equals(FOO, BAR));
446 assertEquals(false, StringUtils.equals(FOO, null));
447 assertEquals(false, StringUtils.equals(null, FOO));
448 }
449
450 public void testEqualsIgnoreCase() {
451 assertEquals(true, StringUtils.equalsIgnoreCase(null, null));
452 assertEquals(true, StringUtils.equalsIgnoreCase(FOO, FOO));
453 assertEquals(true, StringUtils.equalsIgnoreCase(FOO, new String(new char[] { 'f', 'o', 'o' })));
454 assertEquals(true, StringUtils.equalsIgnoreCase(FOO, new String(new char[] { 'f', 'O', 'O' })));
455 assertEquals(false, StringUtils.equalsIgnoreCase(FOO, BAR));
456 assertEquals(false, StringUtils.equalsIgnoreCase(FOO, null));
457 assertEquals(false, StringUtils.equalsIgnoreCase(null, FOO));
458 }
459
460 //-----------------------------------------------------------------------
461 public void testIndexOf_char() {
462 assertEquals(-1, StringUtils.indexOf(null, ' '));
463 assertEquals(-1, StringUtils.indexOf("", ' '));
464 assertEquals(0, StringUtils.indexOf("aabaabaa", 'a'));
465 assertEquals(2, StringUtils.indexOf("aabaabaa", 'b'));
466
467 assertEquals(2, StringUtils.indexOf(new StringBuilder("aabaabaa"), 'b'));
468 }
469
470 public void testIndexOf_charInt() {
471 assertEquals(-1, StringUtils.indexOf(null, ' ', 0));
472 assertEquals(-1, StringUtils.indexOf(null, ' ', -1));
473 assertEquals(-1, StringUtils.indexOf("", ' ', 0));
474 assertEquals(-1, StringUtils.indexOf("", ' ', -1));
475 assertEquals(0, StringUtils.indexOf("aabaabaa", 'a', 0));
476 assertEquals(2, StringUtils.indexOf("aabaabaa", 'b', 0));
477 assertEquals(5, StringUtils.indexOf("aabaabaa", 'b', 3));
478 assertEquals(-1, StringUtils.indexOf("aabaabaa", 'b', 9));
479 assertEquals(2, StringUtils.indexOf("aabaabaa", 'b', -1));
480
481 assertEquals(5, StringUtils.indexOf(new StringBuilder("aabaabaa"), 'b', 3));
482 }
483
484 public void testIndexOf_String() {
485 assertEquals(-1, StringUtils.indexOf(null, null));
486 assertEquals(-1, StringUtils.indexOf("", null));
487 assertEquals(0, StringUtils.indexOf("", ""));
488 assertEquals(0, StringUtils.indexOf("aabaabaa", "a"));
489 assertEquals(2, StringUtils.indexOf("aabaabaa", "b"));
490 assertEquals(1, StringUtils.indexOf("aabaabaa", "ab"));
491 assertEquals(0, StringUtils.indexOf("aabaabaa", ""));
492
493 assertEquals(2, StringUtils.indexOf(new StringBuilder("aabaabaa"), "b"));
494 }
495
496 public void testIndexOf_StringInt() {
497 assertEquals(-1, StringUtils.indexOf(null, null, 0));
498 assertEquals(-1, StringUtils.indexOf(null, null, -1));
499 assertEquals(-1, StringUtils.indexOf(null, "", 0));
500 assertEquals(-1, StringUtils.indexOf(null, "", -1));
501 assertEquals(-1, StringUtils.indexOf("", null, 0));
502 assertEquals(-1, StringUtils.indexOf("", null, -1));
503 assertEquals(0, StringUtils.indexOf("", "", 0));
504 assertEquals(0, StringUtils.indexOf("", "", -1));
505 assertEquals(0, StringUtils.indexOf("", "", 9));
506 assertEquals(0, StringUtils.indexOf("abc", "", 0));
507 assertEquals(0, StringUtils.indexOf("abc", "", -1));
508 assertEquals(3, StringUtils.indexOf("abc", "", 9));
509 assertEquals(3, StringUtils.indexOf("abc", "", 3));
510 assertEquals(0, StringUtils.indexOf("aabaabaa", "a", 0));
511 assertEquals(2, StringUtils.indexOf("aabaabaa", "b", 0));
512 assertEquals(1, StringUtils.indexOf("aabaabaa", "ab", 0));
513 assertEquals(5, StringUtils.indexOf("aabaabaa", "b", 3));
514 assertEquals(-1, StringUtils.indexOf("aabaabaa", "b", 9));
515 assertEquals(2, StringUtils.indexOf("aabaabaa", "b", -1));
516 assertEquals(2,StringUtils.indexOf("aabaabaa", "", 2));
517
518 assertEquals(5, StringUtils.indexOf(new StringBuilder("aabaabaa"), "b", 3));
519 }
520
521 public void testIndexOfAny_StringCharArray() {
522 assertEquals(-1, StringUtils.indexOfAny(null, (char[]) null));
523 assertEquals(-1, StringUtils.indexOfAny(null, new char[0]));
524 assertEquals(-1, StringUtils.indexOfAny(null, new char[] {'a','b'}));
525
526 assertEquals(-1, StringUtils.indexOfAny("", (char[]) null));
527 assertEquals(-1, StringUtils.indexOfAny("", new char[0]));
528 assertEquals(-1, StringUtils.indexOfAny("", new char[] {'a','b'}));
529
530 assertEquals(-1, StringUtils.indexOfAny("zzabyycdxx", (char[]) null));
531 assertEquals(-1, StringUtils.indexOfAny("zzabyycdxx", new char[0]));
532 assertEquals(0, StringUtils.indexOfAny("zzabyycdxx", new char[] {'z','a'}));
533 assertEquals(3, StringUtils.indexOfAny("zzabyycdxx", new char[] {'b','y'}));
534 assertEquals(-1, StringUtils.indexOfAny("ab", new char[] {'z'}));
535 }
536
537 /**
538 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
539 */
540 public void testIndexOfAny_StringCharArrayWithSupplementaryChars() {
541 assertEquals(0, StringUtils.indexOfAny(CharU20000 + CharU20001, CharU20000.toCharArray()));
542 assertEquals(2, StringUtils.indexOfAny(CharU20000 + CharU20001, CharU20001.toCharArray()));
543 assertEquals(0, StringUtils.indexOfAny(CharU20000, CharU20000.toCharArray()));
544 assertEquals(-1, StringUtils.indexOfAny(CharU20000, CharU20001.toCharArray()));
545 }
546
547 public void testIndexOfAny_StringString() {
548 assertEquals(-1, StringUtils.indexOfAny(null, (String) null));
549 assertEquals(-1, StringUtils.indexOfAny(null, ""));
550 assertEquals(-1, StringUtils.indexOfAny(null, "ab"));
551
552 assertEquals(-1, StringUtils.indexOfAny("", (String) null));
553 assertEquals(-1, StringUtils.indexOfAny("", ""));
554 assertEquals(-1, StringUtils.indexOfAny("", "ab"));
555
556 assertEquals(-1, StringUtils.indexOfAny("zzabyycdxx", (String) null));
557 assertEquals(-1, StringUtils.indexOfAny("zzabyycdxx", ""));
558 assertEquals(0, StringUtils.indexOfAny("zzabyycdxx", "za"));
559 assertEquals(3, StringUtils.indexOfAny("zzabyycdxx", "by"));
560 assertEquals(-1, StringUtils.indexOfAny("ab", "z"));
561 }
562
563 public void testIndexOfAny_StringStringArray() {
564 assertEquals(-1, StringUtils.indexOfAny(null, (String[]) null));
565 assertEquals(-1, StringUtils.indexOfAny(null, FOOBAR_SUB_ARRAY));
566 assertEquals(-1, StringUtils.indexOfAny(FOOBAR, (String[]) null));
567 assertEquals(2, StringUtils.indexOfAny(FOOBAR, FOOBAR_SUB_ARRAY));
568 assertEquals(-1, StringUtils.indexOfAny(FOOBAR, new String[0]));
569 assertEquals(-1, StringUtils.indexOfAny(null, new String[0]));
570 assertEquals(-1, StringUtils.indexOfAny("", new String[0]));
571 assertEquals(-1, StringUtils.indexOfAny(FOOBAR, new String[] {"llll"}));
572 assertEquals(0, StringUtils.indexOfAny(FOOBAR, new String[] {""}));
573 assertEquals(0, StringUtils.indexOfAny("", new String[] {""}));
574 assertEquals(-1, StringUtils.indexOfAny("", new String[] {"a"}));
575 assertEquals(-1, StringUtils.indexOfAny("", new String[] {null}));
576 assertEquals(-1, StringUtils.indexOfAny(FOOBAR, new String[] {null}));
577 assertEquals(-1, StringUtils.indexOfAny(null, new String[] {null}));
578 }
579
580 /**
581 * See http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
582 */
583 public void testIndexOfAny_StringStringWithSupplementaryChars() {
584 assertEquals(0, StringUtils.indexOfAny(CharU20000 + CharU20001, CharU20000));
585 assertEquals(2, StringUtils.indexOfAny(CharU20000 + CharU20001, CharU20001));
586 assertEquals(0, StringUtils.indexOfAny(CharU20000, CharU20000));
587 assertEquals(-1, StringUtils.indexOfAny(CharU20000, CharU20001));
588 }
589
590 public void testIndexOfAnyBut_StringCharArray() {
591 assertEquals(-1, StringUtils.indexOfAnyBut(null, (char[]) null));
592 assertEquals(-1, StringUtils.indexOfAnyBut(null, new char[0]));
593 assertEquals(-1, StringUtils.indexOfAnyBut(null, new char[] {'a','b'}));
594
595 assertEquals(-1, StringUtils.indexOfAnyBut("", (char[]) null));
596 assertEquals(-1, StringUtils.indexOfAnyBut("", new char[0]));
597 assertEquals(-1, StringUtils.indexOfAnyBut("", new char[] {'a','b'}));
598
599 assertEquals(-1, StringUtils.indexOfAnyBut("zzabyycdxx", (char[]) null));
600 assertEquals(-1, StringUtils.indexOfAnyBut("zzabyycdxx", new char[0]));
601 assertEquals(3, StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z','a'}));
602 assertEquals(0, StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'b','y'}));
603 assertEquals(-1, StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'}));
604 assertEquals(0, StringUtils.indexOfAnyBut("aba", new char[] {'z'}));
605
606 }
607
608 public void testIndexOfAnyBut_StringCharArrayWithSupplementaryChars() {
609 assertEquals(2, StringUtils.indexOfAnyBut(CharU20000 + CharU20001, CharU20000.toCharArray()));
610 assertEquals(0, StringUtils.indexOfAnyBut(CharU20000 + CharU20001, CharU20001.toCharArray()));
611 assertEquals(-1, StringUtils.indexOfAnyBut(CharU20000, CharU20000.toCharArray()));
612 assertEquals(0, StringUtils.indexOfAnyBut(CharU20000, CharU20001.toCharArray()));
613 }
614
615 public void testIndexOfAnyBut_StringString() {
616 assertEquals(-1, StringUtils.indexOfAnyBut(null, (String) null));
617 assertEquals(-1, StringUtils.indexOfAnyBut(null, ""));
618 assertEquals(-1, StringUtils.indexOfAnyBut(null, "ab"));
619
620 assertEquals(-1, StringUtils.indexOfAnyBut("", (String) null));
621 assertEquals(-1, StringUtils.indexOfAnyBut("", ""));
622 assertEquals(-1, StringUtils.indexOfAnyBut("", "ab"));
623
624 assertEquals(-1, StringUtils.indexOfAnyBut("zzabyycdxx", (String) null));
625 assertEquals(-1, StringUtils.indexOfAnyBut("zzabyycdxx", ""));
626 assertEquals(3, StringUtils.indexOfAnyBut("zzabyycdxx", "za"));
627 assertEquals(0, StringUtils.indexOfAnyBut("zzabyycdxx", "by"));
628 assertEquals(0, StringUtils.indexOfAnyBut("ab", "z"));
629 }
630
631 public void testIndexOfAnyBut_StringStringWithSupplementaryChars() {
632 assertEquals(2, StringUtils.indexOfAnyBut(CharU20000 + CharU20001, CharU20000));
633 assertEquals(0, StringUtils.indexOfAnyBut(CharU20000 + CharU20001, CharU20001));
634 assertEquals(-1, StringUtils.indexOfAnyBut(CharU20000, CharU20000));
635 assertEquals(0, StringUtils.indexOfAnyBut(CharU20000, CharU20001));
636 }
637
638 public void testIndexOfIgnoreCase_String() {
639 assertEquals(-1, StringUtils.indexOfIgnoreCase(null, null));
640 assertEquals(-1, StringUtils.indexOfIgnoreCase(null, ""));
641 assertEquals(-1, StringUtils.indexOfIgnoreCase("", null));
642 assertEquals(0, StringUtils.indexOfIgnoreCase("", ""));
643 assertEquals(0, StringUtils.indexOfIgnoreCase("aabaabaa", "a"));
644 assertEquals(0, StringUtils.indexOfIgnoreCase("aabaabaa", "A"));
645 assertEquals(2, StringUtils.indexOfIgnoreCase("aabaabaa", "b"));
646 assertEquals(2, StringUtils.indexOfIgnoreCase("aabaabaa", "B"));
647 assertEquals(1, StringUtils.indexOfIgnoreCase("aabaabaa", "ab"));
648 assertEquals(1, StringUtils.indexOfIgnoreCase("aabaabaa", "AB"));
649 assertEquals(0, StringUtils.indexOfIgnoreCase("aabaabaa", ""));
650 }
651
652 public void testIndexOfIgnoreCase_StringInt() {
653 assertEquals(1, StringUtils.indexOfIgnoreCase("aabaabaa", "AB", -1));
654 assertEquals(1, StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0));
655 assertEquals(1, StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 1));
656 assertEquals(4, StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 2));
657 assertEquals(4, StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 3));
658 assertEquals(4, StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 4));
659 assertEquals(-1, StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 5));
660 assertEquals(-1, StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 6));
661 assertEquals(-1, StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 7));
662 assertEquals(-1, StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 8));
663 assertEquals(1, StringUtils.indexOfIgnoreCase("aab", "AB", 1));
664 assertEquals(5, StringUtils.indexOfIgnoreCase("aabaabaa", "", 5));
665 assertEquals(-1, StringUtils.indexOfIgnoreCase("ab", "AAB", 0));
666 assertEquals(-1, StringUtils.indexOfIgnoreCase("aab", "AAB", 1));
667 }
668
669 public void testLastIndexOf_char() {
670 assertEquals(-1, StringUtils.lastIndexOf(null, ' '));
671 assertEquals(-1, StringUtils.lastIndexOf("", ' '));
672 assertEquals(7, StringUtils.lastIndexOf("aabaabaa", 'a'));
673 assertEquals(5, StringUtils.lastIndexOf("aabaabaa", 'b'));
674
675 assertEquals(5, StringUtils.lastIndexOf(new StringBuilder("aabaabaa"), 'b'));
676 }
677
678 public void testLastIndexOf_charInt() {
679 assertEquals(-1, StringUtils.lastIndexOf(null, ' ', 0));
680 assertEquals(-1, StringUtils.lastIndexOf(null, ' ', -1));
681 assertEquals(-1, StringUtils.lastIndexOf("", ' ', 0));
682 assertEquals(-1, StringUtils.lastIndexOf("", ' ', -1));
683 assertEquals(7, StringUtils.lastIndexOf("aabaabaa", 'a', 8));
684 assertEquals(5, StringUtils.lastIndexOf("aabaabaa", 'b', 8));
685 assertEquals(2, StringUtils.lastIndexOf("aabaabaa", 'b', 3));
686 assertEquals(5, StringUtils.lastIndexOf("aabaabaa", 'b', 9));
687 assertEquals(-1, StringUtils.lastIndexOf("aabaabaa", 'b', -1));
688 assertEquals(0, StringUtils.lastIndexOf("aabaabaa", 'a', 0));
689
690 assertEquals(2, StringUtils.lastIndexOf(new StringBuilder("aabaabaa"), 'b', 2));
691 }
692
693 public void testLastIndexOf_String() {
694 assertEquals(-1, StringUtils.lastIndexOf(null, null));
695 assertEquals(-1, StringUtils.lastIndexOf("", null));
696 assertEquals(-1, StringUtils.lastIndexOf("", "a"));
697 assertEquals(0, StringUtils.lastIndexOf("", ""));
698 assertEquals(8, StringUtils.lastIndexOf("aabaabaa", ""));
699 assertEquals(7, StringUtils.lastIndexOf("aabaabaa", "a"));
700 assertEquals(5, StringUtils.lastIndexOf("aabaabaa", "b"));
701 assertEquals(4, StringUtils.lastIndexOf("aabaabaa", "ab"));
702
703 assertEquals(4, StringUtils.lastIndexOf(new StringBuilder("aabaabaa"), "ab"));
704 }
705
706 public void testLastIndexOf_StringInt() {
707 assertEquals(-1, StringUtils.lastIndexOf(null, null, 0));
708 assertEquals(-1, StringUtils.lastIndexOf(null, null, -1));
709 assertEquals(-1, StringUtils.lastIndexOf(null, "", 0));
710 assertEquals(-1, StringUtils.lastIndexOf(null, "", -1));
711 assertEquals(-1, StringUtils.lastIndexOf("", null, 0));
712 assertEquals(-1, StringUtils.lastIndexOf("", null, -1));
713 assertEquals(0, StringUtils.lastIndexOf("", "", 0));
714 assertEquals(-1, StringUtils.lastIndexOf("", "", -1));
715 assertEquals(0, StringUtils.lastIndexOf("", "", 9));
716 assertEquals(0, StringUtils.lastIndexOf("abc", "", 0));
717 assertEquals(-1, StringUtils.lastIndexOf("abc", "", -1));
718 assertEquals(3, StringUtils.lastIndexOf("abc", "", 9));
719 assertEquals(7, StringUtils.lastIndexOf("aabaabaa", "a", 8));
720 assertEquals(5, StringUtils.lastIndexOf("aabaabaa", "b", 8));
721 assertEquals(4, StringUtils.lastIndexOf("aabaabaa", "ab", 8));
722 assertEquals(2, StringUtils.lastIndexOf("aabaabaa", "b", 3));
723 assertEquals(5, StringUtils.lastIndexOf("aabaabaa", "b", 9));
724 assertEquals(-1, StringUtils.lastIndexOf("aabaabaa", "b", -1));
725 assertEquals(-1, StringUtils.lastIndexOf("aabaabaa", "b", 0));
726 assertEquals(0, StringUtils.lastIndexOf("aabaabaa", "a", 0));
727
728 assertEquals(2, StringUtils.lastIndexOf(new StringBuilder("aabaabaa"), "b", 3));
729 }
730
731 public void testLastIndexOfAny_StringStringArray() {
732 assertEquals(-1, StringUtils.lastIndexOfAny(null, (CharSequence) null)); // test both types of ...
733 assertEquals(-1, StringUtils.lastIndexOfAny(null, (CharSequence[]) null)); // ... varargs invocation
734 assertEquals(-1, StringUtils.lastIndexOfAny(null)); // Missing varag
735 assertEquals(-1, StringUtils.lastIndexOfAny(null, FOOBAR_SUB_ARRAY));
736 assertEquals(-1, StringUtils.lastIndexOfAny(FOOBAR, (CharSequence) null)); // test both types of ...
737 assertEquals(-1, StringUtils.lastIndexOfAny(FOOBAR, (CharSequence[]) null)); // ... varargs invocation
738 assertEquals(-1, StringUtils.lastIndexOfAny(FOOBAR)); // Missing vararg
739 assertEquals(3, StringUtils.lastIndexOfAny(FOOBAR, FOOBAR_SUB_ARRAY));
740 assertEquals(-1, StringUtils.lastIndexOfAny(FOOBAR, new String[0]));
741 assertEquals(-1, StringUtils.lastIndexOfAny(null, new String[0]));
742 assertEquals(-1, StringUtils.lastIndexOfAny("", new String[0]));
743 assertEquals(-1, StringUtils.lastIndexOfAny(FOOBAR, new String[] {"llll"}));
744 assertEquals(6, StringUtils.lastIndexOfAny(FOOBAR, new String[] {""}));
745 assertEquals(0, StringUtils.lastIndexOfAny("", new String[] {""}));
746 assertEquals(-1, StringUtils.lastIndexOfAny("", new String[] {"a"}));
747 assertEquals(-1, StringUtils.lastIndexOfAny("", new String[] {null}));
748 assertEquals(-1, StringUtils.lastIndexOfAny(FOOBAR, new String[] {null}));
749 assertEquals(-1, StringUtils.lastIndexOfAny(null, new String[] {null}));
750 }
751
752 public void testLastIndexOfIgnoreCase_String() {
753 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase(null, null));
754 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase("", null));
755 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase(null, ""));
756 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase("", "a"));
757 assertEquals(0, StringUtils.lastIndexOfIgnoreCase("", ""));
758 assertEquals(8, StringUtils.lastIndexOfIgnoreCase("aabaabaa", ""));
759 assertEquals(7, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "a"));
760 assertEquals(7, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A"));
761 assertEquals(5, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "b"));
762 assertEquals(5, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B"));
763 assertEquals(4, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "ab"));
764 assertEquals(4, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB"));
765 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase("ab", "AAB"));
766 assertEquals(0, StringUtils.lastIndexOfIgnoreCase("aab", "AAB"));
767 }
768
769 public void testLastIndexOfIgnoreCase_StringInt() {
770 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase(null, null, 0));
771 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase(null, null, -1));
772 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase(null, "", 0));
773 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase(null, "", -1));
774 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase("", null, 0));
775 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase("", null, -1));
776 assertEquals(0, StringUtils.lastIndexOfIgnoreCase("", "", 0));
777 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase("", "", -1));
778 assertEquals(0, StringUtils.lastIndexOfIgnoreCase("", "", 9));
779 assertEquals(0, StringUtils.lastIndexOfIgnoreCase("abc", "", 0));
780 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase("abc", "", -1));
781 assertEquals(3, StringUtils.lastIndexOfIgnoreCase("abc", "", 9));
782 assertEquals(7, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8));
783 assertEquals(5, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8));
784 assertEquals(4, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8));
785 assertEquals(2, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 3));
786 assertEquals(5, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9));
787 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1));
788 assertEquals(-1, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0));
789 assertEquals(0, StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0));
790 assertEquals(1, StringUtils.lastIndexOfIgnoreCase("aab", "AB", 1));
791 }
792
793 public void testLastOrdinalIndexOf() {
794 assertEquals(-1, StringUtils.lastOrdinalIndexOf(null, "*", 42) );
795 assertEquals(-1, StringUtils.lastOrdinalIndexOf("*", null, 42) );
796 assertEquals(0, StringUtils.lastOrdinalIndexOf("", "", 42) );
797 assertEquals(7, StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) );
798 assertEquals(6, StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) );
799 assertEquals(5, StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) );
800 assertEquals(2, StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) );
801 assertEquals(4, StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) );
802 assertEquals(1, StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) );
803 assertEquals(8, StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) );
804 assertEquals(8, StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) );
805 }
806
807 public void testOrdinalIndexOf() {
808 assertEquals(-1, StringUtils.ordinalIndexOf(null, null, Integer.MIN_VALUE));
809 assertEquals(-1, StringUtils.ordinalIndexOf("", null, Integer.MIN_VALUE));
810 assertEquals(-1, StringUtils.ordinalIndexOf("", "", Integer.MIN_VALUE));
811 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "a", Integer.MIN_VALUE));
812 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "b", Integer.MIN_VALUE));
813 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "ab", Integer.MIN_VALUE));
814 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "", Integer.MIN_VALUE));
815
816 assertEquals(-1, StringUtils.ordinalIndexOf(null, null, -1));
817 assertEquals(-1, StringUtils.ordinalIndexOf("", null, -1));
818 assertEquals(-1, StringUtils.ordinalIndexOf("", "", -1));
819 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "a", -1));
820 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "b", -1));
821 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "ab", -1));
822 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "", -1));
823
824 assertEquals(-1, StringUtils.ordinalIndexOf(null, null, 0));
825 assertEquals(-1, StringUtils.ordinalIndexOf("", null, 0));
826 assertEquals(-1, StringUtils.ordinalIndexOf("", "", 0));
827 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "a", 0));
828 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "b", 0));
829 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "ab", 0));
830 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "", 0));
831
832 assertEquals(-1, StringUtils.ordinalIndexOf(null, null, 1));
833 assertEquals(-1, StringUtils.ordinalIndexOf("", null, 1));
834 assertEquals(0, StringUtils.ordinalIndexOf("", "", 1));
835 assertEquals(0, StringUtils.ordinalIndexOf("aabaabaa", "a", 1));
836 assertEquals(2, StringUtils.ordinalIndexOf("aabaabaa", "b", 1));
837 assertEquals(1, StringUtils.ordinalIndexOf("aabaabaa", "ab", 1));
838 assertEquals(0, StringUtils.ordinalIndexOf("aabaabaa", "", 1));
839
840 assertEquals(-1, StringUtils.ordinalIndexOf(null, null, 2));
841 assertEquals(-1, StringUtils.ordinalIndexOf("", null, 2));
842 assertEquals(0, StringUtils.ordinalIndexOf("", "", 2));
843 assertEquals(1, StringUtils.ordinalIndexOf("aabaabaa", "a", 2));
844 assertEquals(5, StringUtils.ordinalIndexOf("aabaabaa", "b", 2));
845 assertEquals(4, StringUtils.ordinalIndexOf("aabaabaa", "ab", 2));
846 assertEquals(0, StringUtils.ordinalIndexOf("aabaabaa", "", 2));
847
848 assertEquals(-1, StringUtils.ordinalIndexOf(null, null, Integer.MAX_VALUE));
849 assertEquals(-1, StringUtils.ordinalIndexOf("", null, Integer.MAX_VALUE));
850 assertEquals(0, StringUtils.ordinalIndexOf("", "", Integer.MAX_VALUE));
851 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "a", Integer.MAX_VALUE));
852 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "b", Integer.MAX_VALUE));
853 assertEquals(-1, StringUtils.ordinalIndexOf("aabaabaa", "ab", Integer.MAX_VALUE));
854 assertEquals(0, StringUtils.ordinalIndexOf("aabaabaa", "", Integer.MAX_VALUE));
855
856 assertEquals(-1, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 0));
857 assertEquals(0, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 1));
858 assertEquals(1, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 2));
859 assertEquals(2, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 3));
860 assertEquals(3, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 4));
861 assertEquals(4, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 5));
862 assertEquals(5, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 6));
863 assertEquals(6, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 7));
864 assertEquals(7, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 8));
865 assertEquals(8, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 9));
866 assertEquals(-1, StringUtils.ordinalIndexOf("aaaaaaaaa", "a", 10));
867 }
868
869 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import junit.framework.TestCase;
19
20 /**
21 * Unit tests {@link org.apache.commons.lang3.StringUtils} - Substring methods
22 *
23 * @version $Id: StringUtilsIsTest.java 1088899 2011-04-05 05:31:27Z bayard $
24 */
25 public class StringUtilsIsTest extends TestCase {
26
27 public StringUtilsIsTest(String name) {
28 super(name);
29 }
30
31 //-----------------------------------------------------------------------
32
33 public void testIsAlpha() {
34 assertEquals(false, StringUtils.isAlpha(null));
35 assertEquals(false, StringUtils.isAlpha(""));
36 assertEquals(false, StringUtils.isAlpha(" "));
37 assertEquals(true, StringUtils.isAlpha("a"));
38 assertEquals(true, StringUtils.isAlpha("A"));
39 assertEquals(true, StringUtils.isAlpha("kgKgKgKgkgkGkjkjlJlOKLgHdGdHgl"));
40 assertEquals(false, StringUtils.isAlpha("ham kso"));
41 assertEquals(false, StringUtils.isAlpha("1"));
42 assertEquals(false, StringUtils.isAlpha("hkHKHik6iUGHKJgU7tUJgKJGI87GIkug"));
43 assertEquals(false, StringUtils.isAlpha("_"));
44 assertEquals(false, StringUtils.isAlpha("hkHKHik*khbkuh"));
45 }
46
47 public void testIsAlphanumeric() {
48 assertEquals(false, StringUtils.isAlphanumeric(null));
49 assertEquals(false, StringUtils.isAlphanumeric(""));
50 assertEquals(false, StringUtils.isAlphanumeric(" "));
51 assertEquals(true, StringUtils.isAlphanumeric("a"));
52 assertEquals(true, StringUtils.isAlphanumeric("A"));
53 assertEquals(true, StringUtils.isAlphanumeric("kgKgKgKgkgkGkjkjlJlOKLgHdGdHgl"));
54 assertEquals(false, StringUtils.isAlphanumeric("ham kso"));
55 assertEquals(true, StringUtils.isAlphanumeric("1"));
56 assertEquals(true, StringUtils.isAlphanumeric("hkHKHik6iUGHKJgU7tUJgKJGI87GIkug"));
57 assertEquals(false, StringUtils.isAlphanumeric("_"));
58 assertEquals(false, StringUtils.isAlphanumeric("hkHKHik*khbkuh"));
59 }
60
61 public void testIsWhitespace() {
62 assertEquals(false, StringUtils.isWhitespace(null));
63 assertEquals(true, StringUtils.isWhitespace(""));
64 assertEquals(true, StringUtils.isWhitespace(" "));
65 assertEquals(true, StringUtils.isWhitespace("\t \n \t"));
66 assertEquals(false, StringUtils.isWhitespace("\t aa\n \t"));
67 assertEquals(true, StringUtils.isWhitespace(" "));
68 assertEquals(false, StringUtils.isWhitespace(" a "));
69 assertEquals(false, StringUtils.isWhitespace("a "));
70 assertEquals(false, StringUtils.isWhitespace(" a"));
71 assertEquals(false, StringUtils.isWhitespace("aba"));
72 assertEquals(true, StringUtils.isWhitespace(StringUtilsTest.WHITESPACE));
73 assertEquals(false, StringUtils.isWhitespace(StringUtilsTest.NON_WHITESPACE));
74 }
75
76 public void testIsAlphaspace() {
77 assertEquals(false, StringUtils.isAlphaSpace(null));
78 assertEquals(true, StringUtils.isAlphaSpace(""));
79 assertEquals(true, StringUtils.isAlphaSpace(" "));
80 assertEquals(true, StringUtils.isAlphaSpace("a"));
81 assertEquals(true, StringUtils.isAlphaSpace("A"));
82 assertEquals(true, StringUtils.isAlphaSpace("kgKgKgKgkgkGkjkjlJlOKLgHdGdHgl"));
83 assertEquals(true, StringUtils.isAlphaSpace("ham kso"));
84 assertEquals(false, StringUtils.isAlphaSpace("1"));
85 assertEquals(false, StringUtils.isAlphaSpace("hkHKHik6iUGHKJgU7tUJgKJGI87GIkug"));
86 assertEquals(false, StringUtils.isAlphaSpace("_"));
87 assertEquals(false, StringUtils.isAlphaSpace("hkHKHik*khbkuh"));
88 }
89
90 public void testIsAlphanumericSpace() {
91 assertEquals(false, StringUtils.isAlphanumericSpace(null));
92 assertEquals(true, StringUtils.isAlphanumericSpace(""));
93 assertEquals(true, StringUtils.isAlphanumericSpace(" "));
94 assertEquals(true, StringUtils.isAlphanumericSpace("a"));
95 assertEquals(true, StringUtils.isAlphanumericSpace("A"));
96 assertEquals(true, StringUtils.isAlphanumericSpace("kgKgKgKgkgkGkjkjlJlOKLgHdGdHgl"));
97 assertEquals(true, StringUtils.isAlphanumericSpace("ham kso"));
98 assertEquals(true, StringUtils.isAlphanumericSpace("1"));
99 assertEquals(true, StringUtils.isAlphanumericSpace("hkHKHik6iUGHKJgU7tUJgKJGI87GIkug"));
100 assertEquals(false, StringUtils.isAlphanumericSpace("_"));
101 assertEquals(false, StringUtils.isAlphanumericSpace("hkHKHik*khbkuh"));
102 }
103
104 public void testIsAsciiPrintable_String() {
105 assertEquals(false, StringUtils.isAsciiPrintable(null));
106 assertEquals(true, StringUtils.isAsciiPrintable(""));
107 assertEquals(true, StringUtils.isAsciiPrintable(" "));
108 assertEquals(true, StringUtils.isAsciiPrintable("a"));
109 assertEquals(true, StringUtils.isAsciiPrintable("A"));
110 assertEquals(true, StringUtils.isAsciiPrintable("1"));
111 assertEquals(true, StringUtils.isAsciiPrintable("Ceki"));
112 assertEquals(true, StringUtils.isAsciiPrintable("!ab2c~"));
113 assertEquals(true, StringUtils.isAsciiPrintable("1000"));
114 assertEquals(true, StringUtils.isAsciiPrintable("10 00"));
115 assertEquals(false, StringUtils.isAsciiPrintable("10\t00"));
116 assertEquals(true, StringUtils.isAsciiPrintable("10.00"));
117 assertEquals(true, StringUtils.isAsciiPrintable("10,00"));
118 assertEquals(true, StringUtils.isAsciiPrintable("!ab-c~"));
119 assertEquals(true, StringUtils.isAsciiPrintable("hkHK=Hik6i?UGH_KJgU7.tUJgKJ*GI87GI,kug"));
120 assertEquals(true, StringUtils.isAsciiPrintable("\u0020"));
121 assertEquals(true, StringUtils.isAsciiPrintable("\u0021"));
122 assertEquals(true, StringUtils.isAsciiPrintable("\u007e"));
123 assertEquals(false, StringUtils.isAsciiPrintable("\u007f"));
124 assertEquals(true, StringUtils.isAsciiPrintable("G?lc?"));
125 assertEquals(true, StringUtils.isAsciiPrintable("=?iso-8859-1?Q?G=FClc=FC?="));
126 assertEquals(false, StringUtils.isAsciiPrintable("G\u00fclc\u00fc"));
127 }
128
129 public void testIsNumeric() {
130 assertEquals(false, StringUtils.isNumeric(null));
131 assertEquals(false, StringUtils.isNumeric(""));
132 assertEquals(false, StringUtils.isNumeric(" "));
133 assertEquals(false, StringUtils.isNumeric("a"));
134 assertEquals(false, StringUtils.isNumeric("A"));
135 assertEquals(false, StringUtils.isNumeric("kgKgKgKgkgkGkjkjlJlOKLgHdGdHgl"));
136 assertEquals(false, StringUtils.isNumeric("ham kso"));
137 assertEquals(true, StringUtils.isNumeric("1"));
138 assertEquals(true, StringUtils.isNumeric("1000"));
139 assertEquals(false, StringUtils.isNumeric("2.3"));
140 assertEquals(false, StringUtils.isNumeric("10 00"));
141 assertEquals(false, StringUtils.isNumeric("hkHKHik6iUGHKJgU7tUJgKJGI87GIkug"));
142 assertEquals(false, StringUtils.isNumeric("_"));
143 assertEquals(false, StringUtils.isNumeric("hkHKHik*khbkuh"));
144 }
145
146 public void testIsNumericSpace() {
147 assertEquals(false, StringUtils.isNumericSpace(null));
148 assertEquals(true, StringUtils.isNumericSpace(""));
149 assertEquals(true, StringUtils.isNumericSpace(" "));
150 assertEquals(false, StringUtils.isNumericSpace("a"));
151 assertEquals(false, StringUtils.isNumericSpace("A"));
152 assertEquals(false, StringUtils.isNumericSpace("kgKgKgKgkgkGkjkjlJlOKLgHdGdHgl"));
153 assertEquals(false, StringUtils.isNumericSpace("ham kso"));
154 assertEquals(true, StringUtils.isNumericSpace("1"));
155 assertEquals(true, StringUtils.isNumericSpace("1000"));
156 assertEquals(false, StringUtils.isNumericSpace("2.3"));
157 assertEquals(true, StringUtils.isNumericSpace("10 00"));
158 assertEquals(false, StringUtils.isNumericSpace("hkHKHik6iUGHKJgU7tUJgKJGI87GIkug"));
159 assertEquals(false, StringUtils.isNumericSpace("_"));
160 assertEquals(false, StringUtils.isNumericSpace("hkHKHik*khbkuh"));
161 }
162
163 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import junit.framework.TestCase;
19
20 import org.apache.commons.lang3.text.StrBuilder;
21
22 /**
23 * Unit tests {@link org.apache.commons.lang3.StringUtils} - StartsWith/EndsWith methods
24 *
25 * @version $Id: StringUtilsStartsEndsWithTest.java 1144929 2011-07-10 18:26:16Z ggregory $
26 */
27 public class StringUtilsStartsEndsWithTest extends TestCase {
28 private static final String foo = "foo";
29 private static final String bar = "bar";
30 private static final String foobar = "foobar";
31 private static final String FOO = "FOO";
32 private static final String BAR = "BAR";
33 private static final String FOOBAR = "FOOBAR";
34
35 public StringUtilsStartsEndsWithTest(String name) {
36 super(name);
37 }
38
39 //-----------------------------------------------------------------------
40
41 /**
42 * Test StringUtils.startsWith()
43 */
44 public void testStartsWith() {
45 assertTrue("startsWith(null, null)", StringUtils.startsWith(null, (String)null));
46 assertFalse("startsWith(FOOBAR, null)", StringUtils.startsWith(FOOBAR, (String)null));
47 assertFalse("startsWith(null, FOO)", StringUtils.startsWith(null, FOO));
48 assertTrue("startsWith(FOOBAR, \"\")", StringUtils.startsWith(FOOBAR, ""));
49
50 assertTrue("startsWith(foobar, foo)", StringUtils.startsWith(foobar, foo));
51 assertTrue("startsWith(FOOBAR, FOO)", StringUtils.startsWith(FOOBAR, FOO));
52 assertFalse("startsWith(foobar, FOO)", StringUtils.startsWith(foobar, FOO));
53 assertFalse("startsWith(FOOBAR, foo)", StringUtils.startsWith(FOOBAR, foo));
54
55 assertFalse("startsWith(foo, foobar)", StringUtils.startsWith(foo, foobar));
56 assertFalse("startsWith(foo, foobar)", StringUtils.startsWith(bar, foobar));
57
58 assertFalse("startsWith(foobar, bar)", StringUtils.startsWith(foobar, bar));
59 assertFalse("startsWith(FOOBAR, BAR)", StringUtils.startsWith(FOOBAR, BAR));
60 assertFalse("startsWith(foobar, BAR)", StringUtils.startsWith(foobar, BAR));
61 assertFalse("startsWith(FOOBAR, bar)", StringUtils.startsWith(FOOBAR, bar));
62 }
63
64 /**
65 * Test StringUtils.testStartsWithIgnoreCase()
66 */
67 public void testStartsWithIgnoreCase() {
68 assertTrue("startsWithIgnoreCase(null, null)", StringUtils.startsWithIgnoreCase(null, (String)null));
69 assertFalse("startsWithIgnoreCase(FOOBAR, null)", StringUtils.startsWithIgnoreCase(FOOBAR, (String)null));
70 assertFalse("startsWithIgnoreCase(null, FOO)", StringUtils.startsWithIgnoreCase(null, FOO));
71 assertTrue("startsWithIgnoreCase(FOOBAR, \"\")", StringUtils.startsWithIgnoreCase(FOOBAR, ""));
72
73 assertTrue("startsWithIgnoreCase(foobar, foo)", StringUtils.startsWithIgnoreCase(foobar, foo));
74 assertTrue("startsWithIgnoreCase(FOOBAR, FOO)", StringUtils.startsWithIgnoreCase(FOOBAR, FOO));
75 assertTrue("startsWithIgnoreCase(foobar, FOO)", StringUtils.startsWithIgnoreCase(foobar, FOO));
76 assertTrue("startsWithIgnoreCase(FOOBAR, foo)", StringUtils.startsWithIgnoreCase(FOOBAR, foo));
77
78 assertFalse("startsWithIgnoreCase(foo, foobar)", StringUtils.startsWithIgnoreCase(foo, foobar));
79 assertFalse("startsWithIgnoreCase(foo, foobar)", StringUtils.startsWithIgnoreCase(bar, foobar));
80
81 assertFalse("startsWithIgnoreCase(foobar, bar)", StringUtils.startsWithIgnoreCase(foobar, bar));
82 assertFalse("startsWithIgnoreCase(FOOBAR, BAR)", StringUtils.startsWithIgnoreCase(FOOBAR, BAR));
83 assertFalse("startsWithIgnoreCase(foobar, BAR)", StringUtils.startsWithIgnoreCase(foobar, BAR));
84 assertFalse("startsWithIgnoreCase(FOOBAR, bar)", StringUtils.startsWithIgnoreCase(FOOBAR, bar));
85 }
86
87 public void testStartsWithAny() {
88 assertFalse(StringUtils.startsWithAny(null, (String[])null));
89 assertFalse(StringUtils.startsWithAny(null, "abc"));
90 assertFalse(StringUtils.startsWithAny("abcxyz", (String[])null));
91 assertFalse(StringUtils.startsWithAny("abcxyz"));
92 assertTrue(StringUtils.startsWithAny("abcxyz", "abc"));
93 assertTrue(StringUtils.startsWithAny("abcxyz", null, "xyz", "abc"));
94 assertFalse(StringUtils.startsWithAny("abcxyz", null, "xyz", "abcd"));
95
96 assertTrue("StringUtils.startsWithAny(abcxyz, StringBuilder(xyz), StringBuffer(abc))", StringUtils.startsWithAny("abcxyz", new StringBuilder("xyz"), new StringBuffer("abc")));
97 assertTrue("StringUtils.startsWithAny( StrBuilder(abcxyz), StringBuilder(xyz), StringBuffer(abc))", StringUtils.startsWithAny( new StrBuilder("abcxyz"), new StringBuilder("xyz"), new StringBuffer("abc")));
98 }
99
100
101 /**
102 * Test StringUtils.endsWith()
103 */
104 public void testEndsWith() {
105 assertTrue("endsWith(null, null)", StringUtils.endsWith(null, (String)null));
106 assertFalse("endsWith(FOOBAR, null)", StringUtils.endsWith(FOOBAR, (String)null));
107 assertFalse("endsWith(null, FOO)", StringUtils.endsWith(null, FOO));
108 assertTrue("endsWith(FOOBAR, \"\")", StringUtils.endsWith(FOOBAR, ""));
109
110 assertFalse("endsWith(foobar, foo)", StringUtils.endsWith(foobar, foo));
111 assertFalse("endsWith(FOOBAR, FOO)", StringUtils.endsWith(FOOBAR, FOO));
112 assertFalse("endsWith(foobar, FOO)", StringUtils.endsWith(foobar, FOO));
113 assertFalse("endsWith(FOOBAR, foo)", StringUtils.endsWith(FOOBAR, foo));
114
115 assertFalse("endsWith(foo, foobar)", StringUtils.endsWith(foo, foobar));
116 assertFalse("endsWith(foo, foobar)", StringUtils.endsWith(bar, foobar));
117
118 assertTrue("endsWith(foobar, bar)", StringUtils.endsWith(foobar, bar));
119 assertTrue("endsWith(FOOBAR, BAR)", StringUtils.endsWith(FOOBAR, BAR));
120 assertFalse("endsWith(foobar, BAR)", StringUtils.endsWith(foobar, BAR));
121 assertFalse("endsWith(FOOBAR, bar)", StringUtils.endsWith(FOOBAR, bar));
122 }
123
124 /**
125 * Test StringUtils.endsWithIgnoreCase()
126 */
127 public void testEndsWithIgnoreCase() {
128 assertTrue("endsWithIgnoreCase(null, null)", StringUtils.endsWithIgnoreCase(null, (String)null));
129 assertFalse("endsWithIgnoreCase(FOOBAR, null)", StringUtils.endsWithIgnoreCase(FOOBAR, (String)null));
130 assertFalse("endsWithIgnoreCase(null, FOO)", StringUtils.endsWithIgnoreCase(null, FOO));
131 assertTrue("endsWithIgnoreCase(FOOBAR, \"\")", StringUtils.endsWithIgnoreCase(FOOBAR, ""));
132
133 assertFalse("endsWithIgnoreCase(foobar, foo)", StringUtils.endsWithIgnoreCase(foobar, foo));
134 assertFalse("endsWithIgnoreCase(FOOBAR, FOO)", StringUtils.endsWithIgnoreCase(FOOBAR, FOO));
135 assertFalse("endsWithIgnoreCase(foobar, FOO)", StringUtils.endsWithIgnoreCase(foobar, FOO));
136 assertFalse("endsWithIgnoreCase(FOOBAR, foo)", StringUtils.endsWithIgnoreCase(FOOBAR, foo));
137
138 assertFalse("endsWithIgnoreCase(foo, foobar)", StringUtils.endsWithIgnoreCase(foo, foobar));
139 assertFalse("endsWithIgnoreCase(foo, foobar)", StringUtils.endsWithIgnoreCase(bar, foobar));
140
141 assertTrue("endsWithIgnoreCase(foobar, bar)", StringUtils.endsWithIgnoreCase(foobar, bar));
142 assertTrue("endsWithIgnoreCase(FOOBAR, BAR)", StringUtils.endsWithIgnoreCase(FOOBAR, BAR));
143 assertTrue("endsWithIgnoreCase(foobar, BAR)", StringUtils.endsWithIgnoreCase(foobar, BAR));
144 assertTrue("endsWithIgnoreCase(FOOBAR, bar)", StringUtils.endsWithIgnoreCase(FOOBAR, bar));
145
146 // javadoc
147 assertTrue(StringUtils.endsWithIgnoreCase("abcdef", "def"));
148 assertTrue(StringUtils.endsWithIgnoreCase("ABCDEF", "def"));
149 assertFalse(StringUtils.endsWithIgnoreCase("ABCDEF", "cde"));
150 }
151
152 public void testEndsWithAny() {
153 assertFalse("StringUtils.endsWithAny(null, null)", StringUtils.endsWithAny(null, (String)null));
154 assertFalse("StringUtils.endsWithAny(null, new String[] {abc})", StringUtils.endsWithAny(null, new String[] {"abc"}));
155 assertFalse("StringUtils.endsWithAny(abcxyz, null)", StringUtils.endsWithAny("abcxyz", (String)null));
156 assertTrue("StringUtils.endsWithAny(abcxyz, new String[] {\"\"})", StringUtils.endsWithAny("abcxyz", new String[] {""}));
157 assertTrue("StringUtils.endsWithAny(abcxyz, new String[] {xyz})", StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}));
158 assertTrue("StringUtils.endsWithAny(abcxyz, new String[] {null, xyz, abc})", StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}));
159 assertFalse("StringUtils.endsWithAny(defg, new String[] {null, xyz, abc})", StringUtils.endsWithAny("defg", new String[] {null, "xyz", "abc"}));
160
161 assertTrue("StringUtils.endsWithAny(abcxyz, StringBuilder(abc), StringBuffer(xyz))", StringUtils.endsWithAny("abcxyz", new StringBuilder("abc"), new StringBuffer("xyz")));
162 assertTrue("StringUtils.endsWithAny( StrBuilder(abcxyz), StringBuilder(abc), StringBuffer(xyz))", StringUtils.endsWithAny( new StrBuilder("abcxyz"), new StringBuilder("abc"), new StringBuffer("xyz")));
163 }
164
165
166 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import junit.framework.TestCase;
19
20 /**
21 * Unit tests {@link org.apache.commons.lang3.StringUtils} - Substring methods
22 *
23 * @version $Id: StringUtilsSubstringTest.java 1089970 2011-04-07 20:05:50Z sebb $
24 */
25 public class StringUtilsSubstringTest extends TestCase {
26 private static final String FOO = "foo";
27 private static final String BAR = "bar";
28 private static final String BAZ = "baz";
29 private static final String FOOBAR = "foobar";
30 private static final String SENTENCE = "foo bar baz";
31
32 public StringUtilsSubstringTest(String name) {
33 super(name);
34 }
35
36 //-----------------------------------------------------------------------
37
38
39 public void testSubstring_StringInt() {
40 assertEquals(null, StringUtils.substring(null, 0));
41 assertEquals("", StringUtils.substring("", 0));
42 assertEquals("", StringUtils.substring("", 2));
43
44 assertEquals("", StringUtils.substring(SENTENCE, 80));
45 assertEquals(BAZ, StringUtils.substring(SENTENCE, 8));
46 assertEquals(BAZ, StringUtils.substring(SENTENCE, -3));
47 assertEquals(SENTENCE, StringUtils.substring(SENTENCE, 0));
48 assertEquals("abc", StringUtils.substring("abc", -4));
49 assertEquals("abc", StringUtils.substring("abc", -3));
50 assertEquals("bc", StringUtils.substring("abc", -2));
51 assertEquals("c", StringUtils.substring("abc", -1));
52 assertEquals("abc", StringUtils.substring("abc", 0));
53 assertEquals("bc", StringUtils.substring("abc", 1));
54 assertEquals("c", StringUtils.substring("abc", 2));
55 assertEquals("", StringUtils.substring("abc", 3));
56 assertEquals("", StringUtils.substring("abc", 4));
57 }
58
59 public void testSubstring_StringIntInt() {
60 assertEquals(null, StringUtils.substring(null, 0, 0));
61 assertEquals(null, StringUtils.substring(null, 1, 2));
62 assertEquals("", StringUtils.substring("", 0, 0));
63 assertEquals("", StringUtils.substring("", 1, 2));
64 assertEquals("", StringUtils.substring("", -2, -1));
65
66 assertEquals("", StringUtils.substring(SENTENCE, 8, 6));
67 assertEquals(FOO, StringUtils.substring(SENTENCE, 0, 3));
68 assertEquals("o", StringUtils.substring(SENTENCE, -9, 3));
69 assertEquals(FOO, StringUtils.substring(SENTENCE, 0, -8));
70 assertEquals("o", StringUtils.substring(SENTENCE, -9, -8));
71 assertEquals(SENTENCE, StringUtils.substring(SENTENCE, 0, 80));
72 assertEquals("", StringUtils.substring(SENTENCE, 2, 2));
73 assertEquals("b",StringUtils.substring("abc", -2, -1));
74 }
75
76 public void testLeft_String() {
77 assertSame(null, StringUtils.left(null, -1));
78 assertSame(null, StringUtils.left(null, 0));
79 assertSame(null, StringUtils.left(null, 2));
80
81 assertEquals("", StringUtils.left("", -1));
82 assertEquals("", StringUtils.left("", 0));
83 assertEquals("", StringUtils.left("", 2));
84
85 assertEquals("", StringUtils.left(FOOBAR, -1));
86 assertEquals("", StringUtils.left(FOOBAR, 0));
87 assertEquals(FOO, StringUtils.left(FOOBAR, 3));
88 assertSame(FOOBAR, StringUtils.left(FOOBAR, 80));
89 }
90
91 public void testRight_String() {
92 assertSame(null, StringUtils.right(null, -1));
93 assertSame(null, StringUtils.right(null, 0));
94 assertSame(null, StringUtils.right(null, 2));
95
96 assertEquals("", StringUtils.right("", -1));
97 assertEquals("", StringUtils.right("", 0));
98 assertEquals("", StringUtils.right("", 2));
99
100 assertEquals("", StringUtils.right(FOOBAR, -1));
101 assertEquals("", StringUtils.right(FOOBAR, 0));
102 assertEquals(BAR, StringUtils.right(FOOBAR, 3));
103 assertSame(FOOBAR, StringUtils.right(FOOBAR, 80));
104 }
105
106 public void testMid_String() {
107 assertSame(null, StringUtils.mid(null, -1, 0));
108 assertSame(null, StringUtils.mid(null, 0, -1));
109 assertSame(null, StringUtils.mid(null, 3, 0));
110 assertSame(null, StringUtils.mid(null, 3, 2));
111
112 assertEquals("", StringUtils.mid("", 0, -1));
113 assertEquals("", StringUtils.mid("", 0, 0));
114 assertEquals("", StringUtils.mid("", 0, 2));
115
116 assertEquals("", StringUtils.mid(FOOBAR, 3, -1));
117 assertEquals("", StringUtils.mid(FOOBAR, 3, 0));
118 assertEquals("b", StringUtils.mid(FOOBAR, 3, 1));
119 assertEquals(FOO, StringUtils.mid(FOOBAR, 0, 3));
120 assertEquals(BAR, StringUtils.mid(FOOBAR, 3, 3));
121 assertEquals(FOOBAR, StringUtils.mid(FOOBAR, 0, 80));
122 assertEquals(BAR, StringUtils.mid(FOOBAR, 3, 80));
123 assertEquals("", StringUtils.mid(FOOBAR, 9, 3));
124 assertEquals(FOO, StringUtils.mid(FOOBAR, -1, 3));
125 }
126
127 //-----------------------------------------------------------------------
128 public void testSubstringBefore_StringString() {
129 assertEquals("foo", StringUtils.substringBefore("fooXXbarXXbaz", "XX"));
130
131 assertEquals(null, StringUtils.substringBefore(null, null));
132 assertEquals(null, StringUtils.substringBefore(null, ""));
133 assertEquals(null, StringUtils.substringBefore(null, "XX"));
134 assertEquals("", StringUtils.substringBefore("", null));
135 assertEquals("", StringUtils.substringBefore("", ""));
136 assertEquals("", StringUtils.substringBefore("", "XX"));
137
138 assertEquals("foo", StringUtils.substringBefore("foo", null));
139 assertEquals("foo", StringUtils.substringBefore("foo", "b"));
140 assertEquals("f", StringUtils.substringBefore("foot", "o"));
141 assertEquals("", StringUtils.substringBefore("abc", "a"));
142 assertEquals("a", StringUtils.substringBefore("abcba", "b"));
143 assertEquals("ab", StringUtils.substringBefore("abc", "c"));
144 assertEquals("", StringUtils.substringBefore("abc", ""));
145 }
146
147 public void testSubstringAfter_StringString() {
148 assertEquals("barXXbaz", StringUtils.substringAfter("fooXXbarXXbaz", "XX"));
149
150 assertEquals(null, StringUtils.substringAfter(null, null));
151 assertEquals(null, StringUtils.substringAfter(null, ""));
152 assertEquals(null, StringUtils.substringAfter(null, "XX"));
153 assertEquals("", StringUtils.substringAfter("", null));
154 assertEquals("", StringUtils.substringAfter("", ""));
155 assertEquals("", StringUtils.substringAfter("", "XX"));
156
157 assertEquals("", StringUtils.substringAfter("foo", null));
158 assertEquals("ot", StringUtils.substringAfter("foot", "o"));
159 assertEquals("bc", StringUtils.substringAfter("abc", "a"));
160 assertEquals("cba", StringUtils.substringAfter("abcba", "b"));
161 assertEquals("", StringUtils.substringAfter("abc", "c"));
162 assertEquals("abc", StringUtils.substringAfter("abc", ""));
163 assertEquals("", StringUtils.substringAfter("abc", "d"));
164 }
165
166 public void testSubstringBeforeLast_StringString() {
167 assertEquals("fooXXbar", StringUtils.substringBeforeLast("fooXXbarXXbaz", "XX"));
168
169 assertEquals(null, StringUtils.substringBeforeLast(null, null));
170 assertEquals(null, StringUtils.substringBeforeLast(null, ""));
171 assertEquals(null, StringUtils.substringBeforeLast(null, "XX"));
172 assertEquals("", StringUtils.substringBeforeLast("", null));
173 assertEquals("", StringUtils.substringBeforeLast("", ""));
174 assertEquals("", StringUtils.substringBeforeLast("", "XX"));
175
176 assertEquals("foo", StringUtils.substringBeforeLast("foo", null));
177 assertEquals("foo", StringUtils.substringBeforeLast("foo", "b"));
178 assertEquals("fo", StringUtils.substringBeforeLast("foo", "o"));
179 assertEquals("abc\r\n", StringUtils.substringBeforeLast("abc\r\n", "d"));
180 assertEquals("abc", StringUtils.substringBeforeLast("abcdabc", "d"));
181 assertEquals("abcdabc", StringUtils.substringBeforeLast("abcdabcd", "d"));
182 assertEquals("a", StringUtils.substringBeforeLast("abc", "b"));
183 assertEquals("abc ", StringUtils.substringBeforeLast("abc \n", "\n"));
184 assertEquals("a", StringUtils.substringBeforeLast("a", null));
185 assertEquals("a", StringUtils.substringBeforeLast("a", ""));
186 assertEquals("", StringUtils.substringBeforeLast("a", "a"));
187 }
188
189 public void testSubstringAfterLast_StringString() {
190 assertEquals("baz", StringUtils.substringAfterLast("fooXXbarXXbaz", "XX"));
191
192 assertEquals(null, StringUtils.substringAfterLast(null, null));
193 assertEquals(null, StringUtils.substringAfterLast(null, ""));
194 assertEquals(null, StringUtils.substringAfterLast(null, "XX"));
195 assertEquals("", StringUtils.substringAfterLast("", null));
196 assertEquals("", StringUtils.substringAfterLast("", ""));
197 assertEquals("", StringUtils.substringAfterLast("", "a"));
198
199 assertEquals("", StringUtils.substringAfterLast("foo", null));
200 assertEquals("", StringUtils.substringAfterLast("foo", "b"));
201 assertEquals("t", StringUtils.substringAfterLast("foot", "o"));
202 assertEquals("bc", StringUtils.substringAfterLast("abc", "a"));
203 assertEquals("a", StringUtils.substringAfterLast("abcba", "b"));
204 assertEquals("", StringUtils.substringAfterLast("abc", "c"));
205 assertEquals("", StringUtils.substringAfterLast("", "d"));
206 assertEquals("", StringUtils.substringAfterLast("abc", ""));
207 }
208
209 //-----------------------------------------------------------------------
210 public void testSubstringBetween_StringString() {
211 assertEquals(null, StringUtils.substringBetween(null, "tag"));
212 assertEquals("", StringUtils.substringBetween("", ""));
213 assertEquals(null, StringUtils.substringBetween("", "abc"));
214 assertEquals("", StringUtils.substringBetween(" ", " "));
215 assertEquals(null, StringUtils.substringBetween("abc", null));
216 assertEquals("", StringUtils.substringBetween("abc", ""));
217 assertEquals(null, StringUtils.substringBetween("abc", "a"));
218 assertEquals("bc", StringUtils.substringBetween("abca", "a"));
219 assertEquals("bc", StringUtils.substringBetween("abcabca", "a"));
220 assertEquals("bar", StringUtils.substringBetween("\nbar\n", "\n"));
221 }
222
223 public void testSubstringBetween_StringStringString() {
224 assertEquals(null, StringUtils.substringBetween(null, "", ""));
225 assertEquals(null, StringUtils.substringBetween("", null, ""));
226 assertEquals(null, StringUtils.substringBetween("", "", null));
227 assertEquals("", StringUtils.substringBetween("", "", ""));
228 assertEquals("", StringUtils.substringBetween("foo", "", ""));
229 assertEquals(null, StringUtils.substringBetween("foo", "", "]"));
230 assertEquals(null, StringUtils.substringBetween("foo", "[", "]"));
231 assertEquals("", StringUtils.substringBetween(" ", " ", " "));
232 assertEquals("bar", StringUtils.substringBetween("<foo>bar</foo>", "<foo>", "</foo>") );
233 }
234
235 /**
236 * Tests the substringsBetween method that returns an String Array of substrings.
237 */
238 public void testSubstringsBetween_StringStringString() {
239
240 String[] results = StringUtils.substringsBetween("[one], [two], [three]", "[", "]");
241 assertEquals(3, results.length);
242 assertEquals("one", results[0]);
243 assertEquals("two", results[1]);
244 assertEquals("three", results[2]);
245
246 results = StringUtils.substringsBetween("[one], [two], three", "[", "]");
247 assertEquals(2, results.length);
248 assertEquals("one", results[0]);
249 assertEquals("two", results[1]);
250
251 results = StringUtils.substringsBetween("[one], [two], three]", "[", "]");
252 assertEquals(2, results.length);
253 assertEquals("one", results[0]);
254 assertEquals("two", results[1]);
255
256 results = StringUtils.substringsBetween("[one], two], three]", "[", "]");
257 assertEquals(1, results.length);
258 assertEquals("one", results[0]);
259
260 results = StringUtils.substringsBetween("one], two], [three]", "[", "]");
261 assertEquals(1, results.length);
262 assertEquals("three", results[0]);
263
264 // 'ab hello ba' will match, but 'ab non ba' won't
265 // this is because the 'a' is shared between the two and can't be matched twice
266 results = StringUtils.substringsBetween("aabhellobabnonba", "ab", "ba");
267 assertEquals(1, results.length);
268 assertEquals("hello", results[0]);
269
270 results = StringUtils.substringsBetween("one, two, three", "[", "]");
271 assertNull(results);
272
273 results = StringUtils.substringsBetween("[one, two, three", "[", "]");
274 assertNull(results);
275
276 results = StringUtils.substringsBetween("one, two, three]", "[", "]");
277 assertNull(results);
278
279 results = StringUtils.substringsBetween("[one], [two], [three]", "[", null);
280 assertNull(results);
281
282 results = StringUtils.substringsBetween("[one], [two], [three]", null, "]");
283 assertNull(results);
284
285 results = StringUtils.substringsBetween("[one], [two], [three]", "", "");
286 assertNull(results);
287
288 results = StringUtils.substringsBetween(null, "[", "]");
289 assertNull(results);
290
291 results = StringUtils.substringsBetween("", "[", "]");
292 assertEquals(0, results.length);
293 }
294
295 //-----------------------------------------------------------------------
296 public void testCountMatches_String() {
297 assertEquals(0, StringUtils.countMatches(null, null));
298 assertEquals(0, StringUtils.countMatches("blah", null));
299 assertEquals(0, StringUtils.countMatches(null, "DD"));
300
301 assertEquals(0, StringUtils.countMatches("x", ""));
302 assertEquals(0, StringUtils.countMatches("", ""));
303
304 assertEquals(3,
305 StringUtils.countMatches("one long someone sentence of one", "one"));
306 assertEquals(0,
307 StringUtils.countMatches("one long someone sentence of one", "two"));
308 assertEquals(4,
309 StringUtils.countMatches("oooooooooooo", "ooo"));
310 }
311
312 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.Method;
20 import java.lang.reflect.Modifier;
21 import java.nio.CharBuffer;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.Iterator;
25 import java.util.Locale;
26
27 import junit.framework.TestCase;
28
29 import org.apache.commons.lang3.text.WordUtils;
30
31 /**
32 * Unit tests {@link org.apache.commons.lang3.StringUtils}.
33 *
34 * @version $Id: StringUtilsTest.java 1144929 2011-07-10 18:26:16Z ggregory $
35 */
36 public class StringUtilsTest extends TestCase {
37
38 static final String WHITESPACE;
39 static final String NON_WHITESPACE;
40 static final String TRIMMABLE;
41 static final String NON_TRIMMABLE;
42 static {
43 String ws = "";
44 String nws = "";
45 String tr = "";
46 String ntr = "";
47 for (int i = 0; i < Character.MAX_VALUE; i++) {
48 if (Character.isWhitespace((char) i)) {
49 ws += String.valueOf((char) i);
50 if (i > 32) {
51 ntr += String.valueOf((char) i);
52 }
53 } else if (i < 40) {
54 nws += String.valueOf((char) i);
55 }
56 }
57 for (int i = 0; i <= 32; i++) {
58 tr += String.valueOf((char) i);
59 }
60 WHITESPACE = ws;
61 NON_WHITESPACE = nws;
62 TRIMMABLE = tr;
63 NON_TRIMMABLE = ntr;
64 }
65
66 private static final String[] ARRAY_LIST = { "foo", "bar", "baz" };
67 private static final String[] EMPTY_ARRAY_LIST = {};
68 private static final String[] NULL_ARRAY_LIST = {null};
69 private static final Object[] NULL_TO_STRING_LIST = {
70 new Object(){
71 @Override
72 public String toString() {
73 return null;
74 }
75 }
76 };
77 private static final String[] MIXED_ARRAY_LIST = {null, "", "foo"};
78 private static final Object[] MIXED_TYPE_LIST = {"foo", Long.valueOf(2L)};
79
80 private static final String SEPARATOR = ",";
81 private static final char SEPARATOR_CHAR = ';';
82
83 private static final String TEXT_LIST = "foo,bar,baz";
84 private static final String TEXT_LIST_CHAR = "foo;bar;baz";
85 private static final String TEXT_LIST_NOSEP = "foobarbaz";
86
87 private static final String FOO_UNCAP = "foo";
88 private static final String FOO_CAP = "Foo";
89
90 private static final String SENTENCE_UNCAP = "foo bar baz";
91 private static final String SENTENCE_CAP = "Foo Bar Baz";
92
93 public StringUtilsTest(String name) {
94 super(name);
95 }
96
97 //-----------------------------------------------------------------------
98 public void testConstructor() {
99 assertNotNull(new StringUtils());
100 Constructor<?>[] cons = StringUtils.class.getDeclaredConstructors();
101 assertEquals(1, cons.length);
102 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
103 assertEquals(true, Modifier.isPublic(StringUtils.class.getModifiers()));
104 assertEquals(false, Modifier.isFinal(StringUtils.class.getModifiers()));
105 }
106
107 //-----------------------------------------------------------------------
108 public void testCaseFunctions() {
109 assertEquals(null, StringUtils.upperCase(null));
110 assertEquals(null, StringUtils.upperCase(null, Locale.ENGLISH));
111 assertEquals(null, StringUtils.lowerCase(null));
112 assertEquals(null, StringUtils.lowerCase(null, Locale.ENGLISH));
113 assertEquals(null, StringUtils.capitalize(null));
114 assertEquals(null, StringUtils.uncapitalize(null));
115
116 assertEquals("capitalize(empty-string) failed",
117 "", StringUtils.capitalize("") );
118 assertEquals("capitalize(single-char-string) failed",
119 "X", StringUtils.capitalize("x") );
120
121 assertEquals("uncapitalize(String) failed",
122 FOO_UNCAP, StringUtils.uncapitalize(FOO_CAP) );
123 assertEquals("uncapitalize(empty-string) failed",
124 "", StringUtils.uncapitalize("") );
125 assertEquals("uncapitalize(single-char-string) failed",
126 "x", StringUtils.uncapitalize("X") );
127
128 // reflection type of tests: Sentences.
129 assertEquals("uncapitalize(capitalize(String)) failed",
130 SENTENCE_UNCAP, StringUtils.uncapitalize(StringUtils.capitalize(SENTENCE_UNCAP)) );
131 assertEquals("capitalize(uncapitalize(String)) failed",
132 SENTENCE_CAP, StringUtils.capitalize(StringUtils.uncapitalize(SENTENCE_CAP)) );
133
134 // reflection type of tests: One word.
135 assertEquals("uncapitalize(capitalize(String)) failed",
136 FOO_UNCAP, StringUtils.uncapitalize(StringUtils.capitalize(FOO_UNCAP)) );
137 assertEquals("capitalize(uncapitalize(String)) failed",
138 FOO_CAP, StringUtils.capitalize(StringUtils.uncapitalize(FOO_CAP)) );
139
140 assertEquals("upperCase(String) failed",
141 "FOO TEST THING", StringUtils.upperCase("fOo test THING") );
142 assertEquals("upperCase(empty-string) failed",
143 "", StringUtils.upperCase("") );
144 assertEquals("lowerCase(String) failed",
145 "foo test thing", StringUtils.lowerCase("fOo test THING") );
146 assertEquals("lowerCase(empty-string) failed",
147 "", StringUtils.lowerCase("") );
148
149 assertEquals("upperCase(String, Locale) failed",
150 "FOO TEST THING", StringUtils.upperCase("fOo test THING", Locale.ENGLISH) );
151 assertEquals("upperCase(empty-string, Locale) failed",
152 "", StringUtils.upperCase("", Locale.ENGLISH) );
153 assertEquals("lowerCase(String, Locale) failed",
154 "foo test thing", StringUtils.lowerCase("fOo test THING", Locale.ENGLISH) );
155 assertEquals("lowerCase(empty-string, Locale) failed",
156 "", StringUtils.lowerCase("", Locale.ENGLISH) );
157 }
158
159 public void testSwapCase_String() {
160 assertEquals(null, StringUtils.swapCase(null));
161 assertEquals("", StringUtils.swapCase(""));
162 assertEquals(" ", StringUtils.swapCase(" "));
163
164 assertEquals("i", WordUtils.swapCase("I") );
165 assertEquals("I", WordUtils.swapCase("i") );
166 assertEquals("I AM HERE 123", StringUtils.swapCase("i am here 123") );
167 assertEquals("i aM hERE 123", StringUtils.swapCase("I Am Here 123") );
168 assertEquals("I AM here 123", StringUtils.swapCase("i am HERE 123") );
169 assertEquals("i am here 123", StringUtils.swapCase("I AM HERE 123") );
170
171 String test = "This String contains a TitleCase character: \u01C8";
172 String expect = "tHIS sTRING CONTAINS A tITLEcASE CHARACTER: \u01C9";
173 assertEquals(expect, WordUtils.swapCase(test));
174 }
175
176 //-----------------------------------------------------------------------
177 public void testJoin_Objects() {
178 assertEquals("abc", StringUtils.join("a", "b", "c"));
179 assertEquals("a", StringUtils.join(null, "", "a"));
180 assertEquals(null, StringUtils.join((Object[])null));
181 }
182
183 public void testJoin_Objectarray() {
184 // assertEquals(null, StringUtils.join(null)); // generates warning
185 assertEquals(null, StringUtils.join((Object[]) null)); // equivalent explicit cast
186 // test additional varargs calls
187 assertEquals("", StringUtils.join()); // empty array
188 assertEquals("", StringUtils.join((Object) null)); // => new Object[]{null}
189
190 assertEquals("", StringUtils.join(EMPTY_ARRAY_LIST));
191 assertEquals("", StringUtils.join(NULL_ARRAY_LIST));
192 assertEquals("null", StringUtils.join(NULL_TO_STRING_LIST));
193 assertEquals("abc", StringUtils.join(new String[] {"a", "b", "c"}));
194 assertEquals("a", StringUtils.join(new String[] {null, "a", ""}));
195 assertEquals("foo", StringUtils.join(MIXED_ARRAY_LIST));
196 assertEquals("foo2", StringUtils.join(MIXED_TYPE_LIST));
197 }
198
199 public void testJoin_ArrayChar() {
200 assertEquals(null, StringUtils.join((Object[]) null, ','));
201 assertEquals(TEXT_LIST_CHAR, StringUtils.join(ARRAY_LIST, SEPARATOR_CHAR));
202 assertEquals("", StringUtils.join(EMPTY_ARRAY_LIST, SEPARATOR_CHAR));
203 assertEquals(";;foo", StringUtils.join(MIXED_ARRAY_LIST, SEPARATOR_CHAR));
204 assertEquals("foo;2", StringUtils.join(MIXED_TYPE_LIST, SEPARATOR_CHAR));
205
206 assertEquals("/", StringUtils.join(MIXED_ARRAY_LIST, '/', 0, MIXED_ARRAY_LIST.length-1));
207 assertEquals("foo", StringUtils.join(MIXED_TYPE_LIST, '/', 0, 1));
208 assertEquals("null", StringUtils.join(NULL_TO_STRING_LIST,'/', 0, 1));
209 assertEquals("foo/2", StringUtils.join(MIXED_TYPE_LIST, '/', 0, 2));
210 assertEquals("2", StringUtils.join(MIXED_TYPE_LIST, '/', 1, 2));
211 assertEquals("", StringUtils.join(MIXED_TYPE_LIST, '/', 2, 1));
212 }
213
214 public void testJoin_ArrayString() {
215 assertEquals(null, StringUtils.join((Object[]) null, null));
216 assertEquals(TEXT_LIST_NOSEP, StringUtils.join(ARRAY_LIST, null));
217 assertEquals(TEXT_LIST_NOSEP, StringUtils.join(ARRAY_LIST, ""));
218
219 assertEquals("", StringUtils.join(NULL_ARRAY_LIST, null));
220
221 assertEquals("", StringUtils.join(EMPTY_ARRAY_LIST, null));
222 assertEquals("", StringUtils.join(EMPTY_ARRAY_LIST, ""));
223 assertEquals("", StringUtils.join(EMPTY_ARRAY_LIST, SEPARATOR));
224
225 assertEquals(TEXT_LIST, StringUtils.join(ARRAY_LIST, SEPARATOR));
226 assertEquals(",,foo", StringUtils.join(MIXED_ARRAY_LIST, SEPARATOR));
227 assertEquals("foo,2", StringUtils.join(MIXED_TYPE_LIST, SEPARATOR));
228
229 assertEquals("/", StringUtils.join(MIXED_ARRAY_LIST, "/", 0, MIXED_ARRAY_LIST.length-1));
230 assertEquals("", StringUtils.join(MIXED_ARRAY_LIST, "", 0, MIXED_ARRAY_LIST.length-1));
231 assertEquals("foo", StringUtils.join(MIXED_TYPE_LIST, "/", 0, 1));
232 assertEquals("foo/2", StringUtils.join(MIXED_TYPE_LIST, "/", 0, 2));
233 assertEquals("2", StringUtils.join(MIXED_TYPE_LIST, "/", 1, 2));
234 assertEquals("", StringUtils.join(MIXED_TYPE_LIST, "/", 2, 1));
235 }
236
237 public void testJoin_IteratorChar() {
238 assertEquals(null, StringUtils.join((Iterator<?>) null, ','));
239 assertEquals(TEXT_LIST_CHAR, StringUtils.join(Arrays.asList(ARRAY_LIST).iterator(), SEPARATOR_CHAR));
240 assertEquals("", StringUtils.join(Arrays.asList(NULL_ARRAY_LIST).iterator(), SEPARATOR_CHAR));
241 assertEquals("", StringUtils.join(Arrays.asList(EMPTY_ARRAY_LIST).iterator(), SEPARATOR_CHAR));
242 assertEquals("foo", StringUtils.join(Collections.singleton("foo").iterator(), 'x'));
243 }
244
245 public void testJoin_IteratorString() {
246 assertEquals(null, StringUtils.join((Iterator<?>) null, null));
247 assertEquals(TEXT_LIST_NOSEP, StringUtils.join(Arrays.asList(ARRAY_LIST).iterator(), null));
248 assertEquals(TEXT_LIST_NOSEP, StringUtils.join(Arrays.asList(ARRAY_LIST).iterator(), ""));
249 assertEquals("foo", StringUtils.join(Collections.singleton("foo").iterator(), "x"));
250 assertEquals("foo", StringUtils.join(Collections.singleton("foo").iterator(), null));
251
252 assertEquals("", StringUtils.join(Arrays.asList(NULL_ARRAY_LIST).iterator(), null));
253
254 assertEquals("", StringUtils.join(Arrays.asList(EMPTY_ARRAY_LIST).iterator(), null));
255 assertEquals("", StringUtils.join(Arrays.asList(EMPTY_ARRAY_LIST).iterator(), ""));
256 assertEquals("", StringUtils.join(Arrays.asList(EMPTY_ARRAY_LIST).iterator(), SEPARATOR));
257
258 assertEquals(TEXT_LIST, StringUtils.join(Arrays.asList(ARRAY_LIST).iterator(), SEPARATOR));
259 }
260
261 public void testJoin_IterableChar() {
262 assertEquals(null, StringUtils.join((Iterable<?>) null, ','));
263 assertEquals(TEXT_LIST_CHAR, StringUtils.join(Arrays.asList(ARRAY_LIST), SEPARATOR_CHAR));
264 assertEquals("", StringUtils.join(Arrays.asList(NULL_ARRAY_LIST), SEPARATOR_CHAR));
265 assertEquals("", StringUtils.join(Arrays.asList(EMPTY_ARRAY_LIST), SEPARATOR_CHAR));
266 assertEquals("foo", StringUtils.join(Collections.singleton("foo"), 'x'));
267 }
268
269 public void testJoin_IterableString() {
270 assertEquals(null, StringUtils.join((Iterable<?>) null, null));
271 assertEquals(TEXT_LIST_NOSEP, StringUtils.join(Arrays.asList(ARRAY_LIST), null));
272 assertEquals(TEXT_LIST_NOSEP, StringUtils.join(Arrays.asList(ARRAY_LIST), ""));
273 assertEquals("foo", StringUtils.join(Collections.singleton("foo"), "x"));
274 assertEquals("foo", StringUtils.join(Collections.singleton("foo"), null));
275
276 assertEquals("", StringUtils.join(Arrays.asList(NULL_ARRAY_LIST), null));
277
278 assertEquals("", StringUtils.join(Arrays.asList(EMPTY_ARRAY_LIST), null));
279 assertEquals("", StringUtils.join(Arrays.asList(EMPTY_ARRAY_LIST), ""));
280 assertEquals("", StringUtils.join(Arrays.asList(EMPTY_ARRAY_LIST), SEPARATOR));
281
282 assertEquals(TEXT_LIST, StringUtils.join(Arrays.asList(ARRAY_LIST), SEPARATOR));
283 }
284
285 public void testSplit_String() {
286 assertEquals(null, StringUtils.split(null));
287 assertEquals(0, StringUtils.split("").length);
288
289 String str = "a b .c";
290 String[] res = StringUtils.split(str);
291 assertEquals(3, res.length);
292 assertEquals("a", res[0]);
293 assertEquals("b", res[1]);
294 assertEquals(".c", res[2]);
295
296 str = " a ";
297 res = StringUtils.split(str);
298 assertEquals(1, res.length);
299 assertEquals("a", res[0]);
300
301 str = "a" + WHITESPACE + "b" + NON_WHITESPACE + "c";
302 res = StringUtils.split(str);
303 assertEquals(2, res.length);
304 assertEquals("a", res[0]);
305 assertEquals("b" + NON_WHITESPACE + "c", res[1]);
306 }
307
308 public void testSplit_StringChar() {
309 assertEquals(null, StringUtils.split(null, '.'));
310 assertEquals(0, StringUtils.split("", '.').length);
311
312 String str = "a.b.. c";
313 String[] res = StringUtils.split(str, '.');
314 assertEquals(3, res.length);
315 assertEquals("a", res[0]);
316 assertEquals("b", res[1]);
317 assertEquals(" c", res[2]);
318
319 str = ".a.";
320 res = StringUtils.split(str, '.');
321 assertEquals(1, res.length);
322 assertEquals("a", res[0]);
323
324 str = "a b c";
325 res = StringUtils.split(str,' ');
326 assertEquals(3, res.length);
327 assertEquals("a", res[0]);
328 assertEquals("b", res[1]);
329 assertEquals("c", res[2]);
330 }
331
332 public void testSplit_StringString_StringStringInt() {
333 assertEquals(null, StringUtils.split(null, "."));
334 assertEquals(null, StringUtils.split(null, ".", 3));
335
336 assertEquals(0, StringUtils.split("", ".").length);
337 assertEquals(0, StringUtils.split("", ".", 3).length);
338
339 innerTestSplit('.', ".", ' ');
340 innerTestSplit('.', ".", ',');
341 innerTestSplit('.', ".,", 'x');
342 for (int i = 0; i < WHITESPACE.length(); i++) {
343 for (int j = 0; j < NON_WHITESPACE.length(); j++) {
344 innerTestSplit(WHITESPACE.charAt(i), null, NON_WHITESPACE.charAt(j));
345 innerTestSplit(WHITESPACE.charAt(i), String.valueOf(WHITESPACE.charAt(i)), NON_WHITESPACE.charAt(j));
346 }
347 }
348
349 String[] results;
350 String[] expectedResults = {"ab", "de fg"};
351 results = StringUtils.split("ab de fg", null, 2);
352 assertEquals(expectedResults.length, results.length);
353 for (int i = 0; i < expectedResults.length; i++) {
354 assertEquals(expectedResults[i], results[i]);
355 }
356
357 String[] expectedResults2 = {"ab", "cd:ef"};
358 results = StringUtils.split("ab:cd:ef",":", 2);
359 assertEquals(expectedResults2.length, results.length);
360 for (int i = 0; i < expectedResults2.length; i++) {
361 assertEquals(expectedResults2[i], results[i]);
362 }
363 }
364
365 private void innerTestSplit(char separator, String sepStr, char noMatch) {
366 String msg = "Failed on separator hex(" + Integer.toHexString(separator) +
367 "), noMatch hex(" + Integer.toHexString(noMatch) + "), sepStr(" + sepStr + ")";
368
369 final String str = "a" + separator + "b" + separator + separator + noMatch + "c";
370 String[] res;
371 // (str, sepStr)
372 res = StringUtils.split(str, sepStr);
373 assertEquals(msg, 3, res.length);
374 assertEquals(msg, "a", res[0]);
375 assertEquals(msg, "b", res[1]);
376 assertEquals(msg, noMatch + "c", res[2]);
377
378 final String str2 = separator + "a" + separator;
379 res = StringUtils.split(str2, sepStr);
380 assertEquals(msg, 1, res.length);
381 assertEquals(msg, "a", res[0]);
382
383 res = StringUtils.split(str, sepStr, -1);
384 assertEquals(msg, 3, res.length);
385 assertEquals(msg, "a", res[0]);
386 assertEquals(msg, "b", res[1]);
387 assertEquals(msg, noMatch + "c", res[2]);
388
389 res = StringUtils.split(str, sepStr, 0);
390 assertEquals(msg, 3, res.length);
391 assertEquals(msg, "a", res[0]);
392 assertEquals(msg, "b", res[1]);
393 assertEquals(msg, noMatch + "c", res[2]);
394
395 res = StringUtils.split(str, sepStr, 1);
396 assertEquals(msg, 1, res.length);
397 assertEquals(msg, str, res[0]);
398
399 res = StringUtils.split(str, sepStr, 2);
400 assertEquals(msg, 2, res.length);
401 assertEquals(msg, "a", res[0]);
402 assertEquals(msg, str.substring(2), res[1]);
403 }
404
405 public void testSplitByWholeString_StringStringBoolean() {
406 assertEquals( null, StringUtils.splitByWholeSeparator( null, "." ) ) ;
407
408 assertEquals( 0, StringUtils.splitByWholeSeparator( "", "." ).length ) ;
409
410 String stringToSplitOnNulls = "ab de fg" ;
411 String[] splitOnNullExpectedResults = { "ab", "de", "fg" } ;
412
413 String[] splitOnNullResults = StringUtils.splitByWholeSeparator( stringToSplitOnNulls, null ) ;
414 assertEquals( splitOnNullExpectedResults.length, splitOnNullResults.length ) ;
415 for ( int i = 0 ; i < splitOnNullExpectedResults.length ; i+= 1 ) {
416 assertEquals( splitOnNullExpectedResults[i], splitOnNullResults[i] ) ;
417 }
418
419 String stringToSplitOnCharactersAndString = "abstemiouslyaeiouyabstemiously" ;
420
421 String[] splitOnStringExpectedResults = { "abstemiously", "abstemiously" } ;
422 String[] splitOnStringResults = StringUtils.splitByWholeSeparator( stringToSplitOnCharactersAndString, "aeiouy" ) ;
423 assertEquals( splitOnStringExpectedResults.length, splitOnStringResults.length ) ;
424 for ( int i = 0 ; i < splitOnStringExpectedResults.length ; i+= 1 ) {
425 assertEquals( splitOnStringExpectedResults[i], splitOnStringResults[i] ) ;
426 }
427
428 String[] splitWithMultipleSeparatorExpectedResults = {"ab", "cd", "ef"};
429 String[] splitWithMultipleSeparator = StringUtils.splitByWholeSeparator("ab:cd::ef", ":");
430 assertEquals( splitWithMultipleSeparatorExpectedResults.length, splitWithMultipleSeparator.length );
431 for( int i = 0; i < splitWithMultipleSeparatorExpectedResults.length ; i++ ) {
432 assertEquals( splitWithMultipleSeparatorExpectedResults[i], splitWithMultipleSeparator[i] ) ;
433 }
434 }
435
436 public void testSplitByWholeString_StringStringBooleanInt() {
437 assertEquals( null, StringUtils.splitByWholeSeparator( null, ".", 3 ) ) ;
438
439 assertEquals( 0, StringUtils.splitByWholeSeparator( "", ".", 3 ).length ) ;
440
441 String stringToSplitOnNulls = "ab de fg" ;
442 String[] splitOnNullExpectedResults = { "ab", "de fg" } ;
443 //String[] splitOnNullExpectedResults = { "ab", "de" } ;
444
445 String[] splitOnNullResults = StringUtils.splitByWholeSeparator( stringToSplitOnNulls, null, 2 ) ;
446 assertEquals( splitOnNullExpectedResults.length, splitOnNullResults.length ) ;
447 for ( int i = 0 ; i < splitOnNullExpectedResults.length ; i+= 1 ) {
448 assertEquals( splitOnNullExpectedResults[i], splitOnNullResults[i] ) ;
449 }
450
451 String stringToSplitOnCharactersAndString = "abstemiouslyaeiouyabstemiouslyaeiouyabstemiously" ;
452
453 String[] splitOnStringExpectedResults = { "abstemiously", "abstemiouslyaeiouyabstemiously" } ;
454 //String[] splitOnStringExpectedResults = { "abstemiously", "abstemiously" } ;
455 String[] splitOnStringResults = StringUtils.splitByWholeSeparator( stringToSplitOnCharactersAndString, "aeiouy", 2 ) ;
456 assertEquals( splitOnStringExpectedResults.length, splitOnStringResults.length ) ;
457 for ( int i = 0 ; i < splitOnStringExpectedResults.length ; i++ ) {
458 assertEquals( splitOnStringExpectedResults[i], splitOnStringResults[i] ) ;
459 }
460 }
461
462 public void testSplitByWholeSeparatorPreserveAllTokens_StringStringInt() {
463 assertEquals( null, StringUtils.splitByWholeSeparatorPreserveAllTokens( null, ".", -1 ) ) ;
464
465 assertEquals( 0, StringUtils.splitByWholeSeparatorPreserveAllTokens( "", ".", -1 ).length ) ;
466
467 // test whitespace
468 String input = "ab de fg" ;
469 String[] expected = new String[] { "ab", "", "", "de", "fg" } ;
470
471 String[] actual = StringUtils.splitByWholeSeparatorPreserveAllTokens( input, null, -1 ) ;
472 assertEquals( expected.length, actual.length ) ;
473 for ( int i = 0 ; i < actual.length ; i+= 1 ) {
474 assertEquals( expected[i], actual[i] );
475 }
476
477 // test delimiter singlechar
478 input = "1::2:::3::::4";
479 expected = new String[] { "1", "", "2", "", "", "3", "", "", "", "4" };
480
481 actual = StringUtils.splitByWholeSeparatorPreserveAllTokens( input, ":", -1 ) ;
482 assertEquals( expected.length, actual.length ) ;
483 for ( int i = 0 ; i < actual.length ; i+= 1 ) {
484 assertEquals( expected[i], actual[i] );
485 }
486
487 // test delimiter multichar
488 input = "1::2:::3::::4";
489 expected = new String[] { "1", "2", ":3", "", "4" };
490
491 actual = StringUtils.splitByWholeSeparatorPreserveAllTokens( input, "::", -1 ) ;
492 assertEquals( expected.length, actual.length ) ;
493 for ( int i = 0 ; i < actual.length ; i+= 1 ) {
494 assertEquals( expected[i], actual[i] );
495 }
496
497 // test delimiter char with max
498 input = "1::2::3:4";
499 expected = new String[] { "1", "", "2", ":3:4" };
500
501 actual = StringUtils.splitByWholeSeparatorPreserveAllTokens( input, ":", 4 ) ;
502 assertEquals( expected.length, actual.length ) ;
503 for ( int i = 0 ; i < actual.length ; i+= 1 ) {
504 assertEquals( expected[i], actual[i] );
505 }
506 }
507
508 public void testSplitPreserveAllTokens_String() {
509 assertEquals(null, StringUtils.splitPreserveAllTokens(null));
510 assertEquals(0, StringUtils.splitPreserveAllTokens("").length);
511
512 String str = "abc def";
513 String[] res = StringUtils.splitPreserveAllTokens(str);
514 assertEquals(2, res.length);
515 assertEquals("abc", res[0]);
516 assertEquals("def", res[1]);
517
518 str = "abc def";
519 res = StringUtils.splitPreserveAllTokens(str);
520 assertEquals(3, res.length);
521 assertEquals("abc", res[0]);
522 assertEquals("", res[1]);
523 assertEquals("def", res[2]);
524
525 str = " abc ";
526 res = StringUtils.splitPreserveAllTokens(str);
527 assertEquals(3, res.length);
528 assertEquals("", res[0]);
529 assertEquals("abc", res[1]);
530 assertEquals("", res[2]);
531
532 str = "a b .c";
533 res = StringUtils.splitPreserveAllTokens(str);
534 assertEquals(3, res.length);
535 assertEquals("a", res[0]);
536 assertEquals("b", res[1]);
537 assertEquals(".c", res[2]);
538
539 str = " a b .c";
540 res = StringUtils.splitPreserveAllTokens(str);
541 assertEquals(4, res.length);
542 assertEquals("", res[0]);
543 assertEquals("a", res[1]);
544 assertEquals("b", res[2]);
545 assertEquals(".c", res[3]);
546
547 str = "a b .c";
548 res = StringUtils.splitPreserveAllTokens(str);
549 assertEquals(5, res.length);
550 assertEquals("a", res[0]);
551 assertEquals("", res[1]);
552 assertEquals("b", res[2]);
553 assertEquals("", res[3]);
554 assertEquals(".c", res[4]);
555
556 str = " a ";
557 res = StringUtils.splitPreserveAllTokens(str);
558 assertEquals(4, res.length);
559 assertEquals("", res[0]);
560 assertEquals("a", res[1]);
561 assertEquals("", res[2]);
562 assertEquals("", res[3]);
563
564 str = " a b";
565 res = StringUtils.splitPreserveAllTokens(str);
566 assertEquals(4, res.length);
567 assertEquals("", res[0]);
568 assertEquals("a", res[1]);
569 assertEquals("", res[2]);
570 assertEquals("b", res[3]);
571
572 str = "a" + WHITESPACE + "b" + NON_WHITESPACE + "c";
573 res = StringUtils.splitPreserveAllTokens(str);
574 assertEquals(WHITESPACE.length() + 1, res.length);
575 assertEquals("a", res[0]);
576 for(int i = 1; i < WHITESPACE.length()-1; i++)
577 {
578 assertEquals("", res[i]);
579 }
580 assertEquals("b" + NON_WHITESPACE + "c", res[WHITESPACE.length()]);
581 }
582
583 public void testSplitPreserveAllTokens_StringChar() {
584 assertEquals(null, StringUtils.splitPreserveAllTokens(null, '.'));
585 assertEquals(0, StringUtils.splitPreserveAllTokens("", '.').length);
586
587 String str = "a.b. c";
588 String[] res = StringUtils.splitPreserveAllTokens(str, '.');
589 assertEquals(3, res.length);
590 assertEquals("a", res[0]);
591 assertEquals("b", res[1]);
592 assertEquals(" c", res[2]);
593
594 str = "a.b.. c";
595 res = StringUtils.splitPreserveAllTokens(str, '.');
596 assertEquals(4, res.length);
597 assertEquals("a", res[0]);
598 assertEquals("b", res[1]);
599 assertEquals("", res[2]);
600 assertEquals(" c", res[3]);
601
602 str = ".a.";
603 res = StringUtils.splitPreserveAllTokens(str, '.');
604 assertEquals(3, res.length);
605 assertEquals("", res[0]);
606 assertEquals("a", res[1]);
607 assertEquals("", res[2]);
608
609 str = ".a..";
610 res = StringUtils.splitPreserveAllTokens(str, '.');
611 assertEquals(4, res.length);
612 assertEquals("", res[0]);
613 assertEquals("a", res[1]);
614 assertEquals("", res[2]);
615 assertEquals("", res[3]);
616
617 str = "..a.";
618 res = StringUtils.splitPreserveAllTokens(str, '.');
619 assertEquals(4, res.length);
620 assertEquals("", res[0]);
621 assertEquals("", res[1]);
622 assertEquals("a", res[2]);
623 assertEquals("", res[3]);
624
625 str = "..a";
626 res = StringUtils.splitPreserveAllTokens(str, '.');
627 assertEquals(3, res.length);
628 assertEquals("", res[0]);
629 assertEquals("", res[1]);
630 assertEquals("a", res[2]);
631
632 str = "a b c";
633 res = StringUtils.splitPreserveAllTokens(str,' ');
634 assertEquals(3, res.length);
635 assertEquals("a", res[0]);
636 assertEquals("b", res[1]);
637 assertEquals("c", res[2]);
638
639 str = "a b c";
640 res = StringUtils.splitPreserveAllTokens(str,' ');
641 assertEquals(5, res.length);
642 assertEquals("a", res[0]);
643 assertEquals("", res[1]);
644 assertEquals("b", res[2]);
645 assertEquals("", res[3]);
646 assertEquals("c", res[4]);
647
648 str = " a b c";
649 res = StringUtils.splitPreserveAllTokens(str,' ');
650 assertEquals(4, res.length);
651 assertEquals("", res[0]);
652 assertEquals("a", res[1]);
653 assertEquals("b", res[2]);
654 assertEquals("c", res[3]);
655
656 str = " a b c";
657 res = StringUtils.splitPreserveAllTokens(str,' ');
658 assertEquals(5, res.length);
659 assertEquals("", res[0]);
660 assertEquals("", res[1]);
661 assertEquals("a", res[2]);
662 assertEquals("b", res[3]);
663 assertEquals("c", res[4]);
664
665 str = "a b c ";
666 res = StringUtils.splitPreserveAllTokens(str,' ');
667 assertEquals(4, res.length);
668 assertEquals("a", res[0]);
669 assertEquals("b", res[1]);
670 assertEquals("c", res[2]);
671 assertEquals("", res[3]);
672
673 str = "a b c ";
674 res = StringUtils.splitPreserveAllTokens(str,' ');
675 assertEquals(5, res.length);
676 assertEquals("a", res[0]);
677 assertEquals("b", res[1]);
678 assertEquals("c", res[2]);
679 assertEquals("", res[3]);
680 assertEquals("", res[3]);
681
682 // Match example in javadoc
683 {
684 String[] results;
685 String[] expectedResults = {"a", "", "b", "c"};
686 results = StringUtils.splitPreserveAllTokens("a..b.c",'.');
687 assertEquals(expectedResults.length, results.length);
688 for (int i = 0; i < expectedResults.length; i++) {
689 assertEquals(expectedResults[i], results[i]);
690 }
691 }
692 }
693
694 public void testSplitPreserveAllTokens_StringString_StringStringInt() {
695 assertEquals(null, StringUtils.splitPreserveAllTokens(null, "."));
696 assertEquals(null, StringUtils.splitPreserveAllTokens(null, ".", 3));
697
698 assertEquals(0, StringUtils.splitPreserveAllTokens("", ".").length);
699 assertEquals(0, StringUtils.splitPreserveAllTokens("", ".", 3).length);
700
701 innerTestSplitPreserveAllTokens('.', ".", ' ');
702 innerTestSplitPreserveAllTokens('.', ".", ',');
703 innerTestSplitPreserveAllTokens('.', ".,", 'x');
704 for (int i = 0; i < WHITESPACE.length(); i++) {
705 for (int j = 0; j < NON_WHITESPACE.length(); j++) {
706 innerTestSplitPreserveAllTokens(WHITESPACE.charAt(i), null, NON_WHITESPACE.charAt(j));
707 innerTestSplitPreserveAllTokens(WHITESPACE.charAt(i), String.valueOf(WHITESPACE.charAt(i)), NON_WHITESPACE.charAt(j));
708 }
709 }
710
711 {
712 String[] results;
713 String[] expectedResults = {"ab", "de fg"};
714 results = StringUtils.splitPreserveAllTokens("ab de fg", null, 2);
715 assertEquals(expectedResults.length, results.length);
716 for (int i = 0; i < expectedResults.length; i++) {
717 assertEquals(expectedResults[i], results[i]);
718 }
719 }
720
721 {
722 String[] results;
723 String[] expectedResults = {"ab", " de fg"};
724 results = StringUtils.splitPreserveAllTokens("ab de fg", null, 2);
725 assertEquals(expectedResults.length, results.length);
726 for (int i = 0; i < expectedResults.length; i++) {
727 assertEquals(expectedResults[i], results[i]);
728 }
729 }
730
731 {
732 String[] results;
733 String[] expectedResults = {"ab", "::de:fg"};
734 results = StringUtils.splitPreserveAllTokens("ab:::de:fg", ":", 2);
735 assertEquals(expectedResults.length, results.length);
736 for (int i = 0; i < expectedResults.length; i++) {
737 assertEquals(expectedResults[i], results[i]);
738 }
739 }
740
741 {
742 String[] results;
743 String[] expectedResults = {"ab", "", " de fg"};
744 results = StringUtils.splitPreserveAllTokens("ab de fg", null, 3);
745 assertEquals(expectedResults.length, results.length);
746 for (int i = 0; i < expectedResults.length; i++) {
747 assertEquals(expectedResults[i], results[i]);
748 }
749 }
750
751 {
752 String[] results;
753 String[] expectedResults = {"ab", "", "", "de fg"};
754 results = StringUtils.splitPreserveAllTokens("ab de fg", null, 4);
755 assertEquals(expectedResults.length, results.length);
756 for (int i = 0; i < expectedResults.length; i++) {
757 assertEquals(expectedResults[i], results[i]);
758 }
759 }
760
761 {
762 String[] expectedResults = {"ab", "cd:ef"};
763 String[] results;
764 results = StringUtils.splitPreserveAllTokens("ab:cd:ef",":", 2);
765 assertEquals(expectedResults.length, results.length);
766 for (int i = 0; i < expectedResults.length; i++) {
767 assertEquals(expectedResults[i], results[i]);
768 }
769 }
770
771 {
772 String[] results;
773 String[] expectedResults = {"ab", ":cd:ef"};
774 results = StringUtils.splitPreserveAllTokens("ab::cd:ef",":", 2);
775 assertEquals(expectedResults.length, results.length);
776 for (int i = 0; i < expectedResults.length; i++) {
777 assertEquals(expectedResults[i], results[i]);
778 }
779 }
780
781 {
782 String[] results;
783 String[] expectedResults = {"ab", "", ":cd:ef"};
784 results = StringUtils.splitPreserveAllTokens("ab:::cd:ef",":", 3);
785 assertEquals(expectedResults.length, results.length);
786 for (int i = 0; i < expectedResults.length; i++) {
787 assertEquals(expectedResults[i], results[i]);
788 }
789 }
790
791 {
792 String[] results;
793 String[] expectedResults = {"ab", "", "", "cd:ef"};
794 results = StringUtils.splitPreserveAllTokens("ab:::cd:ef",":", 4);
795 assertEquals(expectedResults.length, results.length);
796 for (int i = 0; i < expectedResults.length; i++) {
797 assertEquals(expectedResults[i], results[i]);
798 }
799 }
800
801 {
802 String[] results;
803 String[] expectedResults = {"", "ab", "", "", "cd:ef"};
804 results = StringUtils.splitPreserveAllTokens(":ab:::cd:ef",":", 5);
805 assertEquals(expectedResults.length, results.length);
806 for (int i = 0; i < expectedResults.length; i++) {
807 assertEquals(expectedResults[i], results[i]);
808 }
809 }
810
811 {
812 String[] results;
813 String[] expectedResults = {"", "", "ab", "", "", "cd:ef"};
814 results = StringUtils.splitPreserveAllTokens("::ab:::cd:ef",":", 6);
815 assertEquals(expectedResults.length, results.length);
816 for (int i = 0; i < expectedResults.length; i++) {
817 assertEquals(expectedResults[i], results[i]);
818 }
819 }
820
821 }
822
823 private void innerTestSplitPreserveAllTokens(char separator, String sepStr, char noMatch) {
824 String msg = "Failed on separator hex(" + Integer.toHexString(separator) +
825 "), noMatch hex(" + Integer.toHexString(noMatch) + "), sepStr(" + sepStr + ")";
826
827 final String str = "a" + separator + "b" + separator + separator + noMatch + "c";
828 String[] res;
829 // (str, sepStr)
830 res = StringUtils.splitPreserveAllTokens(str, sepStr);
831 assertEquals(msg, 4, res.length);
832 assertEquals(msg, "a", res[0]);
833 assertEquals(msg, "b", res[1]);
834 assertEquals(msg, "", res[2]);
835 assertEquals(msg, noMatch + "c", res[3]);
836
837 final String str2 = separator + "a" + separator;
838 res = StringUtils.splitPreserveAllTokens(str2, sepStr);
839 assertEquals(msg, 3, res.length);
840 assertEquals(msg, "", res[0]);
841 assertEquals(msg, "a", res[1]);
842 assertEquals(msg, "", res[2]);
843
844 res = StringUtils.splitPreserveAllTokens(str, sepStr, -1);
845 assertEquals(msg, 4, res.length);
846 assertEquals(msg, "a", res[0]);
847 assertEquals(msg, "b", res[1]);
848 assertEquals(msg, "", res[2]);
849 assertEquals(msg, noMatch + "c", res[3]);
850
851 res = StringUtils.splitPreserveAllTokens(str, sepStr, 0);
852 assertEquals(msg, 4, res.length);
853 assertEquals(msg, "a", res[0]);
854 assertEquals(msg, "b", res[1]);
855 assertEquals(msg, "", res[2]);
856 assertEquals(msg, noMatch + "c", res[3]);
857
858 res = StringUtils.splitPreserveAllTokens(str, sepStr, 1);
859 assertEquals(msg, 1, res.length);
860 assertEquals(msg, str, res[0]);
861
862 res = StringUtils.splitPreserveAllTokens(str, sepStr, 2);
863 assertEquals(msg, 2, res.length);
864 assertEquals(msg, "a", res[0]);
865 assertEquals(msg, str.substring(2), res[1]);
866 }
867
868 public void testSplitByCharacterType() {
869 assertNull(StringUtils.splitByCharacterType(null));
870 assertEquals(0, StringUtils.splitByCharacterType("").length);
871
872 assertTrue(ArrayUtils.isEquals(new String[] { "ab", " ", "de", " ",
873 "fg" }, StringUtils.splitByCharacterType("ab de fg")));
874
875 assertTrue(ArrayUtils.isEquals(new String[] { "ab", " ", "de", " ",
876 "fg" }, StringUtils.splitByCharacterType("ab de fg")));
877
878 assertTrue(ArrayUtils.isEquals(new String[] { "ab", ":", "cd", ":",
879 "ef" }, StringUtils.splitByCharacterType("ab:cd:ef")));
880
881 assertTrue(ArrayUtils.isEquals(new String[] { "number", "5" },
882 StringUtils.splitByCharacterType("number5")));
883
884 assertTrue(ArrayUtils.isEquals(new String[] { "foo", "B", "ar" },
885 StringUtils.splitByCharacterType("fooBar")));
886
887 assertTrue(ArrayUtils.isEquals(new String[] { "foo", "200", "B", "ar" },
888 StringUtils.splitByCharacterType("foo200Bar")));
889
890 assertTrue(ArrayUtils.isEquals(new String[] { "ASFR", "ules" },
891 StringUtils.splitByCharacterType("ASFRules")));
892 }
893
894 public void testSplitByCharacterTypeCamelCase() {
895 assertNull(StringUtils.splitByCharacterTypeCamelCase(null));
896 assertEquals(0, StringUtils.splitByCharacterTypeCamelCase("").length);
897
898 assertTrue(ArrayUtils.isEquals(new String[] { "ab", " ", "de", " ",
899 "fg" }, StringUtils.splitByCharacterTypeCamelCase("ab de fg")));
900
901 assertTrue(ArrayUtils.isEquals(new String[] { "ab", " ", "de", " ",
902 "fg" }, StringUtils.splitByCharacterTypeCamelCase("ab de fg")));
903
904 assertTrue(ArrayUtils.isEquals(new String[] { "ab", ":", "cd", ":",
905 "ef" }, StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")));
906
907 assertTrue(ArrayUtils.isEquals(new String[] { "number", "5" },
908 StringUtils.splitByCharacterTypeCamelCase("number5")));
909
910 assertTrue(ArrayUtils.isEquals(new String[] { "foo", "Bar" },
911 StringUtils.splitByCharacterTypeCamelCase("fooBar")));
912
913 assertTrue(ArrayUtils.isEquals(new String[] { "foo", "200", "Bar" },
914 StringUtils.splitByCharacterTypeCamelCase("foo200Bar")));
915
916 assertTrue(ArrayUtils.isEquals(new String[] { "ASF", "Rules" },
917 StringUtils.splitByCharacterTypeCamelCase("ASFRules")));
918 }
919
920 public void testDeleteWhitespace_String() {
921 assertEquals(null, StringUtils.deleteWhitespace(null));
922 assertEquals("", StringUtils.deleteWhitespace(""));
923 assertEquals("", StringUtils.deleteWhitespace(" \u000C \t\t\u001F\n\n \u000B "));
924 assertEquals("", StringUtils.deleteWhitespace(StringUtilsTest.WHITESPACE));
925 assertEquals(StringUtilsTest.NON_WHITESPACE, StringUtils.deleteWhitespace(StringUtilsTest.NON_WHITESPACE));
926 // Note: u-2007 and u-000A both cause problems in the source code
927 // it should ignore 2007 but delete 000A
928 assertEquals("\u00A0\u202F", StringUtils.deleteWhitespace(" \u00A0 \t\t\n\n \u202F "));
929 assertEquals("\u00A0\u202F", StringUtils.deleteWhitespace("\u00A0\u202F"));
930 assertEquals("test", StringUtils.deleteWhitespace("\u000Bt \t\n\u0009e\rs\n\n \tt"));
931 }
932
933 public void testLang623() {
934 assertEquals("t", StringUtils.replaceChars("\u00DE", '\u00DE', 't'));
935 assertEquals("t", StringUtils.replaceChars("\u00FE", '\u00FE', 't'));
936 }
937
938 public void testReplace_StringStringString() {
939 assertEquals(null, StringUtils.replace(null, null, null));
940 assertEquals(null, StringUtils.replace(null, null, "any"));
941 assertEquals(null, StringUtils.replace(null, "any", null));
942 assertEquals(null, StringUtils.replace(null, "any", "any"));
943
944 assertEquals("", StringUtils.replace("", null, null));
945 assertEquals("", StringUtils.replace("", null, "any"));
946 assertEquals("", StringUtils.replace("", "any", null));
947 assertEquals("", StringUtils.replace("", "any", "any"));
948
949 assertEquals("FOO", StringUtils.replace("FOO", "", "any"));
950 assertEquals("FOO", StringUtils.replace("FOO", null, "any"));
951 assertEquals("FOO", StringUtils.replace("FOO", "F", null));
952 assertEquals("FOO", StringUtils.replace("FOO", null, null));
953
954 assertEquals("", StringUtils.replace("foofoofoo", "foo", ""));
955 assertEquals("barbarbar", StringUtils.replace("foofoofoo", "foo", "bar"));
956 assertEquals("farfarfar", StringUtils.replace("foofoofoo", "oo", "ar"));
957 }
958
959 public void testReplace_StringStringStringInt() {
960 assertEquals(null, StringUtils.replace(null, null, null, 2));
961 assertEquals(null, StringUtils.replace(null, null, "any", 2));
962 assertEquals(null, StringUtils.replace(null, "any", null, 2));
963 assertEquals(null, StringUtils.replace(null, "any", "any", 2));
964
965 assertEquals("", StringUtils.replace("", null, null, 2));
966 assertEquals("", StringUtils.replace("", null, "any", 2));
967 assertEquals("", StringUtils.replace("", "any", null, 2));
968 assertEquals("", StringUtils.replace("", "any", "any", 2));
969
970 String str = new String(new char[] {'o', 'o', 'f', 'o', 'o'});
971 assertSame(str, StringUtils.replace(str, "x", "", -1));
972
973 assertEquals("f", StringUtils.replace("oofoo", "o", "", -1));
974 assertEquals("oofoo", StringUtils.replace("oofoo", "o", "", 0));
975 assertEquals("ofoo", StringUtils.replace("oofoo", "o", "", 1));
976 assertEquals("foo", StringUtils.replace("oofoo", "o", "", 2));
977 assertEquals("fo", StringUtils.replace("oofoo", "o", "", 3));
978 assertEquals("f", StringUtils.replace("oofoo", "o", "", 4));
979
980 assertEquals("f", StringUtils.replace("oofoo", "o", "", -5));
981 assertEquals("f", StringUtils.replace("oofoo", "o", "", 1000));
982 }
983
984 public void testReplaceOnce_StringStringString() {
985 assertEquals(null, StringUtils.replaceOnce(null, null, null));
986 assertEquals(null, StringUtils.replaceOnce(null, null, "any"));
987 assertEquals(null, StringUtils.replaceOnce(null, "any", null));
988 assertEquals(null, StringUtils.replaceOnce(null, "any", "any"));
989
990 assertEquals("", StringUtils.replaceOnce("", null, null));
991 assertEquals("", StringUtils.replaceOnce("", null, "any"));
992 assertEquals("", StringUtils.replaceOnce("", "any", null));
993 assertEquals("", StringUtils.replaceOnce("", "any", "any"));
994
995 assertEquals("FOO", StringUtils.replaceOnce("FOO", "", "any"));
996 assertEquals("FOO", StringUtils.replaceOnce("FOO", null, "any"));
997 assertEquals("FOO", StringUtils.replaceOnce("FOO", "F", null));
998 assertEquals("FOO", StringUtils.replaceOnce("FOO", null, null));
999
1000 assertEquals("foofoo", StringUtils.replaceOnce("foofoofoo", "foo", ""));
1001 }
1002
1003 /**
1004 * Test method for 'StringUtils.replaceEach(String, String[], String[])'
1005 */
1006 public void testReplace_StringStringArrayStringArray() {
1007
1008
1009 //JAVADOC TESTS START
1010 assertNull(StringUtils.replaceEach(null, new String[]{"a"}, new String[]{"b"}));
1011 assertEquals(StringUtils.replaceEach("", new String[]{"a"}, new String[]{"b"}),"");
1012 assertEquals(StringUtils.replaceEach("aba", null, null),"aba");
1013 assertEquals(StringUtils.replaceEach("aba", new String[0], null),"aba");
1014 assertEquals(StringUtils.replaceEach("aba", null, new String[0]),"aba");
1015 assertEquals(StringUtils.replaceEach("aba", new String[]{"a"}, null),"aba");
1016
1017 assertEquals(StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}),"b");
1018 assertEquals(StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}),"aba");
1019 assertEquals(StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}),"wcte");
1020 assertEquals(StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}),"dcte");
1021 //JAVADOC TESTS END
1022
1023 assertEquals("bcc", StringUtils.replaceEach("abc", new String[]{"a", "b"}, new String[]{"b", "c"}));
1024 assertEquals("q651.506bera", StringUtils.replaceEach("d216.102oren",
1025 new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
1026 "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D",
1027 "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
1028 "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9"},
1029 new String[]{"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "a",
1030 "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "N", "O", "P", "Q",
1031 "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A", "B", "C", "D", "E", "F", "G",
1032 "H", "I", "J", "K", "L", "M", "5", "6", "7", "8", "9", "1", "2", "3", "4"}));
1033
1034 // Test null safety inside arrays - LANG-552
1035 assertEquals(StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{null}),"aba");
1036 assertEquals(StringUtils.replaceEach("aba", new String[]{"a", "b"}, new String[]{"c", null}),"cbc");
1037 }
1038
1039 /**
1040 * Test method for 'StringUtils.replaceEachRepeatedly(String, String[], String[])'
1041 */
1042 public void testReplace_StringStringArrayStringArrayBoolean() {
1043 //JAVADOC TESTS START
1044 assertNull(StringUtils.replaceEachRepeatedly(null, new String[]{"a"}, new String[]{"b"}));
1045 assertEquals(StringUtils.replaceEachRepeatedly("", new String[]{"a"}, new String[]{"b"}),"");
1046 assertEquals(StringUtils.replaceEachRepeatedly("aba", null, null),"aba");
1047 assertEquals(StringUtils.replaceEachRepeatedly("aba", new String[0], null),"aba");
1048 assertEquals(StringUtils.replaceEachRepeatedly("aba", null, new String[0]),"aba");
1049 assertEquals(StringUtils.replaceEachRepeatedly("aba", new String[0], null),"aba");
1050
1051 assertEquals(StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}),"b");
1052 assertEquals(StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}),"aba");
1053 assertEquals(StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}),"wcte");
1054 assertEquals(StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}),"tcte");
1055
1056 try {
1057 StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"});
1058 fail("Should be a circular reference");
1059 } catch (IllegalStateException e) {}
1060
1061 //JAVADOC TESTS END
1062
1063 }
1064
1065 public void testReplaceChars_StringCharChar() {
1066 assertEquals(null, StringUtils.replaceChars(null, 'b', 'z'));
1067 assertEquals("", StringUtils.replaceChars("", 'b', 'z'));
1068 assertEquals("azcza", StringUtils.replaceChars("abcba", 'b', 'z'));
1069 assertEquals("abcba", StringUtils.replaceChars("abcba", 'x', 'z'));
1070 }
1071
1072 public void testReplaceChars_StringStringString() {
1073 assertEquals(null, StringUtils.replaceChars(null, null, null));
1074 assertEquals(null, StringUtils.replaceChars(null, "", null));
1075 assertEquals(null, StringUtils.replaceChars(null, "a", null));
1076 assertEquals(null, StringUtils.replaceChars(null, null, ""));
1077 assertEquals(null, StringUtils.replaceChars(null, null, "x"));
1078
1079 assertEquals("", StringUtils.replaceChars("", null, null));
1080 assertEquals("", StringUtils.replaceChars("", "", null));
1081 assertEquals("", StringUtils.replaceChars("", "a", null));
1082 assertEquals("", StringUtils.replaceChars("", null, ""));
1083 assertEquals("", StringUtils.replaceChars("", null, "x"));
1084
1085 assertEquals("abc", StringUtils.replaceChars("abc", null, null));
1086 assertEquals("abc", StringUtils.replaceChars("abc", null, ""));
1087 assertEquals("abc", StringUtils.replaceChars("abc", null, "x"));
1088
1089 assertEquals("abc", StringUtils.replaceChars("abc", "", null));
1090 assertEquals("abc", StringUtils.replaceChars("abc", "", ""));
1091 assertEquals("abc", StringUtils.replaceChars("abc", "", "x"));
1092
1093 assertEquals("ac", StringUtils.replaceChars("abc", "b", null));
1094 assertEquals("ac", StringUtils.replaceChars("abc", "b", ""));
1095 assertEquals("axc", StringUtils.replaceChars("abc", "b", "x"));
1096
1097 assertEquals("ayzya", StringUtils.replaceChars("abcba", "bc", "yz"));
1098 assertEquals("ayya", StringUtils.replaceChars("abcba", "bc", "y"));
1099 assertEquals("ayzya", StringUtils.replaceChars("abcba", "bc", "yzx"));
1100
1101 assertEquals("abcba", StringUtils.replaceChars("abcba", "z", "w"));
1102 assertSame("abcba", StringUtils.replaceChars("abcba", "z", "w"));
1103
1104 // Javadoc examples:
1105 assertEquals("jelly", StringUtils.replaceChars("hello", "ho", "jy"));
1106 assertEquals("ayzya", StringUtils.replaceChars("abcba", "bc", "yz"));
1107 assertEquals("ayya", StringUtils.replaceChars("abcba", "bc", "y"));
1108 assertEquals("ayzya", StringUtils.replaceChars("abcba", "bc", "yzx"));
1109
1110 // From http://issues.apache.org/bugzilla/show_bug.cgi?id=25454
1111 assertEquals("bcc", StringUtils.replaceChars("abc", "ab", "bc"));
1112 assertEquals("q651.506bera", StringUtils.replaceChars("d216.102oren",
1113 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789",
1114 "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM567891234"));
1115 }
1116
1117 public void testOverlay_StringStringIntInt() {
1118 assertEquals(null, StringUtils.overlay(null, null, 2, 4));
1119 assertEquals(null, StringUtils.overlay(null, null, -2, -4));
1120
1121 assertEquals("", StringUtils.overlay("", null, 0, 0));
1122 assertEquals("", StringUtils.overlay("", "", 0, 0));
1123 assertEquals("zzzz", StringUtils.overlay("", "zzzz", 0, 0));
1124 assertEquals("zzzz", StringUtils.overlay("", "zzzz", 2, 4));
1125 assertEquals("zzzz", StringUtils.overlay("", "zzzz", -2, -4));
1126
1127 assertEquals("abef", StringUtils.overlay("abcdef", null, 2, 4));
1128 assertEquals("abef", StringUtils.overlay("abcdef", null, 4, 2));
1129 assertEquals("abef", StringUtils.overlay("abcdef", "", 2, 4));
1130 assertEquals("abef", StringUtils.overlay("abcdef", "", 4, 2));
1131 assertEquals("abzzzzef", StringUtils.overlay("abcdef", "zzzz", 2, 4));
1132 assertEquals("abzzzzef", StringUtils.overlay("abcdef", "zzzz", 4, 2));
1133
1134 assertEquals("zzzzef", StringUtils.overlay("abcdef", "zzzz", -1, 4));
1135 assertEquals("zzzzef", StringUtils.overlay("abcdef", "zzzz", 4, -1));
1136 assertEquals("zzzzabcdef", StringUtils.overlay("abcdef", "zzzz", -2, -1));
1137 assertEquals("zzzzabcdef", StringUtils.overlay("abcdef", "zzzz", -1, -2));
1138 assertEquals("abcdzzzz", StringUtils.overlay("abcdef", "zzzz", 4, 10));
1139 assertEquals("abcdzzzz", StringUtils.overlay("abcdef", "zzzz", 10, 4));
1140 assertEquals("abcdefzzzz", StringUtils.overlay("abcdef", "zzzz", 8, 10));
1141 assertEquals("abcdefzzzz", StringUtils.overlay("abcdef", "zzzz", 10, 8));
1142 }
1143
1144 public void testRepeat_StringInt() {
1145 assertEquals(null, StringUtils.repeat(null, 2));
1146 assertEquals("", StringUtils.repeat("ab", 0));
1147 assertEquals("", StringUtils.repeat("", 3));
1148 assertEquals("aaa", StringUtils.repeat("a", 3));
1149 assertEquals("ababab", StringUtils.repeat("ab", 3));
1150 assertEquals("abcabcabc", StringUtils.repeat("abc", 3));
1151 String str = StringUtils.repeat("a", 10000); // bigger than pad limit
1152 assertEquals(10000, str.length());
1153 assertEquals(true, StringUtils.containsOnly(str, new char[] {'a'}));
1154 }
1155
1156 public void testRepeat_StringStringInt() {
1157 assertEquals(null, StringUtils.repeat(null, null, 2));
1158 assertEquals(null, StringUtils.repeat(null, "x", 2));
1159 assertEquals("", StringUtils.repeat("", null, 2));
1160
1161 assertEquals("", StringUtils.repeat("ab", "", 0));
1162 assertEquals("", StringUtils.repeat("", "", 2));
1163
1164 assertEquals("xx", StringUtils.repeat("", "x", 3));
1165
1166 assertEquals("?, ?, ?", StringUtils.repeat("?", ", ", 3));
1167 }
1168
1169 public void testChop() {
1170
1171 String[][] chopCases = {
1172 { FOO_UNCAP + "\r\n", FOO_UNCAP } ,
1173 { FOO_UNCAP + "\n" , FOO_UNCAP } ,
1174 { FOO_UNCAP + "\r", FOO_UNCAP },
1175 { FOO_UNCAP + " \r", FOO_UNCAP + " " },
1176 { "foo", "fo"},
1177 { "foo\nfoo", "foo\nfo" },
1178 { "\n", "" },
1179 { "\r", "" },
1180 { "\r\n", "" },
1181 { null, null },
1182 { "", "" },
1183 { "a", "" },
1184 };
1185 for (String[] chopCase : chopCases) {
1186 String original = chopCase[0];
1187 String expectedResult = chopCase[1];
1188 assertEquals("chop(String) failed",
1189 expectedResult, StringUtils.chop(original));
1190 }
1191 }
1192
1193 public void testChomp() {
1194
1195 String[][] chompCases = {
1196 { FOO_UNCAP + "\r\n", FOO_UNCAP },
1197 { FOO_UNCAP + "\n" , FOO_UNCAP },
1198 { FOO_UNCAP + "\r", FOO_UNCAP },
1199 { FOO_UNCAP + " \r", FOO_UNCAP + " " },
1200 { FOO_UNCAP, FOO_UNCAP },
1201 { FOO_UNCAP + "\n\n", FOO_UNCAP + "\n"},
1202 { FOO_UNCAP + "\r\n\r\n", FOO_UNCAP + "\r\n" },
1203 { "foo\nfoo", "foo\nfoo" },
1204 { "foo\n\rfoo", "foo\n\rfoo" },
1205 { "\n", "" },
1206 { "\r", "" },
1207 { "a", "a" },
1208 { "\r\n", "" },
1209 { "", "" },
1210 { null, null },
1211 { FOO_UNCAP + "\n\r", FOO_UNCAP + "\n"}
1212 };
1213 for (String[] chompCase : chompCases) {
1214 String original = chompCase[0];
1215 String expectedResult = chompCase[1];
1216 assertEquals("chomp(String) failed",
1217 expectedResult, StringUtils.chomp(original));
1218 }
1219
1220 assertEquals("chomp(String, String) failed",
1221 "foo", StringUtils.chomp("foobar", "bar"));
1222 assertEquals("chomp(String, String) failed",
1223 "foobar", StringUtils.chomp("foobar", "baz"));
1224 assertEquals("chomp(String, String) failed",
1225 "foo", StringUtils.chomp("foo", "foooo"));
1226 assertEquals("chomp(String, String) failed",
1227 "foobar", StringUtils.chomp("foobar", ""));
1228 assertEquals("chomp(String, String) failed",
1229 "foobar", StringUtils.chomp("foobar", null));
1230 assertEquals("chomp(String, String) failed",
1231 "", StringUtils.chomp("", "foo"));
1232 assertEquals("chomp(String, String) failed",
1233 "", StringUtils.chomp("", null));
1234 assertEquals("chomp(String, String) failed",
1235 "", StringUtils.chomp("", ""));
1236 assertEquals("chomp(String, String) failed",
1237 null, StringUtils.chomp(null, "foo"));
1238 assertEquals("chomp(String, String) failed",
1239 null, StringUtils.chomp(null, null));
1240 assertEquals("chomp(String, String) failed",
1241 null, StringUtils.chomp(null, ""));
1242 assertEquals("chomp(String, String) failed",
1243 "", StringUtils.chomp("foo", "foo"));
1244 assertEquals("chomp(String, String) failed",
1245 " ", StringUtils.chomp(" foo", "foo"));
1246 assertEquals("chomp(String, String) failed",
1247 "foo ", StringUtils.chomp("foo ", "foo"));
1248 }
1249
1250 //-----------------------------------------------------------------------
1251 public void testRightPad_StringInt() {
1252 assertEquals(null, StringUtils.rightPad(null, 5));
1253 assertEquals(" ", StringUtils.rightPad("", 5));
1254 assertEquals("abc ", StringUtils.rightPad("abc", 5));
1255 assertEquals("abc", StringUtils.rightPad("abc", 2));
1256 assertEquals("abc", StringUtils.rightPad("abc", -1));
1257 }
1258
1259 public void testRightPad_StringIntChar() {
1260 assertEquals(null, StringUtils.rightPad(null, 5, ' '));
1261 assertEquals(" ", StringUtils.rightPad("", 5, ' '));
1262 assertEquals("abc ", StringUtils.rightPad("abc", 5, ' '));
1263 assertEquals("abc", StringUtils.rightPad("abc", 2, ' '));
1264 assertEquals("abc", StringUtils.rightPad("abc", -1, ' '));
1265 assertEquals("abcxx", StringUtils.rightPad("abc", 5, 'x'));
1266 String str = StringUtils.rightPad("aaa", 10000, 'a'); // bigger than pad length
1267 assertEquals(10000, str.length());
1268 assertEquals(true, StringUtils.containsOnly(str, new char[] {'a'}));
1269 }
1270
1271 public void testRightPad_StringIntString() {
1272 assertEquals(null, StringUtils.rightPad(null, 5, "-+"));
1273 assertEquals(" ", StringUtils.rightPad("", 5, " "));
1274 assertEquals(null, StringUtils.rightPad(null, 8, null));
1275 assertEquals("abc-+-+", StringUtils.rightPad("abc", 7, "-+"));
1276 assertEquals("abc-+~", StringUtils.rightPad("abc", 6, "-+~"));
1277 assertEquals("abc-+", StringUtils.rightPad("abc", 5, "-+~"));
1278 assertEquals("abc", StringUtils.rightPad("abc", 2, " "));
1279 assertEquals("abc", StringUtils.rightPad("abc", -1, " "));
1280 assertEquals("abc ", StringUtils.rightPad("abc", 5, null));
1281 assertEquals("abc ", StringUtils.rightPad("abc", 5, ""));
1282 }
1283
1284 //-----------------------------------------------------------------------
1285 public void testLeftPad_StringInt() {
1286 assertEquals(null, StringUtils.leftPad(null, 5));
1287 assertEquals(" ", StringUtils.leftPad("", 5));
1288 assertEquals(" abc", StringUtils.leftPad("abc", 5));
1289 assertEquals("abc", StringUtils.leftPad("abc", 2));
1290 }
1291
1292 public void testLeftPad_StringIntChar() {
1293 assertEquals(null, StringUtils.leftPad(null, 5, ' '));
1294 assertEquals(" ", StringUtils.leftPad("", 5, ' '));
1295 assertEquals(" abc", StringUtils.leftPad("abc", 5, ' '));
1296 assertEquals("xxabc", StringUtils.leftPad("abc", 5, 'x'));
1297 assertEquals("\uffff\uffffabc", StringUtils.leftPad("abc", 5, '\uffff'));
1298 assertEquals("abc", StringUtils.leftPad("abc", 2, ' '));
1299 String str = StringUtils.leftPad("aaa", 10000, 'a'); // bigger than pad length
1300 assertEquals(10000, str.length());
1301 assertEquals(true, StringUtils.containsOnly(str, new char[] {'a'}));
1302 }
1303
1304 public void testLeftPad_StringIntString() {
1305 assertEquals(null, StringUtils.leftPad(null, 5, "-+"));
1306 assertEquals(null, StringUtils.leftPad(null, 5, null));
1307 assertEquals(" ", StringUtils.leftPad("", 5, " "));
1308 assertEquals("-+-+abc", StringUtils.leftPad("abc", 7, "-+"));
1309 assertEquals("-+~abc", StringUtils.leftPad("abc", 6, "-+~"));
1310 assertEquals("-+abc", StringUtils.leftPad("abc", 5, "-+~"));
1311 assertEquals("abc", StringUtils.leftPad("abc", 2, " "));
1312 assertEquals("abc", StringUtils.leftPad("abc", -1, " "));
1313 assertEquals(" abc", StringUtils.leftPad("abc", 5, null));
1314 assertEquals(" abc", StringUtils.leftPad("abc", 5, ""));
1315 }
1316
1317 public void testLengthString() {
1318 assertEquals(0, StringUtils.length(null));
1319 assertEquals(0, StringUtils.length(""));
1320 assertEquals(0, StringUtils.length(StringUtils.EMPTY));
1321 assertEquals(1, StringUtils.length("A"));
1322 assertEquals(1, StringUtils.length(" "));
1323 assertEquals(8, StringUtils.length("ABCDEFGH"));
1324 }
1325
1326 public void testLengthStringBuffer() {
1327 assertEquals(0, StringUtils.length(new StringBuffer("")));
1328 assertEquals(0, StringUtils.length(new StringBuffer(StringUtils.EMPTY)));
1329 assertEquals(1, StringUtils.length(new StringBuffer("A")));
1330 assertEquals(1, StringUtils.length(new StringBuffer(" ")));
1331 assertEquals(8, StringUtils.length(new StringBuffer("ABCDEFGH")));
1332 }
1333
1334 public void testLengthStringBuilder() {
1335 assertEquals(0, StringUtils.length(new StringBuilder("")));
1336 assertEquals(0, StringUtils.length(new StringBuilder(StringUtils.EMPTY)));
1337 assertEquals(1, StringUtils.length(new StringBuilder("A")));
1338 assertEquals(1, StringUtils.length(new StringBuilder(" ")));
1339 assertEquals(8, StringUtils.length(new StringBuilder("ABCDEFGH")));
1340 }
1341
1342 public void testLength_CharBuffer() {
1343 assertEquals(0, StringUtils.length(CharBuffer.wrap("")));
1344 assertEquals(1, StringUtils.length(CharBuffer.wrap("A")));
1345 assertEquals(1, StringUtils.length(CharBuffer.wrap(" ")));
1346 assertEquals(8, StringUtils.length(CharBuffer.wrap("ABCDEFGH")));
1347 }
1348
1349 //-----------------------------------------------------------------------
1350 public void testCenter_StringInt() {
1351 assertEquals(null, StringUtils.center(null, -1));
1352 assertEquals(null, StringUtils.center(null, 4));
1353 assertEquals(" ", StringUtils.center("", 4));
1354 assertEquals("ab", StringUtils.center("ab", 0));
1355 assertEquals("ab", StringUtils.center("ab", -1));
1356 assertEquals("ab", StringUtils.center("ab", 1));
1357 assertEquals(" ", StringUtils.center("", 4));
1358 assertEquals(" ab ", StringUtils.center("ab", 4));
1359 assertEquals("abcd", StringUtils.center("abcd", 2));
1360 assertEquals(" a ", StringUtils.center("a", 4));
1361 assertEquals(" a ", StringUtils.center("a", 5));
1362 }
1363
1364 public void testCenter_StringIntChar() {
1365 assertEquals(null, StringUtils.center(null, -1, ' '));
1366 assertEquals(null, StringUtils.center(null, 4, ' '));
1367 assertEquals(" ", StringUtils.center("", 4, ' '));
1368 assertEquals("ab", StringUtils.center("ab", 0, ' '));
1369 assertEquals("ab", StringUtils.center("ab", -1, ' '));
1370 assertEquals("ab", StringUtils.center("ab", 1, ' '));
1371 assertEquals(" ", StringUtils.center("", 4, ' '));
1372 assertEquals(" ab ", StringUtils.center("ab", 4, ' '));
1373 assertEquals("abcd", StringUtils.center("abcd", 2, ' '));
1374 assertEquals(" a ", StringUtils.center("a", 4, ' '));
1375 assertEquals(" a ", StringUtils.center("a", 5, ' '));
1376 assertEquals("xxaxx", StringUtils.center("a", 5, 'x'));
1377 }
1378
1379 public void testCenter_StringIntString() {
1380 assertEquals(null, StringUtils.center(null, 4, null));
1381 assertEquals(null, StringUtils.center(null, -1, " "));
1382 assertEquals(null, StringUtils.center(null, 4, " "));
1383 assertEquals(" ", StringUtils.center("", 4, " "));
1384 assertEquals("ab", StringUtils.center("ab", 0, " "));
1385 assertEquals("ab", StringUtils.center("ab", -1, " "));
1386 assertEquals("ab", StringUtils.center("ab", 1, " "));
1387 assertEquals(" ", StringUtils.center("", 4, " "));
1388 assertEquals(" ab ", StringUtils.center("ab", 4, " "));
1389 assertEquals("abcd", StringUtils.center("abcd", 2, " "));
1390 assertEquals(" a ", StringUtils.center("a", 4, " "));
1391 assertEquals("yayz", StringUtils.center("a", 4, "yz"));
1392 assertEquals("yzyayzy", StringUtils.center("a", 7, "yz"));
1393 assertEquals(" abc ", StringUtils.center("abc", 7, null));
1394 assertEquals(" abc ", StringUtils.center("abc", 7, ""));
1395 }
1396
1397 //-----------------------------------------------------------------------
1398 public void testReverse_String() {
1399 assertEquals(null, StringUtils.reverse(null) );
1400 assertEquals("", StringUtils.reverse("") );
1401 assertEquals("sdrawkcab", StringUtils.reverse("backwards") );
1402 }
1403
1404 public void testReverseDelimited_StringChar() {
1405 assertEquals(null, StringUtils.reverseDelimited(null, '.') );
1406 assertEquals("", StringUtils.reverseDelimited("", '.') );
1407 assertEquals("c.b.a", StringUtils.reverseDelimited("a.b.c", '.') );
1408 assertEquals("a b c", StringUtils.reverseDelimited("a b c", '.') );
1409 assertEquals("", StringUtils.reverseDelimited("", '.') );
1410 }
1411
1412 //-----------------------------------------------------------------------
1413 public void testDefault_String() {
1414 assertEquals("", StringUtils.defaultString(null));
1415 assertEquals("", StringUtils.defaultString(""));
1416 assertEquals("abc", StringUtils.defaultString("abc"));
1417 }
1418
1419 public void testDefault_StringString() {
1420 assertEquals("NULL", StringUtils.defaultString(null, "NULL"));
1421 assertEquals("", StringUtils.defaultString("", "NULL"));
1422 assertEquals("abc", StringUtils.defaultString("abc", "NULL"));
1423 }
1424
1425 public void testDefaultIfEmpty_StringString() {
1426 assertEquals("NULL", StringUtils.defaultIfEmpty(null, "NULL"));
1427 assertEquals("NULL", StringUtils.defaultIfEmpty("", "NULL"));
1428 assertEquals("abc", StringUtils.defaultIfEmpty("abc", "NULL"));
1429 assertNull(StringUtils.defaultIfEmpty("", null));
1430 // Tests compatibility for the API return type
1431 String s = StringUtils.defaultIfEmpty("abc", "NULL");
1432 assertEquals("abc", s);
1433 }
1434
1435 public void testDefaultIfBlank_StringString() {
1436 assertEquals("NULL", StringUtils.defaultIfBlank(null, "NULL"));
1437 assertEquals("NULL", StringUtils.defaultIfBlank("", "NULL"));
1438 assertEquals("NULL", StringUtils.defaultIfBlank(" ", "NULL"));
1439 assertEquals("abc", StringUtils.defaultIfBlank("abc", "NULL"));
1440 assertNull(StringUtils.defaultIfBlank("", null));
1441 // Tests compatibility for the API return type
1442 String s = StringUtils.defaultIfBlank("abc", "NULL");
1443 assertEquals("abc", s);
1444 }
1445
1446 public void testDefaultIfEmpty_StringBuilders() {
1447 assertEquals("NULL", StringUtils.defaultIfEmpty(new StringBuilder(""), new StringBuilder("NULL")).toString());
1448 assertEquals("abc", StringUtils.defaultIfEmpty(new StringBuilder("abc"), new StringBuilder("NULL")).toString());
1449 assertNull(StringUtils.defaultIfEmpty(new StringBuilder(""), null));
1450 // Tests compatibility for the API return type
1451 StringBuilder s = StringUtils.defaultIfEmpty(new StringBuilder("abc"), new StringBuilder("NULL"));
1452 assertEquals("abc", s.toString());
1453 }
1454
1455 public void testDefaultIfBlank_StringBuilders() {
1456 assertEquals("NULL", StringUtils.defaultIfBlank(new StringBuilder(""), new StringBuilder("NULL")).toString());
1457 assertEquals("NULL", StringUtils.defaultIfBlank(new StringBuilder(" "), new StringBuilder("NULL")).toString());
1458 assertEquals("abc", StringUtils.defaultIfBlank(new StringBuilder("abc"), new StringBuilder("NULL")).toString());
1459 assertNull(StringUtils.defaultIfBlank(new StringBuilder(""), null));
1460 // Tests compatibility for the API return type
1461 StringBuilder s = StringUtils.defaultIfBlank(new StringBuilder("abc"), new StringBuilder("NULL"));
1462 assertEquals("abc", s.toString());
1463 }
1464
1465 public void testDefaultIfEmpty_StringBuffers() {
1466 assertEquals("NULL", StringUtils.defaultIfEmpty(new StringBuffer(""), new StringBuffer("NULL")).toString());
1467 assertEquals("abc", StringUtils.defaultIfEmpty(new StringBuffer("abc"), new StringBuffer("NULL")).toString());
1468 assertNull(StringUtils.defaultIfEmpty(new StringBuffer(""), null));
1469 // Tests compatibility for the API return type
1470 StringBuffer s = StringUtils.defaultIfEmpty(new StringBuffer("abc"), new StringBuffer("NULL"));
1471 assertEquals("abc", s.toString());
1472 }
1473
1474 public void testDefaultIfBlank_StringBuffers() {
1475 assertEquals("NULL", StringUtils.defaultIfBlank(new StringBuffer(""), new StringBuffer("NULL")).toString());
1476 assertEquals("NULL", StringUtils.defaultIfBlank(new StringBuffer(" "), new StringBuffer("NULL")).toString());
1477 assertEquals("abc", StringUtils.defaultIfBlank(new StringBuffer("abc"), new StringBuffer("NULL")).toString());
1478 assertNull(StringUtils.defaultIfBlank(new StringBuffer(""), null));
1479 // Tests compatibility for the API return type
1480 StringBuffer s = StringUtils.defaultIfBlank(new StringBuffer("abc"), new StringBuffer("NULL"));
1481 assertEquals("abc", s.toString());
1482 }
1483
1484 public void testDefaultIfEmpty_CharBuffers() {
1485 assertEquals("NULL", StringUtils.defaultIfEmpty(CharBuffer.wrap(""), CharBuffer.wrap("NULL")).toString());
1486 assertEquals("abc", StringUtils.defaultIfEmpty(CharBuffer.wrap("abc"), CharBuffer.wrap("NULL")).toString());
1487 assertNull(StringUtils.defaultIfEmpty(CharBuffer.wrap(""), null));
1488 // Tests compatibility for the API return type
1489 CharBuffer s = StringUtils.defaultIfEmpty(CharBuffer.wrap("abc"), CharBuffer.wrap("NULL"));
1490 assertEquals("abc", s.toString());
1491 }
1492
1493 public void testDefaultIfBlank_CharBuffers() {
1494 assertEquals("NULL", StringUtils.defaultIfBlank(CharBuffer.wrap(""), CharBuffer.wrap("NULL")).toString());
1495 assertEquals("NULL", StringUtils.defaultIfBlank(CharBuffer.wrap(" "), CharBuffer.wrap("NULL")).toString());
1496 assertEquals("abc", StringUtils.defaultIfBlank(CharBuffer.wrap("abc"), CharBuffer.wrap("NULL")).toString());
1497 assertNull(StringUtils.defaultIfBlank(CharBuffer.wrap(""), null));
1498 // Tests compatibility for the API return type
1499 CharBuffer s = StringUtils.defaultIfBlank(CharBuffer.wrap("abc"), CharBuffer.wrap("NULL"));
1500 assertEquals("abc", s.toString());
1501 }
1502
1503 //-----------------------------------------------------------------------
1504 public void testAbbreviate_StringInt() {
1505 assertEquals(null, StringUtils.abbreviate(null, 10));
1506 assertEquals("", StringUtils.abbreviate("", 10));
1507 assertEquals("short", StringUtils.abbreviate("short", 10));
1508 assertEquals("Now is ...", StringUtils.abbreviate("Now is the time for all good men to come to the aid of their party.", 10));
1509
1510 String raspberry = "raspberry peach";
1511 assertEquals("raspberry p...", StringUtils.abbreviate(raspberry, 14));
1512 assertEquals("raspberry peach", StringUtils.abbreviate("raspberry peach", 15));
1513 assertEquals("raspberry peach", StringUtils.abbreviate("raspberry peach", 16));
1514 assertEquals("abc...", StringUtils.abbreviate("abcdefg", 6));
1515 assertEquals("abcdefg", StringUtils.abbreviate("abcdefg", 7));
1516 assertEquals("abcdefg", StringUtils.abbreviate("abcdefg", 8));
1517 assertEquals("a...", StringUtils.abbreviate("abcdefg", 4));
1518 assertEquals("", StringUtils.abbreviate("", 4));
1519
1520 try {
1521 @SuppressWarnings("unused")
1522 String res = StringUtils.abbreviate("abc", 3);
1523 fail("StringUtils.abbreviate expecting IllegalArgumentException");
1524 } catch (IllegalArgumentException ex) {
1525 // empty
1526 }
1527 }
1528
1529 public void testAbbreviate_StringIntInt() {
1530 assertEquals(null, StringUtils.abbreviate(null, 10, 12));
1531 assertEquals("", StringUtils.abbreviate("", 0, 10));
1532 assertEquals("", StringUtils.abbreviate("", 2, 10));
1533
1534 try {
1535 @SuppressWarnings("unused")
1536 String res = StringUtils.abbreviate("abcdefghij", 0, 3);
1537 fail("StringUtils.abbreviate expecting IllegalArgumentException");
1538 } catch (IllegalArgumentException ex) {
1539 // empty
1540 }
1541 try {
1542 @SuppressWarnings("unused")
1543 String res = StringUtils.abbreviate("abcdefghij", 5, 6);
1544 fail("StringUtils.abbreviate expecting IllegalArgumentException");
1545 } catch (IllegalArgumentException ex) {
1546 // empty
1547 }
1548
1549
1550 String raspberry = "raspberry peach";
1551 assertEquals("raspberry peach", StringUtils.abbreviate(raspberry, 11, 15));
1552
1553 assertEquals(null, StringUtils.abbreviate(null, 7, 14));
1554 assertAbbreviateWithOffset("abcdefg...", -1, 10);
1555 assertAbbreviateWithOffset("abcdefg...", 0, 10);
1556 assertAbbreviateWithOffset("abcdefg...", 1, 10);
1557 assertAbbreviateWithOffset("abcdefg...", 2, 10);
1558 assertAbbreviateWithOffset("abcdefg...", 3, 10);
1559 assertAbbreviateWithOffset("abcdefg...", 4, 10);
1560 assertAbbreviateWithOffset("...fghi...", 5, 10);
1561 assertAbbreviateWithOffset("...ghij...", 6, 10);
1562 assertAbbreviateWithOffset("...hijk...", 7, 10);
1563 assertAbbreviateWithOffset("...ijklmno", 8, 10);
1564 assertAbbreviateWithOffset("...ijklmno", 9, 10);
1565 assertAbbreviateWithOffset("...ijklmno", 10, 10);
1566 assertAbbreviateWithOffset("...ijklmno", 10, 10);
1567 assertAbbreviateWithOffset("...ijklmno", 11, 10);
1568 assertAbbreviateWithOffset("...ijklmno", 12, 10);
1569 assertAbbreviateWithOffset("...ijklmno", 13, 10);
1570 assertAbbreviateWithOffset("...ijklmno", 14, 10);
1571 assertAbbreviateWithOffset("...ijklmno", 15, 10);
1572 assertAbbreviateWithOffset("...ijklmno", 16, 10);
1573 assertAbbreviateWithOffset("...ijklmno", Integer.MAX_VALUE, 10);
1574 }
1575
1576 private void assertAbbreviateWithOffset(String expected, int offset, int maxWidth) {
1577 String abcdefghijklmno = "abcdefghijklmno";
1578 String message = "abbreviate(String,int,int) failed";
1579 String actual = StringUtils.abbreviate(abcdefghijklmno, offset, maxWidth);
1580 if (offset >= 0 && offset < abcdefghijklmno.length()) {
1581 assertTrue(message + " -- should contain offset character",
1582 actual.indexOf((char)('a'+offset)) != -1);
1583 }
1584 assertTrue(message + " -- should not be greater than maxWidth",
1585 actual.length() <= maxWidth);
1586 assertEquals(message, expected, actual);
1587 }
1588
1589 public void testAbbreviateMiddle() {
1590 // javadoc examples
1591 assertNull( StringUtils.abbreviateMiddle(null, null, 0) );
1592 assertEquals( "abc", StringUtils.abbreviateMiddle("abc", null, 0) );
1593 assertEquals( "abc", StringUtils.abbreviateMiddle("abc", ".", 0) );
1594 assertEquals( "abc", StringUtils.abbreviateMiddle("abc", ".", 3) );
1595 assertEquals( "ab.f", StringUtils.abbreviateMiddle("abcdef", ".", 4) );
1596
1597 // JIRA issue (LANG-405) example (slightly different than actual expected result)
1598 assertEquals(
1599 "A very long text with un...f the text is complete.",
1600 StringUtils.abbreviateMiddle(
1601 "A very long text with unimportant stuff in the middle but interesting start and " +
1602 "end to see if the text is complete.", "...", 50) );
1603
1604 // Test a much longer text :)
1605 String longText = "Start text" + StringUtils.repeat("x", 10000) + "Close text";
1606 assertEquals(
1607 "Start text->Close text",
1608 StringUtils.abbreviateMiddle( longText, "->", 22 ) );
1609
1610 // Test negative length
1611 assertEquals("abc", StringUtils.abbreviateMiddle("abc", ".", -1));
1612
1613 // Test boundaries
1614 // Fails to change anything as method ensures first and last char are kept
1615 assertEquals("abc", StringUtils.abbreviateMiddle("abc", ".", 1));
1616 assertEquals("abc", StringUtils.abbreviateMiddle("abc", ".", 2));
1617
1618 // Test length of n=1
1619 assertEquals("a", StringUtils.abbreviateMiddle("a", ".", 1));
1620
1621 // Test smallest length that can lead to success
1622 assertEquals("a.d", StringUtils.abbreviateMiddle("abcd", ".", 3));
1623
1624 // More from LANG-405
1625 assertEquals("a..f", StringUtils.abbreviateMiddle("abcdef", "..", 4));
1626 assertEquals("ab.ef", StringUtils.abbreviateMiddle("abcdef", ".", 5));
1627 }
1628
1629 //-----------------------------------------------------------------------
1630 public void testDifference_StringString() {
1631 assertEquals(null, StringUtils.difference(null, null));
1632 assertEquals("", StringUtils.difference("", ""));
1633 assertEquals("abc", StringUtils.difference("", "abc"));
1634 assertEquals("", StringUtils.difference("abc", ""));
1635 assertEquals("i am a robot", StringUtils.difference(null, "i am a robot"));
1636 assertEquals("i am a machine", StringUtils.difference("i am a machine", null));
1637 assertEquals("robot", StringUtils.difference("i am a machine", "i am a robot"));
1638 assertEquals("", StringUtils.difference("abc", "abc"));
1639 assertEquals("you are a robot", StringUtils.difference("i am a robot", "you are a robot"));
1640 }
1641
1642 public void testDifferenceAt_StringString() {
1643 assertEquals(-1, StringUtils.indexOfDifference(null, null));
1644 assertEquals(0, StringUtils.indexOfDifference(null, "i am a robot"));
1645 assertEquals(-1, StringUtils.indexOfDifference("", ""));
1646 assertEquals(0, StringUtils.indexOfDifference("", "abc"));
1647 assertEquals(0, StringUtils.indexOfDifference("abc", ""));
1648 assertEquals(0, StringUtils.indexOfDifference("i am a machine", null));
1649 assertEquals(7, StringUtils.indexOfDifference("i am a machine", "i am a robot"));
1650 assertEquals(-1, StringUtils.indexOfDifference("foo", "foo"));
1651 assertEquals(0, StringUtils.indexOfDifference("i am a robot", "you are a robot"));
1652 //System.out.println("indexOfDiff: " + StringUtils.indexOfDifference("i am a robot", "not machine"));
1653 }
1654
1655 //-----------------------------------------------------------------------
1656 public void testGetLevenshteinDistance_StringString() {
1657 assertEquals(0, StringUtils.getLevenshteinDistance("", "") );
1658 assertEquals(1, StringUtils.getLevenshteinDistance("", "a") );
1659 assertEquals(7, StringUtils.getLevenshteinDistance("aaapppp", "") );
1660 assertEquals(1, StringUtils.getLevenshteinDistance("frog", "fog") );
1661 assertEquals(3, StringUtils.getLevenshteinDistance("fly", "ant") );
1662 assertEquals(7, StringUtils.getLevenshteinDistance("elephant", "hippo") );
1663 assertEquals(7, StringUtils.getLevenshteinDistance("hippo", "elephant") );
1664 assertEquals(8, StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") );
1665 assertEquals(8, StringUtils.getLevenshteinDistance("zzzzzzzz", "hippo") );
1666 assertEquals(1, StringUtils.getLevenshteinDistance("hello", "hallo") );
1667 try {
1668 @SuppressWarnings("unused")
1669 int d = StringUtils.getLevenshteinDistance("a", null);
1670 fail("expecting IllegalArgumentException");
1671 } catch (IllegalArgumentException ex) {
1672 // empty
1673 }
1674 try {
1675 @SuppressWarnings("unused")
1676 int d = StringUtils.getLevenshteinDistance(null, "a");
1677 fail("expecting IllegalArgumentException");
1678 } catch (IllegalArgumentException ex) {
1679 // empty
1680 }
1681 }
1682
1683 public void testGetLevenshteinDistance_StringStringInt() {
1684 // empty strings
1685 assertEquals(0, StringUtils.getLevenshteinDistance("", "", 0));
1686 assertEquals(7, StringUtils.getLevenshteinDistance("aaapppp", "", 8));
1687 assertEquals(7, StringUtils.getLevenshteinDistance("aaapppp", "", 7));
1688 assertEquals(-1, StringUtils.getLevenshteinDistance("aaapppp", "", 6));
1689
1690 // unequal strings, zero threshold
1691 assertEquals(-1, StringUtils.getLevenshteinDistance("b", "a", 0));
1692 assertEquals(-1, StringUtils.getLevenshteinDistance("a", "b", 0));
1693
1694 // equal strings
1695 assertEquals(0, StringUtils.getLevenshteinDistance("aa", "aa", 0));
1696 assertEquals(0, StringUtils.getLevenshteinDistance("aa", "aa", 2));
1697
1698 // same length
1699 assertEquals(-1, StringUtils.getLevenshteinDistance("aaa", "bbb", 2));
1700 assertEquals(3, StringUtils.getLevenshteinDistance("aaa", "bbb", 3));
1701
1702 // big stripe
1703 assertEquals(6, StringUtils.getLevenshteinDistance("aaaaaa", "b", 10));
1704
1705 // distance less than threshold
1706 assertEquals(7, StringUtils.getLevenshteinDistance("aaapppp", "b", 8));
1707 assertEquals(3, StringUtils.getLevenshteinDistance("a", "bbb", 4));
1708
1709 // distance equal to threshold
1710 assertEquals(7, StringUtils.getLevenshteinDistance("aaapppp", "b", 7));
1711 assertEquals(3, StringUtils.getLevenshteinDistance("a", "bbb", 3));
1712
1713 // distance greater than threshold
1714 assertEquals(-1, StringUtils.getLevenshteinDistance("a", "bbb", 2));
1715 assertEquals(-1, StringUtils.getLevenshteinDistance("bbb", "a", 2));
1716 assertEquals(-1, StringUtils.getLevenshteinDistance("aaapppp", "b", 6));
1717
1718 // stripe runs off array, strings not similar
1719 assertEquals(-1, StringUtils.getLevenshteinDistance("a", "bbb", 1));
1720 assertEquals(-1, StringUtils.getLevenshteinDistance("bbb", "a", 1));
1721
1722 // stripe runs off array, strings are similar
1723 assertEquals(-1, StringUtils.getLevenshteinDistance("12345", "1234567", 1));
1724 assertEquals(-1, StringUtils.getLevenshteinDistance("1234567", "12345", 1));
1725
1726 // old getLevenshteinDistance test cases
1727 assertEquals(1, StringUtils.getLevenshteinDistance("frog", "fog",1) );
1728 assertEquals(3, StringUtils.getLevenshteinDistance("fly", "ant",3) );
1729 assertEquals(7, StringUtils.getLevenshteinDistance("elephant", "hippo",7) );
1730 assertEquals(-1, StringUtils.getLevenshteinDistance("elephant", "hippo",6) );
1731 assertEquals(7, StringUtils.getLevenshteinDistance("hippo", "elephant",7) );
1732 assertEquals(-1, StringUtils.getLevenshteinDistance("hippo", "elephant",6) );
1733 assertEquals(8, StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz",8) );
1734 assertEquals(8, StringUtils.getLevenshteinDistance("zzzzzzzz", "hippo",8) );
1735 assertEquals(1, StringUtils.getLevenshteinDistance("hello", "hallo",1) );
1736
1737 // exceptions
1738 try {
1739 @SuppressWarnings("unused")
1740 int d = StringUtils.getLevenshteinDistance("a", null, 0);
1741 fail("expecting IllegalArgumentException");
1742 } catch (IllegalArgumentException ex) {
1743 // empty
1744 }
1745 try {
1746 @SuppressWarnings("unused")
1747 int d = StringUtils.getLevenshteinDistance(null, "a", 0);
1748 fail("expecting IllegalArgumentException");
1749 } catch (IllegalArgumentException ex) {
1750 // empty
1751 }
1752
1753 try {
1754 @SuppressWarnings("unused")
1755 int d = StringUtils.getLevenshteinDistance("a", "a", -1);
1756 fail("expecting IllegalArgumentException");
1757 } catch (IllegalArgumentException ex) {
1758 // empty
1759 }
1760 }
1761
1762 /**
1763 * A sanity check for {@link StringUtils#EMPTY}.
1764 */
1765 public void testEMPTY() {
1766 assertNotNull(StringUtils.EMPTY);
1767 assertEquals("", StringUtils.EMPTY);
1768 assertEquals(0, StringUtils.EMPTY.length());
1769 }
1770
1771 /**
1772 * Test for {@link StringUtils#isAllLowerCase(CharSequence)}.
1773 */
1774 public void testIsAllLowerCase() {
1775 assertFalse(StringUtils.isAllLowerCase(null));
1776 assertFalse(StringUtils.isAllLowerCase(StringUtils.EMPTY));
1777 assertTrue(StringUtils.isAllLowerCase("abc"));
1778 assertFalse(StringUtils.isAllLowerCase("abc "));
1779 assertFalse(StringUtils.isAllLowerCase("abC"));
1780 }
1781
1782 /**
1783 * Test for {@link StringUtils#isAllUpperCase(CharSequence)}.
1784 */
1785 public void testIsAllUpperCase() {
1786 assertFalse(StringUtils.isAllUpperCase(null));
1787 assertFalse(StringUtils.isAllUpperCase(StringUtils.EMPTY));
1788 assertTrue(StringUtils.isAllUpperCase("ABC"));
1789 assertFalse(StringUtils.isAllUpperCase("ABC "));
1790 assertFalse(StringUtils.isAllUpperCase("aBC"));
1791 }
1792
1793 public void testRemoveStart() {
1794 // StringUtils.removeStart("", *) = ""
1795 assertNull(StringUtils.removeStart(null, null));
1796 assertNull(StringUtils.removeStart(null, ""));
1797 assertNull(StringUtils.removeStart(null, "a"));
1798
1799 // StringUtils.removeStart(*, null) = *
1800 assertEquals(StringUtils.removeStart("", null), "");
1801 assertEquals(StringUtils.removeStart("", ""), "");
1802 assertEquals(StringUtils.removeStart("", "a"), "");
1803
1804 // All others:
1805 assertEquals(StringUtils.removeStart("www.domain.com", "www."), "domain.com");
1806 assertEquals(StringUtils.removeStart("domain.com", "www."), "domain.com");
1807 assertEquals(StringUtils.removeStart("domain.com", ""), "domain.com");
1808 assertEquals(StringUtils.removeStart("domain.com", null), "domain.com");
1809 }
1810
1811 public void testRemoveStartIgnoreCase() {
1812 // StringUtils.removeStart("", *) = ""
1813 assertNull("removeStartIgnoreCase(null, null)", StringUtils.removeStartIgnoreCase(null, null));
1814 assertNull("removeStartIgnoreCase(null, \"\")", StringUtils.removeStartIgnoreCase(null, ""));
1815 assertNull("removeStartIgnoreCase(null, \"a\")", StringUtils.removeStartIgnoreCase(null, "a"));
1816
1817 // StringUtils.removeStart(*, null) = *
1818 assertEquals("removeStartIgnoreCase(\"\", null)", StringUtils.removeStartIgnoreCase("", null), "");
1819 assertEquals("removeStartIgnoreCase(\"\", \"\")", StringUtils.removeStartIgnoreCase("", ""), "");
1820 assertEquals("removeStartIgnoreCase(\"\", \"a\")", StringUtils.removeStartIgnoreCase("", "a"), "");
1821
1822 // All others:
1823 assertEquals("removeStartIgnoreCase(\"www.domain.com\", \"www.\")", StringUtils.removeStartIgnoreCase("www.domain.com", "www."), "domain.com");
1824 assertEquals("removeStartIgnoreCase(\"domain.com\", \"www.\")", StringUtils.removeStartIgnoreCase("domain.com", "www."), "domain.com");
1825 assertEquals("removeStartIgnoreCase(\"domain.com\", \"\")", StringUtils.removeStartIgnoreCase("domain.com", ""), "domain.com");
1826 assertEquals("removeStartIgnoreCase(\"domain.com\", null)", StringUtils.removeStartIgnoreCase("domain.com", null), "domain.com");
1827
1828 // Case insensitive:
1829 assertEquals("removeStartIgnoreCase(\"www.domain.com\", \"WWW.\")", StringUtils.removeStartIgnoreCase("www.domain.com", "WWW."), "domain.com");
1830 }
1831
1832 public void testRemoveEnd() {
1833 // StringUtils.removeEnd("", *) = ""
1834 assertNull(StringUtils.removeEnd(null, null));
1835 assertNull(StringUtils.removeEnd(null, ""));
1836 assertNull(StringUtils.removeEnd(null, "a"));
1837
1838 // StringUtils.removeEnd(*, null) = *
1839 assertEquals(StringUtils.removeEnd("", null), "");
1840 assertEquals(StringUtils.removeEnd("", ""), "");
1841 assertEquals(StringUtils.removeEnd("", "a"), "");
1842
1843 // All others:
1844 assertEquals(StringUtils.removeEnd("www.domain.com.", ".com"), "www.domain.com.");
1845 assertEquals(StringUtils.removeEnd("www.domain.com", ".com"), "www.domain");
1846 assertEquals(StringUtils.removeEnd("www.domain", ".com"), "www.domain");
1847 assertEquals(StringUtils.removeEnd("domain.com", ""), "domain.com");
1848 assertEquals(StringUtils.removeEnd("domain.com", null), "domain.com");
1849 }
1850
1851 public void testRemoveEndIgnoreCase() {
1852 // StringUtils.removeEndIgnoreCase("", *) = ""
1853 assertNull("removeEndIgnoreCase(null, null)", StringUtils.removeEndIgnoreCase(null, null));
1854 assertNull("removeEndIgnoreCase(null, \"\")", StringUtils.removeEndIgnoreCase(null, ""));
1855 assertNull("removeEndIgnoreCase(null, \"a\")", StringUtils.removeEndIgnoreCase(null, "a"));
1856
1857 // StringUtils.removeEnd(*, null) = *
1858 assertEquals("removeEndIgnoreCase(\"\", null)", StringUtils.removeEndIgnoreCase("", null), "");
1859 assertEquals("removeEndIgnoreCase(\"\", \"\")", StringUtils.removeEndIgnoreCase("", ""), "");
1860 assertEquals("removeEndIgnoreCase(\"\", \"a\")", StringUtils.removeEndIgnoreCase("", "a"), "");
1861
1862 // All others:
1863 assertEquals("removeEndIgnoreCase(\"www.domain.com.\", \".com\")", StringUtils.removeEndIgnoreCase("www.domain.com.", ".com"), "www.domain.com.");
1864 assertEquals("removeEndIgnoreCase(\"www.domain.com\", \".com\")", StringUtils.removeEndIgnoreCase("www.domain.com", ".com"), "www.domain");
1865 assertEquals("removeEndIgnoreCase(\"www.domain\", \".com\")", StringUtils.removeEndIgnoreCase("www.domain", ".com"), "www.domain");
1866 assertEquals("removeEndIgnoreCase(\"domain.com\", \"\")", StringUtils.removeEndIgnoreCase("domain.com", ""), "domain.com");
1867 assertEquals("removeEndIgnoreCase(\"domain.com\", null)", StringUtils.removeEndIgnoreCase("domain.com", null), "domain.com");
1868
1869 // Case insensitive:
1870 assertEquals("removeEndIgnoreCase(\"www.domain.com\", \".COM\")", StringUtils.removeEndIgnoreCase("www.domain.com", ".COM"), "www.domain");
1871 assertEquals("removeEndIgnoreCase(\"www.domain.COM\", \".com\")", StringUtils.removeEndIgnoreCase("www.domain.COM", ".com"), "www.domain");
1872 }
1873
1874 public void testRemove_String() {
1875 // StringUtils.remove(null, *) = null
1876 assertEquals(null, StringUtils.remove(null, null));
1877 assertEquals(null, StringUtils.remove(null, ""));
1878 assertEquals(null, StringUtils.remove(null, "a"));
1879
1880 // StringUtils.remove("", *) = ""
1881 assertEquals("", StringUtils.remove("", null));
1882 assertEquals("", StringUtils.remove("", ""));
1883 assertEquals("", StringUtils.remove("", "a"));
1884
1885 // StringUtils.remove(*, null) = *
1886 assertEquals(null, StringUtils.remove(null, null));
1887 assertEquals("", StringUtils.remove("", null));
1888 assertEquals("a", StringUtils.remove("a", null));
1889
1890 // StringUtils.remove(*, "") = *
1891 assertEquals(null, StringUtils.remove(null, ""));
1892 assertEquals("", StringUtils.remove("", ""));
1893 assertEquals("a", StringUtils.remove("a", ""));
1894
1895 // StringUtils.remove("queued", "ue") = "qd"
1896 assertEquals("qd", StringUtils.remove("queued", "ue"));
1897
1898 // StringUtils.remove("queued", "zz") = "queued"
1899 assertEquals("queued", StringUtils.remove("queued", "zz"));
1900 }
1901
1902 public void testRemove_char() {
1903 // StringUtils.remove(null, *) = null
1904 assertEquals(null, StringUtils.remove(null, 'a'));
1905 assertEquals(null, StringUtils.remove(null, 'a'));
1906 assertEquals(null, StringUtils.remove(null, 'a'));
1907
1908 // StringUtils.remove("", *) = ""
1909 assertEquals("", StringUtils.remove("", 'a'));
1910 assertEquals("", StringUtils.remove("", 'a'));
1911 assertEquals("", StringUtils.remove("", 'a'));
1912
1913 // StringUtils.remove("queued", 'u') = "qeed"
1914 assertEquals("qeed", StringUtils.remove("queued", 'u'));
1915
1916 // StringUtils.remove("queued", 'z') = "queued"
1917 assertEquals("queued", StringUtils.remove("queued", 'z'));
1918 }
1919
1920 public void testDifferenceAt_StringArray(){
1921 assertEquals(-1, StringUtils.indexOfDifference((String[])null));
1922 assertEquals(-1, StringUtils.indexOfDifference(new String[] {}));
1923 assertEquals(-1, StringUtils.indexOfDifference(new String[] {"abc"}));
1924 assertEquals(-1, StringUtils.indexOfDifference(new String[] {null, null}));
1925 assertEquals(-1, StringUtils.indexOfDifference(new String[] {"", ""}));
1926 assertEquals(0, StringUtils.indexOfDifference(new String[] {"", null}));
1927 assertEquals(0, StringUtils.indexOfDifference(new String[] {"abc", null, null}));
1928 assertEquals(0, StringUtils.indexOfDifference(new String[] {null, null, "abc"}));
1929 assertEquals(0, StringUtils.indexOfDifference(new String[] {"", "abc"}));
1930 assertEquals(0, StringUtils.indexOfDifference(new String[] {"abc", ""}));
1931 assertEquals(-1, StringUtils.indexOfDifference(new String[] {"abc", "abc"}));
1932 assertEquals(1, StringUtils.indexOfDifference(new String[] {"abc", "a"}));
1933 assertEquals(2, StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}));
1934 assertEquals(2, StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}));
1935 assertEquals(0, StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}));
1936 assertEquals(0, StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}));
1937 assertEquals(7, StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}));
1938 }
1939
1940 public void testGetCommonPrefix_StringArray(){
1941 assertEquals("", StringUtils.getCommonPrefix((String[])null));
1942 assertEquals("", StringUtils.getCommonPrefix());
1943 assertEquals("abc", StringUtils.getCommonPrefix("abc"));
1944 assertEquals("", StringUtils.getCommonPrefix(null, null));
1945 assertEquals("", StringUtils.getCommonPrefix("", ""));
1946 assertEquals("", StringUtils.getCommonPrefix("", null));
1947 assertEquals("", StringUtils.getCommonPrefix("abc", null, null));
1948 assertEquals("", StringUtils.getCommonPrefix(null, null, "abc"));
1949 assertEquals("", StringUtils.getCommonPrefix("", "abc"));
1950 assertEquals("", StringUtils.getCommonPrefix("abc", ""));
1951 assertEquals("abc", StringUtils.getCommonPrefix("abc", "abc"));
1952 assertEquals("a", StringUtils.getCommonPrefix("abc", "a"));
1953 assertEquals("ab", StringUtils.getCommonPrefix("ab", "abxyz"));
1954 assertEquals("ab", StringUtils.getCommonPrefix("abcde", "abxyz"));
1955 assertEquals("", StringUtils.getCommonPrefix("abcde", "xyz"));
1956 assertEquals("", StringUtils.getCommonPrefix("xyz", "abcde"));
1957 assertEquals("i am a ", StringUtils.getCommonPrefix("i am a machine", "i am a robot"));
1958 }
1959
1960 public void testNormalizeSpace() {
1961 assertEquals(null, StringUtils.normalizeSpace(null));
1962 assertEquals("", StringUtils.normalizeSpace(""));
1963 assertEquals("", StringUtils.normalizeSpace(" "));
1964 assertEquals("", StringUtils.normalizeSpace("\t"));
1965 assertEquals("", StringUtils.normalizeSpace("\n"));
1966 assertEquals("", StringUtils.normalizeSpace("\u0009"));
1967 assertEquals("", StringUtils.normalizeSpace("\u000B"));
1968 assertEquals("", StringUtils.normalizeSpace("\u000C"));
1969 assertEquals("", StringUtils.normalizeSpace("\u001C"));
1970 assertEquals("", StringUtils.normalizeSpace("\u001D"));
1971 assertEquals("", StringUtils.normalizeSpace("\u001E"));
1972 assertEquals("", StringUtils.normalizeSpace("\u001F"));
1973 assertEquals("", StringUtils.normalizeSpace("\f"));
1974 assertEquals("", StringUtils.normalizeSpace("\r"));
1975 assertEquals("a", StringUtils.normalizeSpace(" a "));
1976 assertEquals("a b c", StringUtils.normalizeSpace(" a b c "));
1977 assertEquals("a b c", StringUtils.normalizeSpace("a\t\f\r b\u000B c\n"));
1978 }
1979
1980 public void testLANG666() {
1981 assertEquals("12",StringUtils.stripEnd("120.00", ".0"));
1982 assertEquals("121",StringUtils.stripEnd("121.00", ".0"));
1983 }
1984
1985 // Methods on StringUtils that are immutable in spirit (i.e. calculate the length)
1986 // should take a CharSequence parameter. Methods that are mutable in spirit (i.e. capitalize)
1987 // should take a String or String[] parameter and return String or String[].
1988 // This test enforces that this is done.
1989 public void testStringUtilsCharSequenceContract() {
1990 Class<StringUtils> c = StringUtils.class;
1991 Method[] methods = c.getMethods();
1992 for (Method m : methods) {
1993 if (m.getReturnType() == String.class || m.getReturnType() == String[].class) {
1994 // Assume this is mutable and ensure the first parameter is not CharSequence.
1995 // It may be String or it may be something else (String[], Object, Object[]) so
1996 // don't actively test for that.
1997 Class<?>[] params = m.getParameterTypes();
1998 if ( params.length > 0 && (params[0] == CharSequence.class || params[0] == CharSequence[].class)) {
1999 fail("The method " + m + " appears to be mutable in spirit and therefore must not accept a CharSequence");
2000 }
2001 } else {
2002 // Assume this is immutable in spirit and ensure the first parameter is not String.
2003 // As above, it may be something other than CharSequence.
2004 Class<?>[] params = m.getParameterTypes();
2005 if ( params.length > 0 && (params[0] == String.class || params[0] == String[].class)) {
2006 fail("The method " + m + " appears to be immutable in spirit and therefore must not accept a String");
2007 }
2008 }
2009 }
2010 }
2011 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3;
17
18 import junit.framework.TestCase;
19
20 /**
21 * Unit tests {@link org.apache.commons.lang3.StringUtils} - Trim/Empty methods
22 *
23 * @version $Id: StringUtilsTrimEmptyTest.java 1132845 2011-06-07 00:50:50Z sebb $
24 */
25 public class StringUtilsTrimEmptyTest extends TestCase {
26 private static final String FOO = "foo";
27
28 public StringUtilsTrimEmptyTest(String name) {
29 super(name);
30 }
31
32 //-----------------------------------------------------------------------
33 public void testIsEmpty() {
34 assertEquals(true, StringUtils.isEmpty(null));
35 assertEquals(true, StringUtils.isEmpty(""));
36 assertEquals(false, StringUtils.isEmpty(" "));
37 assertEquals(false, StringUtils.isEmpty("foo"));
38 assertEquals(false, StringUtils.isEmpty(" foo "));
39 }
40
41 public void testIsNotEmpty() {
42 assertEquals(false, StringUtils.isNotEmpty(null));
43 assertEquals(false, StringUtils.isNotEmpty(""));
44 assertEquals(true, StringUtils.isNotEmpty(" "));
45 assertEquals(true, StringUtils.isNotEmpty("foo"));
46 assertEquals(true, StringUtils.isNotEmpty(" foo "));
47 }
48
49 public void testIsBlank() {
50 assertEquals(true, StringUtils.isBlank(null));
51 assertEquals(true, StringUtils.isBlank(""));
52 assertEquals(true, StringUtils.isBlank(StringUtilsTest.WHITESPACE));
53 assertEquals(false, StringUtils.isBlank("foo"));
54 assertEquals(false, StringUtils.isBlank(" foo "));
55 }
56
57 public void testIsNotBlank() {
58 assertEquals(false, StringUtils.isNotBlank(null));
59 assertEquals(false, StringUtils.isNotBlank(""));
60 assertEquals(false, StringUtils.isNotBlank(StringUtilsTest.WHITESPACE));
61 assertEquals(true, StringUtils.isNotBlank("foo"));
62 assertEquals(true, StringUtils.isNotBlank(" foo "));
63 }
64
65 //-----------------------------------------------------------------------
66 public void testTrim() {
67 assertEquals(FOO, StringUtils.trim(FOO + " "));
68 assertEquals(FOO, StringUtils.trim(" " + FOO + " "));
69 assertEquals(FOO, StringUtils.trim(" " + FOO));
70 assertEquals(FOO, StringUtils.trim(FOO + ""));
71 assertEquals("", StringUtils.trim(" \t\r\n\b "));
72 assertEquals("", StringUtils.trim(StringUtilsTest.TRIMMABLE));
73 assertEquals(StringUtilsTest.NON_TRIMMABLE, StringUtils.trim(StringUtilsTest.NON_TRIMMABLE));
74 assertEquals("", StringUtils.trim(""));
75 assertEquals(null, StringUtils.trim(null));
76 }
77
78 public void testTrimToNull() {
79 assertEquals(FOO, StringUtils.trimToNull(FOO + " "));
80 assertEquals(FOO, StringUtils.trimToNull(" " + FOO + " "));
81 assertEquals(FOO, StringUtils.trimToNull(" " + FOO));
82 assertEquals(FOO, StringUtils.trimToNull(FOO + ""));
83 assertEquals(null, StringUtils.trimToNull(" \t\r\n\b "));
84 assertEquals(null, StringUtils.trimToNull(StringUtilsTest.TRIMMABLE));
85 assertEquals(StringUtilsTest.NON_TRIMMABLE, StringUtils.trimToNull(StringUtilsTest.NON_TRIMMABLE));
86 assertEquals(null, StringUtils.trimToNull(""));
87 assertEquals(null, StringUtils.trimToNull(null));
88 }
89
90 public void testTrimToEmpty() {
91 assertEquals(FOO, StringUtils.trimToEmpty(FOO + " "));
92 assertEquals(FOO, StringUtils.trimToEmpty(" " + FOO + " "));
93 assertEquals(FOO, StringUtils.trimToEmpty(" " + FOO));
94 assertEquals(FOO, StringUtils.trimToEmpty(FOO + ""));
95 assertEquals("", StringUtils.trimToEmpty(" \t\r\n\b "));
96 assertEquals("", StringUtils.trimToEmpty(StringUtilsTest.TRIMMABLE));
97 assertEquals(StringUtilsTest.NON_TRIMMABLE, StringUtils.trimToEmpty(StringUtilsTest.NON_TRIMMABLE));
98 assertEquals("", StringUtils.trimToEmpty(""));
99 assertEquals("", StringUtils.trimToEmpty(null));
100 }
101
102 //-----------------------------------------------------------------------
103 public void testStrip_String() {
104 assertEquals(null, StringUtils.strip(null));
105 assertEquals("", StringUtils.strip(""));
106 assertEquals("", StringUtils.strip(" "));
107 assertEquals("abc", StringUtils.strip(" abc "));
108 assertEquals(StringUtilsTest.NON_WHITESPACE,
109 StringUtils.strip(StringUtilsTest.WHITESPACE + StringUtilsTest.NON_WHITESPACE + StringUtilsTest.WHITESPACE));
110 }
111
112 public void testStripToNull_String() {
113 assertEquals(null, StringUtils.stripToNull(null));
114 assertEquals(null, StringUtils.stripToNull(""));
115 assertEquals(null, StringUtils.stripToNull(" "));
116 assertEquals(null, StringUtils.stripToNull(StringUtilsTest.WHITESPACE));
117 assertEquals("ab c", StringUtils.stripToNull(" ab c "));
118 assertEquals(StringUtilsTest.NON_WHITESPACE,
119 StringUtils.stripToNull(StringUtilsTest.WHITESPACE + StringUtilsTest.NON_WHITESPACE + StringUtilsTest.WHITESPACE));
120 }
121
122 public void testStripToEmpty_String() {
123 assertEquals("", StringUtils.stripToEmpty(null));
124 assertEquals("", StringUtils.stripToEmpty(""));
125 assertEquals("", StringUtils.stripToEmpty(" "));
126 assertEquals("", StringUtils.stripToEmpty(StringUtilsTest.WHITESPACE));
127 assertEquals("ab c", StringUtils.stripToEmpty(" ab c "));
128 assertEquals(StringUtilsTest.NON_WHITESPACE,
129 StringUtils.stripToEmpty(StringUtilsTest.WHITESPACE + StringUtilsTest.NON_WHITESPACE + StringUtilsTest.WHITESPACE));
130 }
131
132 public void testStrip_StringString() {
133 // null strip
134 assertEquals(null, StringUtils.strip(null, null));
135 assertEquals("", StringUtils.strip("", null));
136 assertEquals("", StringUtils.strip(" ", null));
137 assertEquals("abc", StringUtils.strip(" abc ", null));
138 assertEquals(StringUtilsTest.NON_WHITESPACE,
139 StringUtils.strip(StringUtilsTest.WHITESPACE + StringUtilsTest.NON_WHITESPACE + StringUtilsTest.WHITESPACE, null));
140
141 // "" strip
142 assertEquals(null, StringUtils.strip(null, ""));
143 assertEquals("", StringUtils.strip("", ""));
144 assertEquals(" ", StringUtils.strip(" ", ""));
145 assertEquals(" abc ", StringUtils.strip(" abc ", ""));
146 assertEquals(StringUtilsTest.WHITESPACE, StringUtils.strip(StringUtilsTest.WHITESPACE, ""));
147
148 // " " strip
149 assertEquals(null, StringUtils.strip(null, " "));
150 assertEquals("", StringUtils.strip("", " "));
151 assertEquals("", StringUtils.strip(" ", " "));
152 assertEquals("abc", StringUtils.strip(" abc ", " "));
153
154 // "ab" strip
155 assertEquals(null, StringUtils.strip(null, "ab"));
156 assertEquals("", StringUtils.strip("", "ab"));
157 assertEquals(" ", StringUtils.strip(" ", "ab"));
158 assertEquals(" abc ", StringUtils.strip(" abc ", "ab"));
159 assertEquals("c", StringUtils.strip("abcabab", "ab"));
160 assertEquals(StringUtilsTest.WHITESPACE, StringUtils.strip(StringUtilsTest.WHITESPACE, ""));
161 }
162
163 public void testStripStart_StringString() {
164 // null stripStart
165 assertEquals(null, StringUtils.stripStart(null, null));
166 assertEquals("", StringUtils.stripStart("", null));
167 assertEquals("", StringUtils.stripStart(" ", null));
168 assertEquals("abc ", StringUtils.stripStart(" abc ", null));
169 assertEquals(StringUtilsTest.NON_WHITESPACE + StringUtilsTest.WHITESPACE,
170 StringUtils.stripStart(StringUtilsTest.WHITESPACE + StringUtilsTest.NON_WHITESPACE + StringUtilsTest.WHITESPACE, null));
171
172 // "" stripStart
173 assertEquals(null, StringUtils.stripStart(null, ""));
174 assertEquals("", StringUtils.stripStart("", ""));
175 assertEquals(" ", StringUtils.stripStart(" ", ""));
176 assertEquals(" abc ", StringUtils.stripStart(" abc ", ""));
177 assertEquals(StringUtilsTest.WHITESPACE, StringUtils.stripStart(StringUtilsTest.WHITESPACE, ""));
178
179 // " " stripStart
180 assertEquals(null, StringUtils.stripStart(null, " "));
181 assertEquals("", StringUtils.stripStart("", " "));
182 assertEquals("", StringUtils.stripStart(" ", " "));
183 assertEquals("abc ", StringUtils.stripStart(" abc ", " "));
184
185 // "ab" stripStart
186 assertEquals(null, StringUtils.stripStart(null, "ab"));
187 assertEquals("", StringUtils.stripStart("", "ab"));
188 assertEquals(" ", StringUtils.stripStart(" ", "ab"));
189 assertEquals(" abc ", StringUtils.stripStart(" abc ", "ab"));
190 assertEquals("cabab", StringUtils.stripStart("abcabab", "ab"));
191 assertEquals(StringUtilsTest.WHITESPACE, StringUtils.stripStart(StringUtilsTest.WHITESPACE, ""));
192 }
193
194 public void testStripEnd_StringString() {
195 // null stripEnd
196 assertEquals(null, StringUtils.stripEnd(null, null));
197 assertEquals("", StringUtils.stripEnd("", null));
198 assertEquals("", StringUtils.stripEnd(" ", null));
199 assertEquals(" abc", StringUtils.stripEnd(" abc ", null));
200 assertEquals(StringUtilsTest.WHITESPACE + StringUtilsTest.NON_WHITESPACE,
201 StringUtils.stripEnd(StringUtilsTest.WHITESPACE + StringUtilsTest.NON_WHITESPACE + StringUtilsTest.WHITESPACE, null));
202
203 // "" stripEnd
204 assertEquals(null, StringUtils.stripEnd(null, ""));
205 assertEquals("", StringUtils.stripEnd("", ""));
206 assertEquals(" ", StringUtils.stripEnd(" ", ""));
207 assertEquals(" abc ", StringUtils.stripEnd(" abc ", ""));
208 assertEquals(StringUtilsTest.WHITESPACE, StringUtils.stripEnd(StringUtilsTest.WHITESPACE, ""));
209
210 // " " stripEnd
211 assertEquals(null, StringUtils.stripEnd(null, " "));
212 assertEquals("", StringUtils.stripEnd("", " "));
213 assertEquals("", StringUtils.stripEnd(" ", " "));
214 assertEquals(" abc", StringUtils.stripEnd(" abc ", " "));
215
216 // "ab" stripEnd
217 assertEquals(null, StringUtils.stripEnd(null, "ab"));
218 assertEquals("", StringUtils.stripEnd("", "ab"));
219 assertEquals(" ", StringUtils.stripEnd(" ", "ab"));
220 assertEquals(" abc ", StringUtils.stripEnd(" abc ", "ab"));
221 assertEquals("abc", StringUtils.stripEnd("abcabab", "ab"));
222 assertEquals(StringUtilsTest.WHITESPACE, StringUtils.stripEnd(StringUtilsTest.WHITESPACE, ""));
223 }
224
225 public void testStripAll() {
226 // test stripAll method, merely an array version of the above strip
227 String[] empty = new String[0];
228 String[] fooSpace = new String[] { " "+FOO+" ", " "+FOO, FOO+" " };
229 String[] fooDots = new String[] { ".."+FOO+"..", ".."+FOO, FOO+".." };
230 String[] foo = new String[] { FOO, FOO, FOO };
231
232 // assertEquals(null, StringUtils.stripAll(null)); // generates warning
233 assertEquals(null, StringUtils.stripAll((String[]) null)); // equivalent explicit cast
234 // Additional varargs tests
235 assertArrayEquals(empty, StringUtils.stripAll()); // empty array
236 assertArrayEquals(new String[]{null}, StringUtils.stripAll((String) null)); // == new String[]{null}
237
238 assertArrayEquals(empty, StringUtils.stripAll(empty));
239 assertArrayEquals(foo, StringUtils.stripAll(fooSpace));
240
241 assertEquals(null, StringUtils.stripAll(null, null));
242 assertArrayEquals(foo, StringUtils.stripAll(fooSpace, null));
243 assertArrayEquals(foo, StringUtils.stripAll(fooDots, "."));
244 }
245
246 public void testStripAccents() {
247 String cue = "\u00C7\u00FA\u00EA";
248 assertEquals( "Failed to strip accents from " + cue, "Cue", StringUtils.stripAccents(cue));
249
250 String lots = "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C7\u00C8\u00C9" +
251 "\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D1\u00D2\u00D3" +
252 "\u00D4\u00D5\u00D6\u00D9\u00DA\u00DB\u00DC\u00DD";
253 assertEquals( "Failed to strip accents from " + lots,
254 "AAAAAACEEEEIIIINOOOOOUUUUY",
255 StringUtils.stripAccents(lots));
256
257 assertNull( "Failed null safety", StringUtils.stripAccents(null) );
258 assertEquals( "Failed empty String", "", StringUtils.stripAccents("") );
259 assertEquals( "Failed to handle non-accented text", "control", StringUtils.stripAccents("control") );
260 assertEquals( "Failed to handle easy example", "eclair", StringUtils.stripAccents("\u00E9clair") );
261 }
262
263 //-----------------------------------------------------------------------
264
265 private void assertArrayEquals(Object[] o1, Object[] o2) {
266 if(o1 == null) {
267 assertEquals(o1,o2);
268 return;
269 }
270 assertEquals("Length not equal. ", o1.length, o2.length);
271 int sz = o1.length;
272 for(int i=0; i<sz; i++) {
273 if(o1[i] instanceof Object[]) {
274 // do an assert equals on type....
275 assertArrayEquals( (Object[]) o1[i], (Object[]) o2[i] );
276 } else {
277 assertEquals(o1[i], o2[i]);
278 }
279 }
280 }
281
282 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one
2 * or more contributor license agreements. See the NOTICE file
3 * distributed with this work for additional information
4 * regarding copyright ownership. The ASF licenses this file
5 * to you under the Apache License, Version 2.0 (the
6 * "License"); you may not use this file except in compliance
7 * with the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18
19 package org.apache.commons.lang3;
20
21 import static org.apache.commons.lang3.JavaVersion.JAVA_1_4;
22
23 import java.io.File;
24 import java.lang.reflect.Constructor;
25 import java.lang.reflect.Modifier;
26 import java.util.Locale;
27
28 import junit.framework.Assert;
29 import junit.framework.TestCase;
30
31 /**
32 * Unit tests {@link org.apache.commons.lang3.SystemUtils}.
33 *
34 * Only limited testing can be performed.
35 *
36 * @version $Id: SystemUtilsTest.java 1144929 2011-07-10 18:26:16Z ggregory $
37 */
38 public class SystemUtilsTest extends TestCase {
39
40 public SystemUtilsTest(String name) {
41 super(name);
42 }
43
44 public void testConstructor() {
45 assertNotNull(new SystemUtils());
46 Constructor<?>[] cons = SystemUtils.class.getDeclaredConstructors();
47 assertEquals(1, cons.length);
48 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
49 assertEquals(true, Modifier.isPublic(SystemUtils.class.getModifiers()));
50 assertEquals(false, Modifier.isFinal(SystemUtils.class.getModifiers()));
51 }
52
53 /**
54 * Assums no security manager exists.
55 */
56 public void testGetJavaHome() {
57 File dir = SystemUtils.getJavaHome();
58 Assert.assertNotNull(dir);
59 Assert.assertTrue(dir.exists());
60 }
61
62 /**
63 * Assums no security manager exists.
64 */
65 public void testGetJavaIoTmpDir() {
66 File dir = SystemUtils.getJavaIoTmpDir();
67 Assert.assertNotNull(dir);
68 Assert.assertTrue(dir.exists());
69 }
70
71 /**
72 * Assums no security manager exists.
73 */
74 public void testGetUserDir() {
75 File dir = SystemUtils.getUserDir();
76 Assert.assertNotNull(dir);
77 Assert.assertTrue(dir.exists());
78 }
79
80 /**
81 * Assums no security manager exists.
82 */
83 public void testGetUserHome() {
84 File dir = SystemUtils.getUserHome();
85 Assert.assertNotNull(dir);
86 Assert.assertTrue(dir.exists());
87 }
88
89 public void testIS_JAVA() {
90 String javaVersion = System.getProperty("java.version");
91 if (javaVersion == null) {
92 assertEquals(false, SystemUtils.IS_JAVA_1_1);
93 assertEquals(false, SystemUtils.IS_JAVA_1_2);
94 assertEquals(false, SystemUtils.IS_JAVA_1_3);
95 assertEquals(false, SystemUtils.IS_JAVA_1_4);
96 assertEquals(false, SystemUtils.IS_JAVA_1_5);
97 assertEquals(false, SystemUtils.IS_JAVA_1_6);
98 assertEquals(false, SystemUtils.IS_JAVA_1_7);
99 } else if (javaVersion.startsWith("1.1")) {
100 assertEquals(true, SystemUtils.IS_JAVA_1_1);
101 assertEquals(false, SystemUtils.IS_JAVA_1_2);
102 assertEquals(false, SystemUtils.IS_JAVA_1_3);
103 assertEquals(false, SystemUtils.IS_JAVA_1_4);
104 assertEquals(false, SystemUtils.IS_JAVA_1_5);
105 assertEquals(false, SystemUtils.IS_JAVA_1_6);
106 assertEquals(false, SystemUtils.IS_JAVA_1_7);
107 } else if (javaVersion.startsWith("1.2")) {
108 assertEquals(false, SystemUtils.IS_JAVA_1_1);
109 assertEquals(true, SystemUtils.IS_JAVA_1_2);
110 assertEquals(false, SystemUtils.IS_JAVA_1_3);
111 assertEquals(false, SystemUtils.IS_JAVA_1_4);
112 assertEquals(false, SystemUtils.IS_JAVA_1_5);
113 assertEquals(false, SystemUtils.IS_JAVA_1_6);
114 assertEquals(false, SystemUtils.IS_JAVA_1_7);
115 } else if (javaVersion.startsWith("1.3")) {
116 assertEquals(false, SystemUtils.IS_JAVA_1_1);
117 assertEquals(false, SystemUtils.IS_JAVA_1_2);
118 assertEquals(true, SystemUtils.IS_JAVA_1_3);
119 assertEquals(false, SystemUtils.IS_JAVA_1_4);
120 assertEquals(false, SystemUtils.IS_JAVA_1_5);
121 assertEquals(false, SystemUtils.IS_JAVA_1_6);
122 assertEquals(false, SystemUtils.IS_JAVA_1_7);
123 } else if (javaVersion.startsWith("1.4")) {
124 assertEquals(false, SystemUtils.IS_JAVA_1_1);
125 assertEquals(false, SystemUtils.IS_JAVA_1_2);
126 assertEquals(false, SystemUtils.IS_JAVA_1_3);
127 assertEquals(true, SystemUtils.IS_JAVA_1_4);
128 assertEquals(false, SystemUtils.IS_JAVA_1_5);
129 assertEquals(false, SystemUtils.IS_JAVA_1_6);
130 assertEquals(false, SystemUtils.IS_JAVA_1_7);
131 } else if (javaVersion.startsWith("1.5")) {
132 assertEquals(false, SystemUtils.IS_JAVA_1_1);
133 assertEquals(false, SystemUtils.IS_JAVA_1_2);
134 assertEquals(false, SystemUtils.IS_JAVA_1_3);
135 assertEquals(false, SystemUtils.IS_JAVA_1_4);
136 assertEquals(true, SystemUtils.IS_JAVA_1_5);
137 assertEquals(false, SystemUtils.IS_JAVA_1_6);
138 assertEquals(false, SystemUtils.IS_JAVA_1_7);
139 } else if (javaVersion.startsWith("1.6")) {
140 assertEquals(false, SystemUtils.IS_JAVA_1_1);
141 assertEquals(false, SystemUtils.IS_JAVA_1_2);
142 assertEquals(false, SystemUtils.IS_JAVA_1_3);
143 assertEquals(false, SystemUtils.IS_JAVA_1_4);
144 assertEquals(false, SystemUtils.IS_JAVA_1_5);
145 assertEquals(true, SystemUtils.IS_JAVA_1_6);
146 assertEquals(false, SystemUtils.IS_JAVA_1_7);
147 } else {
148 System.out.println("Can't test IS_JAVA value");
149 }
150 }
151
152 public void testIS_OS() {
153 String osName = System.getProperty("os.name");
154 if (osName == null) {
155 assertEquals(false, SystemUtils.IS_OS_WINDOWS);
156 assertEquals(false, SystemUtils.IS_OS_UNIX);
157 assertEquals(false, SystemUtils.IS_OS_SOLARIS);
158 assertEquals(false, SystemUtils.IS_OS_LINUX);
159 assertEquals(false, SystemUtils.IS_OS_MAC_OSX);
160 } else if (osName.startsWith("Windows")) {
161 assertEquals(false, SystemUtils.IS_OS_UNIX);
162 assertEquals(true, SystemUtils.IS_OS_WINDOWS);
163 } else if (osName.startsWith("Solaris")) {
164 assertEquals(true, SystemUtils.IS_OS_SOLARIS);
165 assertEquals(true, SystemUtils.IS_OS_UNIX);
166 assertEquals(false, SystemUtils.IS_OS_WINDOWS);
167 } else if (osName.toLowerCase(Locale.ENGLISH).startsWith("linux")) {
168 assertEquals(true, SystemUtils.IS_OS_LINUX);
169 assertEquals(true, SystemUtils.IS_OS_UNIX);
170 assertEquals(false, SystemUtils.IS_OS_WINDOWS);
171 } else if (osName.startsWith("Mac OS X")) {
172 assertEquals(true, SystemUtils.IS_OS_MAC_OSX);
173 assertEquals(true, SystemUtils.IS_OS_UNIX);
174 assertEquals(false, SystemUtils.IS_OS_WINDOWS);
175 } else if (osName.startsWith("OS/2")) {
176 assertEquals(true, SystemUtils.IS_OS_OS2);
177 assertEquals(false, SystemUtils.IS_OS_UNIX);
178 assertEquals(false, SystemUtils.IS_OS_WINDOWS);
179 } else if (osName.startsWith("SunOS")) {
180 assertEquals(true, SystemUtils.IS_OS_SUN_OS);
181 assertEquals(true, SystemUtils.IS_OS_UNIX);
182 assertEquals(false, SystemUtils.IS_OS_WINDOWS);
183 } else {
184 System.out.println("Can't test IS_OS value");
185 }
186 }
187
188 public void testJavaVersionMatches() {
189 String javaVersion = null;
190 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
191 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
192 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
193 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
194 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
195 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
196 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
197 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
198 javaVersion = "";
199 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
200 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
201 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
202 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
203 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
204 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
205 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
206 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
207 javaVersion = "1.0";
208 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
209 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
210 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
211 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
212 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
213 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
214 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
215 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
216 javaVersion = "1.1";
217 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
218 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
219 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
220 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
221 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
222 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
223 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
224 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
225 javaVersion = "1.2";
226 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
227 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
228 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
229 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
230 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
231 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
232 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
233 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
234 javaVersion = "1.3.0";
235 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
236 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
237 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
238 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
239 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
240 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
241 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
242 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
243 javaVersion = "1.3.1";
244 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
245 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
246 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
247 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
248 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
249 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
250 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
251 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
252 javaVersion = "1.4.0";
253 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
254 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
255 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
256 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
257 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
258 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
259 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
260 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
261 javaVersion = "1.4.1";
262 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
263 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
264 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
265 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
266 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
267 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
268 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
269 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
270 javaVersion = "1.4.2";
271 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
272 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
273 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
274 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
275 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
276 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
277 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
278 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
279 javaVersion = "1.5.0";
280 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
281 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
282 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
283 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
284 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
285 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
286 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
287 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
288 javaVersion = "1.6.0";
289 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
290 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
291 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
292 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
293 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
294 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
295 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
296 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
297 javaVersion = "1.7.0";
298 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.0"));
299 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.1"));
300 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.2"));
301 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.3"));
302 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.4"));
303 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.5"));
304 assertEquals(false, SystemUtils.isJavaVersionMatch(javaVersion, "1.6"));
305 assertEquals(true, SystemUtils.isJavaVersionMatch(javaVersion, "1.7"));
306 }
307
308 public void testOSMatchesName() {
309 String osName = null;
310 assertEquals(false, SystemUtils.isOSNameMatch(osName, "Windows"));
311 osName = "";
312 assertEquals(false, SystemUtils.isOSNameMatch(osName, "Windows"));
313 osName = "Windows 95";
314 assertEquals(true, SystemUtils.isOSNameMatch(osName, "Windows"));
315 osName = "Windows NT";
316 assertEquals(true, SystemUtils.isOSNameMatch(osName, "Windows"));
317 osName = "OS/2";
318 assertEquals(false, SystemUtils.isOSNameMatch(osName, "Windows"));
319 }
320
321 public void testOSMatchesNameAndVersion() {
322 String osName = null;
323 String osVersion = null;
324 assertEquals(false, SystemUtils.isOSMatch(osName, osVersion, "Windows 9", "4.1"));
325 osName = "";
326 osVersion = "";
327 assertEquals(false, SystemUtils.isOSMatch(osName, osVersion, "Windows 9", "4.1"));
328 osName = "Windows 95";
329 osVersion = "4.0";
330 assertEquals(false, SystemUtils.isOSMatch(osName, osVersion, "Windows 9", "4.1"));
331 osName = "Windows 95";
332 osVersion = "4.1";
333 assertEquals(true, SystemUtils.isOSMatch(osName, osVersion, "Windows 9", "4.1"));
334 osName = "Windows 98";
335 osVersion = "4.1";
336 assertEquals(true, SystemUtils.isOSMatch(osName, osVersion, "Windows 9", "4.1"));
337 osName = "Windows NT";
338 osVersion = "4.0";
339 assertEquals(false, SystemUtils.isOSMatch(osName, osVersion, "Windows 9", "4.1"));
340 osName = "OS/2";
341 osVersion = "4.0";
342 assertEquals(false, SystemUtils.isOSMatch(osName, osVersion, "Windows 9", "4.1"));
343 }
344
345 public void testJavaAwtHeadless() {
346 boolean atLeastJava14 = SystemUtils.isJavaVersionAtLeast(JAVA_1_4);
347 String expectedStringValue = System.getProperty("java.awt.headless");
348 String expectedStringValueWithDefault = System.getProperty("java.awt.headless", "false");
349 assertNotNull(expectedStringValueWithDefault);
350 if (atLeastJava14) {
351 boolean expectedValue = Boolean.valueOf(expectedStringValue).booleanValue();
352 if (expectedStringValue != null) {
353 assertEquals(expectedStringValue, SystemUtils.JAVA_AWT_HEADLESS);
354 }
355 assertEquals(expectedValue, SystemUtils.isJavaAwtHeadless());
356 } else {
357 assertNull(expectedStringValue);
358 assertNull(SystemUtils.JAVA_AWT_HEADLESS);
359 assertEquals(expectedStringValueWithDefault, "" + SystemUtils.isJavaAwtHeadless());
360 }
361 assertEquals(expectedStringValueWithDefault, "" + SystemUtils.isJavaAwtHeadless());
362 }
363 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one
2 * or more contributor license agreements. See the NOTICE file
3 * distributed with this work for additional information
4 * regarding copyright ownership. The ASF licenses this file
5 * to you under the Apache License, Version 2.0 (the
6 * "License"); you may not use this file except in compliance
7 * with the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 package org.apache.commons.lang3;
19
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Modifier;
22 import java.util.AbstractList;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import junit.framework.TestCase;
31
32 /**
33 * Unit tests {@link org.apache.commons.lang3.Validate}.
34 *
35 * @version $Id: ValidateTest.java 1153484 2011-08-03 13:39:42Z ggregory $
36 */
37 public class ValidateTest extends TestCase {
38
39 public ValidateTest(String name) {
40 super(name);
41 }
42
43 //-----------------------------------------------------------------------
44 public void testIsTrue1() {
45 Validate.isTrue(true);
46 try {
47 Validate.isTrue(false);
48 fail("Expecting IllegalArgumentException");
49 } catch (IllegalArgumentException ex) {
50 assertEquals("The validated expression is false", ex.getMessage());
51 }
52 }
53
54 //-----------------------------------------------------------------------
55 public void testIsTrue2() {
56 Validate.isTrue(true, "MSG");
57 try {
58 Validate.isTrue(false, "MSG");
59 fail("Expecting IllegalArgumentException");
60 } catch (IllegalArgumentException ex) {
61 assertEquals("MSG", ex.getMessage());
62 }
63 }
64
65 //-----------------------------------------------------------------------
66 public void testIsTrue3() {
67 Validate.isTrue(true, "MSG", Integer.valueOf(6));
68 try {
69 Validate.isTrue(false, "MSG", Integer.valueOf(6));
70 fail("Expecting IllegalArgumentException");
71 } catch (IllegalArgumentException ex) {
72 assertEquals("MSG", ex.getMessage());
73 }
74 }
75
76 //-----------------------------------------------------------------------
77 public void testIsTrue4() {
78 Validate.isTrue(true, "MSG", 7);
79 try {
80 Validate.isTrue(false, "MSG", 7);
81 fail("Expecting IllegalArgumentException");
82 } catch (IllegalArgumentException ex) {
83 assertEquals("MSG", ex.getMessage());
84 }
85 }
86
87 //-----------------------------------------------------------------------
88 public void testIsTrue5() {
89 Validate.isTrue(true, "MSG", 7.4d);
90 try {
91 Validate.isTrue(false, "MSG", 7.4d);
92 fail("Expecting IllegalArgumentException");
93 } catch (IllegalArgumentException ex) {
94 assertEquals("MSG", ex.getMessage());
95 }
96 }
97
98 //-----------------------------------------------------------------------
99 //-----------------------------------------------------------------------
100 public void testNotNull1() {
101 Validate.notNull(new Object());
102 try {
103 Validate.notNull(null);
104 fail("Expecting NullPointerException");
105 } catch (NullPointerException ex) {
106 assertEquals("The validated object is null", ex.getMessage());
107 }
108
109 String str = "Hi";
110 String testStr = Validate.notNull(str);
111 assertSame(str, testStr);
112 }
113
114 //-----------------------------------------------------------------------
115 public void testNotNull2() {
116 Validate.notNull(new Object(), "MSG");
117 try {
118 Validate.notNull(null, "MSG");
119 fail("Expecting NullPointerException");
120 } catch (NullPointerException ex) {
121 assertEquals("MSG", ex.getMessage());
122 }
123
124 String str = "Hi";
125 String testStr = Validate.notNull(str, "Message");
126 assertSame(str, testStr);
127 }
128
129 //-----------------------------------------------------------------------
130 //-----------------------------------------------------------------------
131 public void testNotEmptyArray1() {
132 Validate.notEmpty(new Object[] {null});
133 try {
134 Validate.notEmpty((Object[]) null);
135 fail("Expecting NullPointerException");
136 } catch (NullPointerException ex) {
137 assertEquals("The validated array is empty", ex.getMessage());
138 }
139 try {
140 Validate.notEmpty(new Object[0]);
141 fail("Expecting IllegalArgumentException");
142 } catch (IllegalArgumentException ex) {
143 assertEquals("The validated array is empty", ex.getMessage());
144 }
145
146 String[] array = new String[] {"hi"};
147 String[] test = Validate.notEmpty(array);
148 assertSame(array, test);
149 }
150
151 //-----------------------------------------------------------------------
152 public void testNotEmptyArray2() {
153 Validate.notEmpty(new Object[] {null}, "MSG");
154 try {
155 Validate.notEmpty((Object[]) null, "MSG");
156 fail("Expecting NullPointerException");
157 } catch (NullPointerException ex) {
158 assertEquals("MSG", ex.getMessage());
159 }
160 try {
161 Validate.notEmpty(new Object[0], "MSG");
162 fail("Expecting IllegalArgumentException");
163 } catch (IllegalArgumentException ex) {
164 assertEquals("MSG", ex.getMessage());
165 }
166
167 String[] array = new String[] {"hi"};
168 String[] test = Validate.notEmpty(array, "Message");
169 assertSame(array, test);
170 }
171
172 //-----------------------------------------------------------------------
173 //-----------------------------------------------------------------------
174 public void testNotEmptyCollection1() {
175 Collection<Integer> coll = new ArrayList<Integer>();
176 try {
177 Validate.notEmpty((Collection<?>) null);
178 fail("Expecting NullPointerException");
179 } catch (NullPointerException ex) {
180 assertEquals("The validated collection is empty", ex.getMessage());
181 }
182 try {
183 Validate.notEmpty(coll);
184 fail("Expecting IllegalArgumentException");
185 } catch (IllegalArgumentException ex) {
186 assertEquals("The validated collection is empty", ex.getMessage());
187 }
188 coll.add(Integer.valueOf(8));
189 Validate.notEmpty(coll);
190
191 Collection<Integer> test = Validate.notEmpty(coll);
192 assertSame(coll, test);
193 }
194
195 //-----------------------------------------------------------------------
196 public void testNotEmptyCollection2() {
197 Collection<Integer> coll = new ArrayList<Integer>();
198 try {
199 Validate.notEmpty((Collection<?>) null, "MSG");
200 fail("Expecting NullPointerException");
201 } catch (NullPointerException ex) {
202 assertEquals("MSG", ex.getMessage());
203 }
204 try {
205 Validate.notEmpty(coll, "MSG");
206 fail("Expecting IllegalArgumentException");
207 } catch (IllegalArgumentException ex) {
208 assertEquals("MSG", ex.getMessage());
209 }
210 coll.add(Integer.valueOf(8));
211 Validate.notEmpty(coll, "MSG");
212
213 Collection<Integer> test = Validate.notEmpty(coll, "Message");
214 assertSame(coll, test);
215 }
216
217 //-----------------------------------------------------------------------
218 //-----------------------------------------------------------------------
219 public void testNotEmptyMap1() {
220 Map<String, Integer> map = new HashMap<String, Integer>();
221 try {
222 Validate.notEmpty((Map<?, ?>) null);
223 fail("Expecting NullPointerException");
224 } catch (NullPointerException ex) {
225 assertEquals("The validated map is empty", ex.getMessage());
226 }
227 try {
228 Validate.notEmpty(map);
229 fail("Expecting IllegalArgumentException");
230 } catch (IllegalArgumentException ex) {
231 assertEquals("The validated map is empty", ex.getMessage());
232 }
233 map.put("ll", Integer.valueOf(8));
234 Validate.notEmpty(map);
235
236 Map<String, Integer> test = Validate.notEmpty(map);
237 assertSame(map, test);
238 }
239
240 //-----------------------------------------------------------------------
241 public void testNotEmptyMap2() {
242 Map<String, Integer> map = new HashMap<String, Integer>();
243 try {
244 Validate.notEmpty((Map<?, ?>) null, "MSG");
245 fail("Expecting NullPointerException");
246 } catch (NullPointerException ex) {
247 assertEquals("MSG", ex.getMessage());
248 }
249 try {
250 Validate.notEmpty(map, "MSG");
251 fail("Expecting IllegalArgumentException");
252 } catch (IllegalArgumentException ex) {
253 assertEquals("MSG", ex.getMessage());
254 }
255 map.put("ll", Integer.valueOf(8));
256 Validate.notEmpty(map, "MSG");
257
258 Map<String, Integer> test = Validate.notEmpty(map, "Message");
259 assertSame(map, test);
260 }
261
262 //-----------------------------------------------------------------------
263 //-----------------------------------------------------------------------
264 public void testNotEmptyString1() {
265 Validate.notEmpty("hjl");
266 try {
267 Validate.notEmpty((String) null);
268 fail("Expecting NullPointerException");
269 } catch (NullPointerException ex) {
270 assertEquals("The validated character sequence is empty", ex.getMessage());
271 }
272 try {
273 Validate.notEmpty("");
274 fail("Expecting IllegalArgumentException");
275 } catch (IllegalArgumentException ex) {
276 assertEquals("The validated character sequence is empty", ex.getMessage());
277 }
278
279 String str = "Hi";
280 String testStr = Validate.notEmpty(str);
281 assertSame(str, testStr);
282 }
283
284 //-----------------------------------------------------------------------
285 public void testNotEmptyString2() {
286 Validate.notEmpty("a", "MSG");
287 try {
288 Validate.notEmpty((String) null, "MSG");
289 fail("Expecting NullPointerException");
290 } catch (NullPointerException ex) {
291 assertEquals("MSG", ex.getMessage());
292 }
293 try {
294 Validate.notEmpty("", "MSG");
295 fail("Expecting IllegalArgumentException");
296 } catch (IllegalArgumentException ex) {
297 assertEquals("MSG", ex.getMessage());
298 }
299
300 String str = "Hi";
301 String testStr = Validate.notEmpty(str, "Message");
302 assertSame(str, testStr);
303 }
304
305 //-----------------------------------------------------------------------
306 //-----------------------------------------------------------------------
307 public void testNotBlankNullStringShouldThrow() {
308 //given
309 String string = null;
310
311 try {
312 //when
313 Validate.notBlank(string);
314 fail("Expecting NullPointerException");
315 } catch (NullPointerException e) {
316 //then
317 assertEquals("The validated character sequence is blank", e.getMessage());
318 }
319 }
320
321 //-----------------------------------------------------------------------
322 public void testNotBlankMsgNullStringShouldThrow() {
323 //given
324 String string = null;
325
326 try {
327 //when
328 Validate.notBlank(string, "Message");
329 fail("Expecting NullPointerException");
330 } catch (NullPointerException e) {
331 //then
332 assertEquals("Message", e.getMessage());
333 }
334 }
335
336 //-----------------------------------------------------------------------
337 public void testNotBlankEmptyStringShouldThrow() {
338 //given
339 String string = "";
340
341 try {
342 //when
343 Validate.notBlank(string);
344 fail("Expecting IllegalArgumentException");
345 } catch (IllegalArgumentException e) {
346 //then
347 assertEquals("The validated character sequence is blank", e.getMessage());
348 }
349 }
350
351 //-----------------------------------------------------------------------
352 public void testNotBlankBlankStringWithWhitespacesShouldThrow() {
353 //given
354 String string = " ";
355
356 try {
357 //when
358 Validate.notBlank(string);
359 fail("Expecting IllegalArgumentException");
360 } catch (IllegalArgumentException e) {
361 //then
362 assertEquals("The validated character sequence is blank", e.getMessage());
363 }
364 }
365
366 //-----------------------------------------------------------------------
367 public void testNotBlankBlankStringWithNewlinesShouldThrow() {
368 //given
369 String string = " \n \t \r \n ";
370
371 try {
372 //when
373 Validate.notBlank(string);
374 fail("Expecting IllegalArgumentException");
375 } catch (IllegalArgumentException e) {
376 //then
377 assertEquals("The validated character sequence is blank", e.getMessage());
378 }
379 }
380
381 //-----------------------------------------------------------------------
382 public void testNotBlankMsgBlankStringShouldThrow() {
383 //given
384 String string = " \n \t \r \n ";
385
386 try {
387 //when
388 Validate.notBlank(string, "Message");
389 fail("Expecting IllegalArgumentException");
390 } catch (IllegalArgumentException e) {
391 //then
392 assertEquals("Message", e.getMessage());
393 }
394 }
395
396 //-----------------------------------------------------------------------
397 public void testNotBlankMsgBlankStringWithWhitespacesShouldThrow() {
398 //given
399 String string = " ";
400
401 try {
402 //when
403 Validate.notBlank(string, "Message");
404 fail("Expecting IllegalArgumentException");
405 } catch (IllegalArgumentException e) {
406 //then
407 assertEquals("Message", e.getMessage());
408 }
409 }
410
411 //-----------------------------------------------------------------------
412 public void testNotBlankMsgEmptyStringShouldThrow() {
413 //given
414 String string = "";
415
416 try {
417 //when
418 Validate.notBlank(string, "Message");
419 fail("Expecting IllegalArgumentException");
420 } catch (IllegalArgumentException e) {
421 //then
422 assertEquals("Message", e.getMessage());
423 }
424 }
425
426 //-----------------------------------------------------------------------
427 public void testNotBlankNotBlankStringShouldNotThrow() {
428 //given
429 String string = "abc";
430
431 //when
432 Validate.notBlank(string);
433
434 //then should not throw
435 }
436
437 //-----------------------------------------------------------------------
438 public void testNotBlankNotBlankStringWithWhitespacesShouldNotThrow() {
439 //given
440 String string = " abc ";
441
442 //when
443 Validate.notBlank(string);
444
445 //then should not throw
446 }
447
448 //-----------------------------------------------------------------------
449 public void testNotBlankNotBlankStringWithNewlinesShouldNotThrow() {
450 //given
451 String string = " \n \t abc \r \n ";
452
453 //when
454 Validate.notBlank(string);
455
456 //then should not throw
457 }
458
459 //-----------------------------------------------------------------------
460 public void testNotBlankMsgNotBlankStringShouldNotThrow() {
461 //given
462 String string = "abc";
463
464 //when
465 Validate.notBlank(string, "Message");
466
467 //then should not throw
468 }
469
470 //-----------------------------------------------------------------------
471 public void testNotBlankMsgNotBlankStringWithWhitespacesShouldNotThrow() {
472 //given
473 String string = " abc ";
474
475 //when
476 Validate.notBlank(string, "Message");
477
478 //then should not throw
479 }
480
481 //-----------------------------------------------------------------------
482 public void testNotBlankMsgNotBlankStringWithNewlinesShouldNotThrow() {
483 //given
484 String string = " \n \t abc \r \n ";
485
486 //when
487 Validate.notBlank(string, "Message");
488
489 //then should not throw
490 }
491
492 //-----------------------------------------------------------------------
493 public void testNotBlankReturnValues1() {
494 String str = "Hi";
495 String test = Validate.notBlank(str);
496 assertSame(str, test);
497 }
498
499 public void testNotBlankReturnValues2() {
500 String str = "Hi";
501 String test = Validate.notBlank(str, "Message");
502 assertSame(str, test);
503 }
504
505 //-----------------------------------------------------------------------
506 //-----------------------------------------------------------------------
507 public void testNoNullElementsArray1() {
508 String[] array = new String[] {"a", "b"};
509 Validate.noNullElements(array);
510 try {
511 Validate.noNullElements((Object[]) null);
512 fail("Expecting NullPointerException");
513 } catch (NullPointerException ex) {
514 assertEquals("The validated object is null", ex.getMessage());
515 }
516 array[1] = null;
517 try {
518 Validate.noNullElements(array);
519 fail("Expecting IllegalArgumentException");
520 } catch (IllegalArgumentException ex) {
521 assertEquals("The validated array contains null element at index: 1", ex.getMessage());
522 }
523
524 array = new String[] {"a", "b"};
525 String[] test = Validate.noNullElements(array);
526 assertSame(array, test);
527 }
528
529 //-----------------------------------------------------------------------
530 public void testNoNullElementsArray2() {
531 String[] array = new String[] {"a", "b"};
532 Validate.noNullElements(array, "MSG");
533 try {
534 Validate.noNullElements((Object[]) null, "MSG");
535 fail("Expecting NullPointerException");
536 } catch (NullPointerException ex) {
537 assertEquals("The validated object is null", ex.getMessage());
538 }
539 array[1] = null;
540 try {
541 Validate.noNullElements(array, "MSG");
542 fail("Expecting IllegalArgumentException");
543 } catch (IllegalArgumentException ex) {
544 assertEquals("MSG", ex.getMessage());
545 }
546
547 array = new String[] {"a", "b"};
548 String[] test = Validate.noNullElements(array, "Message");
549 assertSame(array, test);
550 }
551
552 //-----------------------------------------------------------------------
553 //-----------------------------------------------------------------------
554 public void testNoNullElementsCollection1() {
555 List<String> coll = new ArrayList<String>();
556 coll.add("a");
557 coll.add("b");
558 Validate.noNullElements(coll);
559 try {
560 Validate.noNullElements((Collection<?>) null);
561 fail("Expecting NullPointerException");
562 } catch (NullPointerException ex) {
563 assertEquals("The validated object is null", ex.getMessage());
564 }
565 coll.set(1, null);
566 try {
567 Validate.noNullElements(coll);
568 fail("Expecting IllegalArgumentException");
569 } catch (IllegalArgumentException ex) {
570 assertEquals("The validated collection contains null element at index: 1", ex.getMessage());
571 }
572
573 coll.set(1, "b");
574 List<String> test = Validate.noNullElements(coll);
575 assertSame(coll, test);
576 }
577
578 //-----------------------------------------------------------------------
579 public void testNoNullElementsCollection2() {
580 List<String> coll = new ArrayList<String>();
581 coll.add("a");
582 coll.add("b");
583 Validate.noNullElements(coll, "MSG");
584 try {
585 Validate.noNullElements((Collection<?>) null, "MSG");
586 fail("Expecting NullPointerException");
587 } catch (NullPointerException ex) {
588 assertEquals("The validated object is null", ex.getMessage());
589 }
590 coll.set(1, null);
591 try {
592 Validate.noNullElements(coll, "MSG");
593 fail("Expecting IllegalArgumentException");
594 } catch (IllegalArgumentException ex) {
595 assertEquals("MSG", ex.getMessage());
596 }
597
598 coll.set(1, "b");
599 List<String> test = Validate.noNullElements(coll, "Message");
600 assertSame(coll, test);
601 }
602
603 //-----------------------------------------------------------------------
604 //-----------------------------------------------------------------------
605 public void testConstructor() {
606 assertNotNull(new Validate());
607 Constructor<?>[] cons = Validate.class.getDeclaredConstructors();
608 assertEquals(1, cons.length);
609 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
610 assertEquals(true, Modifier.isPublic(Validate.class.getModifiers()));
611 assertEquals(false, Modifier.isFinal(Validate.class.getModifiers()));
612 }
613
614 //-----------------------------------------------------------------------
615 //-----------------------------------------------------------------------
616 public void testValidIndex_withMessage_array() {
617 Object[] array = new Object[2];
618 Validate.validIndex(array, 0, "Broken: ");
619 Validate.validIndex(array, 1, "Broken: ");
620 try {
621 Validate.validIndex(array, -1, "Broken: ");
622 fail("Expecting IndexOutOfBoundsException");
623 } catch (IndexOutOfBoundsException ex) {
624 assertEquals("Broken: ", ex.getMessage());
625 }
626 try {
627 Validate.validIndex(array, 2, "Broken: ");
628 fail("Expecting IndexOutOfBoundsException");
629 } catch (IndexOutOfBoundsException ex) {
630 assertEquals("Broken: ", ex.getMessage());
631 }
632
633 String[] strArray = new String[] {"Hi"};
634 String[] test = Validate.noNullElements(strArray, "Message");
635 assertSame(strArray, test);
636 }
637
638 public void testValidIndex_array() {
639 Object[] array = new Object[2];
640 Validate.validIndex(array, 0);
641 Validate.validIndex(array, 1);
642 try {
643 Validate.validIndex(array, -1);
644 fail("Expecting IndexOutOfBoundsException");
645 } catch (IndexOutOfBoundsException ex) {
646 assertEquals("The validated array index is invalid: -1", ex.getMessage());
647 }
648 try {
649 Validate.validIndex(array, 2);
650 fail("Expecting IndexOutOfBoundsException");
651 } catch (IndexOutOfBoundsException ex) {
652 assertEquals("The validated array index is invalid: 2", ex.getMessage());
653 }
654
655 String[] strArray = new String[] {"Hi"};
656 String[] test = Validate.noNullElements(strArray);
657 assertSame(strArray, test);
658 }
659
660 //-----------------------------------------------------------------------
661 //-----------------------------------------------------------------------
662 public void testValidIndex_withMessage_collection() {
663 Collection<String> coll = new ArrayList<String>();
664 coll.add(null);
665 coll.add(null);
666 Validate.validIndex(coll, 0, "Broken: ");
667 Validate.validIndex(coll, 1, "Broken: ");
668 try {
669 Validate.validIndex(coll, -1, "Broken: ");
670 fail("Expecting IndexOutOfBoundsException");
671 } catch (IndexOutOfBoundsException ex) {
672 assertEquals("Broken: ", ex.getMessage());
673 }
674 try {
675 Validate.validIndex(coll, 2, "Broken: ");
676 fail("Expecting IndexOutOfBoundsException");
677 } catch (IndexOutOfBoundsException ex) {
678 assertEquals("Broken: ", ex.getMessage());
679 }
680
681 List<String> strColl = Arrays.asList(new String[] {"Hi"});
682 List<String> test = Validate.validIndex(strColl, 0, "Message");
683 assertSame(strColl, test);
684 }
685
686 public void testValidIndex_collection() {
687 Collection<String> coll = new ArrayList<String>();
688 coll.add(null);
689 coll.add(null);
690 Validate.validIndex(coll, 0);
691 Validate.validIndex(coll, 1);
692 try {
693 Validate.validIndex(coll, -1);
694 fail("Expecting IndexOutOfBoundsException");
695 } catch (IndexOutOfBoundsException ex) {
696 assertEquals("The validated collection index is invalid: -1", ex.getMessage());
697 }
698 try {
699 Validate.validIndex(coll, 2);
700 fail("Expecting IndexOutOfBoundsException");
701 } catch (IndexOutOfBoundsException ex) {
702 assertEquals("The validated collection index is invalid: 2", ex.getMessage());
703 }
704
705 List<String> strColl = Arrays.asList(new String[] {"Hi"});
706 List<String> test = Validate.validIndex(strColl, 0);
707 assertSame(strColl, test);
708 }
709
710 //-----------------------------------------------------------------------
711 //-----------------------------------------------------------------------
712 public void testValidIndex_withMessage_charSequence() {
713 CharSequence str = "Hi";
714 Validate.validIndex(str, 0, "Broken: ");
715 Validate.validIndex(str, 1, "Broken: ");
716 try {
717 Validate.validIndex(str, -1, "Broken: ");
718 fail("Expecting IndexOutOfBoundsException");
719 } catch (IndexOutOfBoundsException ex) {
720 assertEquals("Broken: ", ex.getMessage());
721 }
722 try {
723 Validate.validIndex(str, 2, "Broken: ");
724 fail("Expecting IndexOutOfBoundsException");
725 } catch (IndexOutOfBoundsException ex) {
726 assertEquals("Broken: ", ex.getMessage());
727 }
728
729 String input = "Hi";
730 String test = Validate.validIndex(input, 0, "Message");
731 assertSame(input, test);
732 }
733
734 public void testValidIndex_charSequence() {
735 CharSequence str = "Hi";
736 Validate.validIndex(str, 0);
737 Validate.validIndex(str, 1);
738 try {
739 Validate.validIndex(str, -1);
740 fail("Expecting IndexOutOfBoundsException");
741 } catch (IndexOutOfBoundsException ex) {
742 assertEquals("The validated character sequence index is invalid: -1", ex.getMessage());
743 }
744 try {
745 Validate.validIndex(str, 2);
746 fail("Expecting IndexOutOfBoundsException");
747 } catch (IndexOutOfBoundsException ex) {
748 assertEquals("The validated character sequence index is invalid: 2", ex.getMessage());
749 }
750
751 String input = "Hi";
752 String test = Validate.validIndex(input, 0);
753 assertSame(input, test);
754 }
755
756 public void testMatchesPattern()
757 {
758 CharSequence str = "hi";
759 Validate.matchesPattern(str, "[a-z]*");
760 try
761 {
762 Validate.matchesPattern(str, "[0-9]*");
763 fail("Expecting IllegalArgumentException");
764 }
765 catch (IllegalArgumentException e)
766 {
767 assertEquals("The string hi does not match the pattern [0-9]*", e.getMessage());
768 }
769 }
770
771 public void testMatchesPattern_withMessage()
772 {
773 CharSequence str = "hi";
774 Validate.matchesPattern(str, "[a-z]*", "Does not match");
775 try
776 {
777 Validate.matchesPattern(str, "[0-9]*", "Does not match");
778 fail("Expecting IllegalArgumentException");
779 }
780 catch (IllegalArgumentException e)
781 {
782 assertEquals("Does not match", e.getMessage());
783 }
784 }
785
786 public void testInclusiveBetween()
787 {
788 Validate.inclusiveBetween("a", "c", "b");
789 Validate.inclusiveBetween(0, 2, 1);
790 Validate.inclusiveBetween(0, 2, 2);
791 try {
792 Validate.inclusiveBetween(0, 5, 6);
793 fail("Expecting IllegalArgumentException");
794 } catch (IllegalArgumentException e) {
795 assertEquals("The value 6 is not in the specified inclusive range of 0 to 5", e.getMessage());
796 }
797 }
798
799 public void testInclusiveBetween_withMessage()
800 {
801 Validate.inclusiveBetween("a", "c", "b", "Error");
802 Validate.inclusiveBetween(0, 2, 1, "Error");
803 Validate.inclusiveBetween(0, 2, 2, "Error");
804 try {
805 Validate.inclusiveBetween(0, 5, 6, "Error");
806 fail("Expecting IllegalArgumentException");
807 } catch (IllegalArgumentException e) {
808 assertEquals("Error", e.getMessage());
809 }
810 }
811
812 public void testExclusiveBetween()
813 {
814 Validate.exclusiveBetween("a", "c", "b");
815 Validate.exclusiveBetween(0, 2, 1);
816 try {
817 Validate.exclusiveBetween(0, 5, 6);
818 fail("Expecting IllegalArgumentException");
819 } catch (IllegalArgumentException e) {
820 assertEquals("The value 6 is not in the specified exclusive range of 0 to 5", e.getMessage());
821 }
822 try {
823 Validate.exclusiveBetween(0, 5, 5);
824 fail("Expecting IllegalArgumentException");
825 } catch (IllegalArgumentException e) {
826 assertEquals("The value 5 is not in the specified exclusive range of 0 to 5", e.getMessage());
827 }
828 }
829
830 public void testExclusiveBetween_withMessage()
831 {
832 Validate.exclusiveBetween("a", "c", "b", "Error");
833 Validate.exclusiveBetween(0, 2, 1, "Error");
834 try {
835 Validate.exclusiveBetween(0, 5, 6, "Error");
836 fail("Expecting IllegalArgumentException");
837 } catch (IllegalArgumentException e) {
838 assertEquals("Error", e.getMessage());
839 }
840 try {
841 Validate.exclusiveBetween(0, 5, 5, "Error");
842 fail("Expecting IllegalArgumentException");
843 } catch (IllegalArgumentException e) {
844 assertEquals("Error", e.getMessage());
845 }
846 }
847
848 public void testIsInstanceOf() {
849 Validate.isInstanceOf(String.class, "hi");
850 Validate.isInstanceOf(Integer.class, 1);
851 try {
852 Validate.isInstanceOf(List.class, "hi");
853 fail("Expecting IllegalArgumentException");
854 } catch(IllegalArgumentException e) {
855 assertEquals("The validated object is not an instance of java.util.List", e.getMessage());
856 }
857 }
858
859 public void testIsInstanceOf_withMessage() {
860 Validate.isInstanceOf(String.class, "hi", "Error");
861 Validate.isInstanceOf(Integer.class, 1, "Error");
862 try {
863 Validate.isInstanceOf(List.class, "hi", "Error");
864 fail("Expecting IllegalArgumentException");
865 } catch(IllegalArgumentException e) {
866 assertEquals("Error", e.getMessage());
867 }
868 }
869
870 public void testIsAssignable() {
871 Validate.isAssignableFrom(CharSequence.class, String.class);
872 Validate.isAssignableFrom(AbstractList.class, ArrayList.class);
873 try {
874 Validate.isAssignableFrom(List.class, String.class);
875 fail("Expecting IllegalArgumentException");
876 } catch(IllegalArgumentException e) {
877 assertEquals("The validated class can not be converted to the java.util.List class", e.getMessage());
878 }
879 }
880
881 public void testIsAssignable_withMessage() {
882 Validate.isAssignableFrom(CharSequence.class, String.class, "Error");
883 Validate.isAssignableFrom(AbstractList.class, ArrayList.class, "Error");
884 try {
885 Validate.isAssignableFrom(List.class, String.class, "Error");
886 fail("Expecting IllegalArgumentException");
887 } catch(IllegalArgumentException e) {
888 assertEquals("Error", e.getMessage());
889 }
890 }
891
892 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.math.BigInteger;
19
20 import junit.framework.TestCase;
21
22 /**
23 * Unit tests {@link org.apache.commons.lang3.builder.CompareToBuilder}.
24 *
25 * @version $Id: CompareToBuilderTest.java 1088899 2011-04-05 05:31:27Z bayard $
26 */
27 public class CompareToBuilderTest extends TestCase {
28
29 public CompareToBuilderTest(String name) {
30 super(name);
31 }
32
33 //-----------------------------------------------------------------------
34
35 static class TestObject implements Comparable<TestObject> {
36 private int a;
37 public TestObject(int a) {
38 this.a = a;
39 }
40 @Override
41 public boolean equals(Object o) {
42 if (o == this) {
43 return true;
44 }
45 if (!(o instanceof TestObject)) {
46 return false;
47 }
48 TestObject rhs = (TestObject) o;
49 return (a == rhs.a);
50 }
51
52 public void setA(int a) {
53 this.a = a;
54 }
55
56 public int getA() {
57 return a;
58 }
59 public int compareTo(TestObject rhs) {
60 return (a < rhs.a) ? -1 : (a > rhs.a) ? +1 : 0;
61 }
62 }
63
64 static class TestSubObject extends TestObject {
65 private int b;
66 public TestSubObject() {
67 super(0);
68 }
69 public TestSubObject(int a, int b) {
70 super(a);
71 this.b = b;
72 }
73 @Override
74 public boolean equals(Object o) {
75 if (o == this) {
76 return true;
77 }
78 if (!(o instanceof TestSubObject)) {
79 return false;
80 }
81 TestSubObject rhs = (TestSubObject) o;
82 return super.equals(o) && (b == rhs.b);
83 }
84 }
85
86 static class TestTransientSubObject extends TestObject {
87 @SuppressWarnings("unused")
88 private transient int t;
89 public TestTransientSubObject(int a, int t) {
90 super(a);
91 this.t = t;
92 }
93 }
94
95 public void testReflectionCompare() {
96 TestObject o1 = new TestObject(4);
97 TestObject o2 = new TestObject(4);
98 assertTrue(CompareToBuilder.reflectionCompare(o1, o1) == 0);
99 assertTrue(CompareToBuilder.reflectionCompare(o1, o2) == 0);
100 o2.setA(5);
101 assertTrue(CompareToBuilder.reflectionCompare(o1, o2) < 0);
102 assertTrue(CompareToBuilder.reflectionCompare(o2, o1) > 0);
103 }
104
105 public void testReflectionCompareEx1() {
106 TestObject o1 = new TestObject(4);
107 try {
108 CompareToBuilder.reflectionCompare(o1, null);
109 } catch (NullPointerException ex) {
110 return;
111 }
112 fail();
113 }
114
115 public void testReflectionCompareEx2() {
116 TestObject o1 = new TestObject(4);
117 Object o2 = new Object();
118 try {
119 CompareToBuilder.reflectionCompare(o1, o2);
120 fail();
121 } catch (ClassCastException ex) {}
122 }
123
124 public void testReflectionHierarchyCompare() {
125 testReflectionHierarchyCompare(false, null);
126 }
127
128 public void testReflectionHierarchyCompareExcludeFields() {
129 String[] excludeFields = new String[] { "b" };
130 testReflectionHierarchyCompare(true, excludeFields);
131
132 TestSubObject x;
133 TestSubObject y;
134 TestSubObject z;
135
136 x = new TestSubObject(1, 1);
137 y = new TestSubObject(2, 1);
138 z = new TestSubObject(3, 1);
139 assertXYZCompareOrder(x, y, z, true, excludeFields);
140
141 x = new TestSubObject(1, 3);
142 y = new TestSubObject(2, 2);
143 z = new TestSubObject(3, 1);
144 assertXYZCompareOrder(x, y, z, true, excludeFields);
145 }
146
147 public void testReflectionHierarchyCompareTransients() {
148 testReflectionHierarchyCompare(true, null);
149
150 TestTransientSubObject x;
151 TestTransientSubObject y;
152 TestTransientSubObject z;
153
154 x = new TestTransientSubObject(1, 1);
155 y = new TestTransientSubObject(2, 2);
156 z = new TestTransientSubObject(3, 3);
157 assertXYZCompareOrder(x, y, z, true, null);
158
159 x = new TestTransientSubObject(1, 1);
160 y = new TestTransientSubObject(1, 2);
161 z = new TestTransientSubObject(1, 3);
162 assertXYZCompareOrder(x, y, z, true, null);
163 }
164
165 private void assertXYZCompareOrder(Object x, Object y, Object z, boolean testTransients, String[] excludeFields) {
166 assertTrue(0 == CompareToBuilder.reflectionCompare(x, x, testTransients, null, excludeFields));
167 assertTrue(0 == CompareToBuilder.reflectionCompare(y, y, testTransients, null, excludeFields));
168 assertTrue(0 == CompareToBuilder.reflectionCompare(z, z, testTransients, null, excludeFields));
169
170 assertTrue(0 > CompareToBuilder.reflectionCompare(x, y, testTransients, null, excludeFields));
171 assertTrue(0 > CompareToBuilder.reflectionCompare(x, z, testTransients, null, excludeFields));
172 assertTrue(0 > CompareToBuilder.reflectionCompare(y, z, testTransients, null, excludeFields));
173
174 assertTrue(0 < CompareToBuilder.reflectionCompare(y, x, testTransients, null, excludeFields));
175 assertTrue(0 < CompareToBuilder.reflectionCompare(z, x, testTransients, null, excludeFields));
176 assertTrue(0 < CompareToBuilder.reflectionCompare(z, y, testTransients, null, excludeFields));
177 }
178
179 public void testReflectionHierarchyCompare(boolean testTransients, String[] excludeFields) {
180 TestObject to1 = new TestObject(1);
181 TestObject to2 = new TestObject(2);
182 TestObject to3 = new TestObject(3);
183 TestSubObject tso1 = new TestSubObject(1, 1);
184 TestSubObject tso2 = new TestSubObject(2, 2);
185 TestSubObject tso3 = new TestSubObject(3, 3);
186
187 assertReflectionCompareContract(to1, to1, to1, false, excludeFields);
188 assertReflectionCompareContract(to1, to2, to3, false, excludeFields);
189 assertReflectionCompareContract(tso1, tso1, tso1, false, excludeFields);
190 assertReflectionCompareContract(tso1, tso2, tso3, false, excludeFields);
191 assertReflectionCompareContract("1", "2", "3", false, excludeFields);
192
193 assertTrue(0 != CompareToBuilder.reflectionCompare(tso1, new TestSubObject(1, 0), testTransients));
194 assertTrue(0 != CompareToBuilder.reflectionCompare(tso1, new TestSubObject(0, 1), testTransients));
195
196 // root class
197 assertXYZCompareOrder(to1, to2, to3, true, null);
198 // subclass
199 assertXYZCompareOrder(tso1, tso2, tso3, true, null);
200 }
201
202 /**
203 * See "Effective Java" under "Consider Implementing Comparable".
204 *
205 * @param x an object to compare
206 * @param y an object to compare
207 * @param z an object to compare
208 * @param testTransients Whether to include transients in the comparison
209 * @param excludeFields fields to exclude
210 */
211 public void assertReflectionCompareContract(Object x, Object y, Object z, boolean testTransients, String[] excludeFields) {
212
213 // signum
214 assertTrue(reflectionCompareSignum(x, y, testTransients, excludeFields) == -reflectionCompareSignum(y, x, testTransients, excludeFields));
215
216 // transitive
217 if (CompareToBuilder.reflectionCompare(x, y, testTransients, null, excludeFields) > 0
218 && CompareToBuilder.reflectionCompare(y, z, testTransients, null, excludeFields) > 0){
219 assertTrue(CompareToBuilder.reflectionCompare(x, z, testTransients, null, excludeFields) > 0);
220 }
221
222 // un-named
223 if (CompareToBuilder.reflectionCompare(x, y, testTransients, null, excludeFields) == 0) {
224 assertTrue(reflectionCompareSignum(x, z, testTransients, excludeFields) == -reflectionCompareSignum(y, z, testTransients, excludeFields));
225 }
226
227 // strongly recommended but not strictly required
228 assertTrue((CompareToBuilder.reflectionCompare(x, y, testTransients) ==0 ) == EqualsBuilder.reflectionEquals(x, y, testTransients));
229 }
230
231 /**
232 * Returns the signum of the result of comparing x and y with
233 * <code>CompareToBuilder.reflectionCompare</code>
234 *
235 * @param lhs The "left-hand-side" of the comparison.
236 * @param rhs The "right-hand-side" of the comparison.
237 * @param testTransients Whether to include transients in the comparison
238 * @param excludeFields fields to exclude
239 * @return int The signum
240 */
241 private int reflectionCompareSignum(Object lhs, Object rhs, boolean testTransients, String[] excludeFields) {
242 return BigInteger.valueOf(CompareToBuilder.reflectionCompare(lhs, rhs, testTransients)).signum();
243 }
244
245 public void testAppendSuper() {
246 TestObject o1 = new TestObject(4);
247 TestObject o2 = new TestObject(5);
248 assertTrue(new CompareToBuilder().appendSuper(0).append(o1, o1).toComparison() == 0);
249 assertTrue(new CompareToBuilder().appendSuper(0).append(o1, o2).toComparison() < 0);
250 assertTrue(new CompareToBuilder().appendSuper(0).append(o2, o1).toComparison() > 0);
251
252 assertTrue(new CompareToBuilder().appendSuper(-1).append(o1, o1).toComparison() < 0);
253 assertTrue(new CompareToBuilder().appendSuper(-1).append(o1, o2).toComparison() < 0);
254
255 assertTrue(new CompareToBuilder().appendSuper(1).append(o1, o1).toComparison() > 0);
256 assertTrue(new CompareToBuilder().appendSuper(1).append(o1, o2).toComparison() > 0);
257 }
258
259 public void testObject() {
260 TestObject o1 = new TestObject(4);
261 TestObject o2 = new TestObject(4);
262 assertTrue(new CompareToBuilder().append(o1, o1).toComparison() == 0);
263 assertTrue(new CompareToBuilder().append(o1, o2).toComparison() == 0);
264 o2.setA(5);
265 assertTrue(new CompareToBuilder().append(o1, o2).toComparison() < 0);
266 assertTrue(new CompareToBuilder().append(o2, o1).toComparison() > 0);
267
268 assertTrue(new CompareToBuilder().append(o1, null).toComparison() > 0);
269 assertTrue(new CompareToBuilder().append((Object) null, (Object) null).toComparison() == 0);
270 assertTrue(new CompareToBuilder().append(null, o1).toComparison() < 0);
271 }
272
273 public void testObjectBuild() {
274 TestObject o1 = new TestObject(4);
275 TestObject o2 = new TestObject(4);
276 assertTrue(new CompareToBuilder().append(o1, o1).build() == 0);
277 assertTrue(new CompareToBuilder().append(o1, o2).build() == 0);
278 o2.setA(5);
279 assertTrue(new CompareToBuilder().append(o1, o2).build() < 0);
280 assertTrue(new CompareToBuilder().append(o2, o1).build() > 0);
281
282 assertTrue(new CompareToBuilder().append(o1, null).build() > 0);
283 assertTrue(new CompareToBuilder().append((Object) null, (Object) null).build() == 0);
284 assertTrue(new CompareToBuilder().append(null, o1).build() < 0);
285 }
286
287 public void testObjectEx2() {
288 TestObject o1 = new TestObject(4);
289 Object o2 = new Object();
290 try {
291 new CompareToBuilder().append(o1, o2);
292 fail();
293 } catch (ClassCastException ex) {}
294 }
295
296 public void testObjectComparator() {
297 String o1 = "Fred";
298 String o2 = "Fred";
299 assertTrue(new CompareToBuilder().append(o1, o1, String.CASE_INSENSITIVE_ORDER).toComparison() == 0);
300 assertTrue(new CompareToBuilder().append(o1, o2, String.CASE_INSENSITIVE_ORDER).toComparison() == 0);
301 o2 = "FRED";
302 assertTrue(new CompareToBuilder().append(o1, o2, String.CASE_INSENSITIVE_ORDER).toComparison() == 0);
303 assertTrue(new CompareToBuilder().append(o2, o1, String.CASE_INSENSITIVE_ORDER).toComparison() == 0);
304 o2 = "FREDA";
305 assertTrue(new CompareToBuilder().append(o1, o2, String.CASE_INSENSITIVE_ORDER).toComparison() < 0);
306 assertTrue(new CompareToBuilder().append(o2, o1, String.CASE_INSENSITIVE_ORDER).toComparison() > 0);
307
308 assertTrue(new CompareToBuilder().append(o1, null, String.CASE_INSENSITIVE_ORDER).toComparison() > 0);
309 assertTrue(new CompareToBuilder().append((Object) null, (Object) null, String.CASE_INSENSITIVE_ORDER).toComparison() == 0);
310 assertTrue(new CompareToBuilder().append(null, o1, String.CASE_INSENSITIVE_ORDER).toComparison() < 0);
311 }
312
313 public void testObjectComparatorNull() {
314 String o1 = "Fred";
315 String o2 = "Fred";
316 assertTrue(new CompareToBuilder().append(o1, o1, null).toComparison() == 0);
317 assertTrue(new CompareToBuilder().append(o1, o2, null).toComparison() == 0);
318 o2 = "Zebra";
319 assertTrue(new CompareToBuilder().append(o1, o2, null).toComparison() < 0);
320 assertTrue(new CompareToBuilder().append(o2, o1, null).toComparison() > 0);
321
322 assertTrue(new CompareToBuilder().append(o1, null, null).toComparison() > 0);
323 assertTrue(new CompareToBuilder().append((Object) null, (Object) null, null).toComparison() == 0);
324 assertTrue(new CompareToBuilder().append(null, o1, null).toComparison() < 0);
325 }
326
327 public void testLong() {
328 long o1 = 1L;
329 long o2 = 2L;
330 assertTrue(new CompareToBuilder().append(o1, o1).toComparison() == 0);
331 assertTrue(new CompareToBuilder().append(o1, o2).toComparison() < 0);
332 assertTrue(new CompareToBuilder().append(o2, o1).toComparison() > 0);
333 assertTrue(new CompareToBuilder().append(o1, Long.MAX_VALUE).toComparison() < 0);
334 assertTrue(new CompareToBuilder().append(Long.MAX_VALUE, o1).toComparison() > 0);
335 assertTrue(new CompareToBuilder().append(o1, Long.MIN_VALUE).toComparison() > 0);
336 assertTrue(new CompareToBuilder().append(Long.MIN_VALUE, o1).toComparison() < 0);
337 }
338
339 public void testInt() {
340 int o1 = 1;
341 int o2 = 2;
342 assertTrue(new CompareToBuilder().append(o1, o1).toComparison() == 0);
343 assertTrue(new CompareToBuilder().append(o1, o2).toComparison() < 0);
344 assertTrue(new CompareToBuilder().append(o2, o1).toComparison() > 0);
345 assertTrue(new CompareToBuilder().append(o1, Integer.MAX_VALUE).toComparison() < 0);
346 assertTrue(new CompareToBuilder().append(Integer.MAX_VALUE, o1).toComparison() > 0);
347 assertTrue(new CompareToBuilder().append(o1, Integer.MIN_VALUE).toComparison() > 0);
348 assertTrue(new CompareToBuilder().append(Integer.MIN_VALUE, o1).toComparison() < 0);
349 }
350
351 public void testShort() {
352 short o1 = 1;
353 short o2 = 2;
354 assertTrue(new CompareToBuilder().append(o1, o1).toComparison() == 0);
355 assertTrue(new CompareToBuilder().append(o1, o2).toComparison() < 0);
356 assertTrue(new CompareToBuilder().append(o2, o1).toComparison() > 0);
357 assertTrue(new CompareToBuilder().append(o1, Short.MAX_VALUE).toComparison() < 0);
358 assertTrue(new CompareToBuilder().append(Short.MAX_VALUE, o1).toComparison() > 0);
359 assertTrue(new CompareToBuilder().append(o1, Short.MIN_VALUE).toComparison() > 0);
360 assertTrue(new CompareToBuilder().append(Short.MIN_VALUE, o1).toComparison() < 0);
361 }
362
363 public void testChar() {
364 char o1 = 1;
365 char o2 = 2;
366 assertTrue(new CompareToBuilder().append(o1, o1).toComparison() == 0);
367 assertTrue(new CompareToBuilder().append(o1, o2).toComparison() < 0);
368 assertTrue(new CompareToBuilder().append(o2, o1).toComparison() > 0);
369 assertTrue(new CompareToBuilder().append(o1, Character.MAX_VALUE).toComparison() < 0);
370 assertTrue(new CompareToBuilder().append(Character.MAX_VALUE, o1).toComparison() > 0);
371 assertTrue(new CompareToBuilder().append(o1, Character.MIN_VALUE).toComparison() > 0);
372 assertTrue(new CompareToBuilder().append(Character.MIN_VALUE, o1).toComparison() < 0);
373 }
374
375 public void testByte() {
376 byte o1 = 1;
377 byte o2 = 2;
378 assertTrue(new CompareToBuilder().append(o1, o1).toComparison() == 0);
379 assertTrue(new CompareToBuilder().append(o1, o2).toComparison() < 0);
380 assertTrue(new CompareToBuilder().append(o2, o1).toComparison() > 0);
381 assertTrue(new CompareToBuilder().append(o1, Byte.MAX_VALUE).toComparison() < 0);
382 assertTrue(new CompareToBuilder().append(Byte.MAX_VALUE, o1).toComparison() > 0);
383 assertTrue(new CompareToBuilder().append(o1, Byte.MIN_VALUE).toComparison() > 0);
384 assertTrue(new CompareToBuilder().append(Byte.MIN_VALUE, o1).toComparison() < 0);
385 }
386
387 public void testDouble() {
388 double o1 = 1;
389 double o2 = 2;
390 assertTrue(new CompareToBuilder().append(o1, o1).toComparison() == 0);
391 assertTrue(new CompareToBuilder().append(o1, o2).toComparison() < 0);
392 assertTrue(new CompareToBuilder().append(o2, o1).toComparison() > 0);
393 assertTrue(new CompareToBuilder().append(o1, Double.MAX_VALUE).toComparison() < 0);
394 assertTrue(new CompareToBuilder().append(Double.MAX_VALUE, o1).toComparison() > 0);
395 assertTrue(new CompareToBuilder().append(o1, Double.MIN_VALUE).toComparison() > 0);
396 assertTrue(new CompareToBuilder().append(Double.MIN_VALUE, o1).toComparison() < 0);
397 assertTrue(new CompareToBuilder().append(Double.NaN, Double.NaN).toComparison() == 0);
398 assertTrue(new CompareToBuilder().append(Double.NaN, Double.MAX_VALUE).toComparison() > 0);
399 assertTrue(new CompareToBuilder().append(Double.POSITIVE_INFINITY, Double.MAX_VALUE).toComparison() > 0);
400 assertTrue(new CompareToBuilder().append(Double.NEGATIVE_INFINITY, Double.MIN_VALUE).toComparison() < 0);
401 assertTrue(new CompareToBuilder().append(o1, Double.NaN).toComparison() < 0);
402 assertTrue(new CompareToBuilder().append(Double.NaN, o1).toComparison() > 0);
403 assertTrue(new CompareToBuilder().append(-0.0, 0.0).toComparison() < 0);
404 assertTrue(new CompareToBuilder().append(0.0, -0.0).toComparison() > 0);
405 }
406
407 public void testFloat() {
408 float o1 = 1;
409 float o2 = 2;
410 assertTrue(new CompareToBuilder().append(o1, o1).toComparison() == 0);
411 assertTrue(new CompareToBuilder().append(o1, o2).toComparison() < 0);
412 assertTrue(new CompareToBuilder().append(o2, o1).toComparison() > 0);
413 assertTrue(new CompareToBuilder().append(o1, Float.MAX_VALUE).toComparison() < 0);
414 assertTrue(new CompareToBuilder().append(Float.MAX_VALUE, o1).toComparison() > 0);
415 assertTrue(new CompareToBuilder().append(o1, Float.MIN_VALUE).toComparison() > 0);
416 assertTrue(new CompareToBuilder().append(Float.MIN_VALUE, o1).toComparison() < 0);
417 assertTrue(new CompareToBuilder().append(Float.NaN, Float.NaN).toComparison() == 0);
418 assertTrue(new CompareToBuilder().append(Float.NaN, Float.MAX_VALUE).toComparison() > 0);
419 assertTrue(new CompareToBuilder().append(Float.POSITIVE_INFINITY, Float.MAX_VALUE).toComparison() > 0);
420 assertTrue(new CompareToBuilder().append(Float.NEGATIVE_INFINITY, Float.MIN_VALUE).toComparison() < 0);
421 assertTrue(new CompareToBuilder().append(o1, Float.NaN).toComparison() < 0);
422 assertTrue(new CompareToBuilder().append(Float.NaN, o1).toComparison() > 0);
423 assertTrue(new CompareToBuilder().append(-0.0, 0.0).toComparison() < 0);
424 assertTrue(new CompareToBuilder().append(0.0, -0.0).toComparison() > 0);
425 }
426
427 public void testBoolean() {
428 boolean o1 = true;
429 boolean o2 = false;
430 assertTrue(new CompareToBuilder().append(o1, o1).toComparison() == 0);
431 assertTrue(new CompareToBuilder().append(o2, o2).toComparison() == 0);
432 assertTrue(new CompareToBuilder().append(o1, o2).toComparison() > 0);
433 assertTrue(new CompareToBuilder().append(o2, o1).toComparison() < 0);
434 }
435
436 public void testObjectArray() {
437 TestObject[] obj1 = new TestObject[2];
438 obj1[0] = new TestObject(4);
439 obj1[1] = new TestObject(5);
440 TestObject[] obj2 = new TestObject[2];
441 obj2[0] = new TestObject(4);
442 obj2[1] = new TestObject(5);
443 TestObject[] obj3 = new TestObject[3];
444 obj3[0] = new TestObject(4);
445 obj3[1] = new TestObject(5);
446 obj3[2] = new TestObject(6);
447
448 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
449 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
450 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
451 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
452
453 obj1[1] = new TestObject(7);
454 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
455 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
456
457 assertTrue(new CompareToBuilder().append(obj1, null).toComparison() > 0);
458 assertTrue(new CompareToBuilder().append((Object[]) null, (Object[]) null).toComparison() == 0);
459 assertTrue(new CompareToBuilder().append(null, obj1).toComparison() < 0);
460 }
461
462 public void testLongArray() {
463 long[] obj1 = new long[2];
464 obj1[0] = 5L;
465 obj1[1] = 6L;
466 long[] obj2 = new long[2];
467 obj2[0] = 5L;
468 obj2[1] = 6L;
469 long[] obj3 = new long[3];
470 obj3[0] = 5L;
471 obj3[1] = 6L;
472 obj3[2] = 7L;
473
474 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
475 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
476 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
477 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
478
479 obj1[1] = 7;
480 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
481 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
482
483 assertTrue(new CompareToBuilder().append(obj1, null).toComparison() > 0);
484 assertTrue(new CompareToBuilder().append((long[]) null, (long[]) null).toComparison() == 0);
485 assertTrue(new CompareToBuilder().append(null, obj1).toComparison() < 0);
486 }
487
488 public void testIntArray() {
489 int[] obj1 = new int[2];
490 obj1[0] = 5;
491 obj1[1] = 6;
492 int[] obj2 = new int[2];
493 obj2[0] = 5;
494 obj2[1] = 6;
495 int[] obj3 = new int[3];
496 obj3[0] = 5;
497 obj3[1] = 6;
498 obj3[2] = 7;
499
500 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
501 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
502 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
503 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
504
505 obj1[1] = 7;
506 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
507 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
508
509 assertTrue(new CompareToBuilder().append(obj1, null).toComparison() > 0);
510 assertTrue(new CompareToBuilder().append((int[]) null, (int[]) null).toComparison() == 0);
511 assertTrue(new CompareToBuilder().append(null, obj1).toComparison() < 0);
512 }
513
514 public void testShortArray() {
515 short[] obj1 = new short[2];
516 obj1[0] = 5;
517 obj1[1] = 6;
518 short[] obj2 = new short[2];
519 obj2[0] = 5;
520 obj2[1] = 6;
521 short[] obj3 = new short[3];
522 obj3[0] = 5;
523 obj3[1] = 6;
524 obj3[2] = 7;
525
526 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
527 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
528 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
529 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
530
531 obj1[1] = 7;
532 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
533 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
534
535 assertTrue(new CompareToBuilder().append(obj1, null).toComparison() > 0);
536 assertTrue(new CompareToBuilder().append((short[]) null, (short[]) null).toComparison() == 0);
537 assertTrue(new CompareToBuilder().append(null, obj1).toComparison() < 0);
538 }
539
540 public void testCharArray() {
541 char[] obj1 = new char[2];
542 obj1[0] = 5;
543 obj1[1] = 6;
544 char[] obj2 = new char[2];
545 obj2[0] = 5;
546 obj2[1] = 6;
547 char[] obj3 = new char[3];
548 obj3[0] = 5;
549 obj3[1] = 6;
550 obj3[2] = 7;
551
552 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
553 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
554 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
555 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
556
557 obj1[1] = 7;
558 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
559 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
560
561 assertTrue(new CompareToBuilder().append(obj1, null).toComparison() > 0);
562 assertTrue(new CompareToBuilder().append((char[]) null, (char[]) null).toComparison() == 0);
563 assertTrue(new CompareToBuilder().append(null, obj1).toComparison() < 0);
564 }
565
566 public void testByteArray() {
567 byte[] obj1 = new byte[2];
568 obj1[0] = 5;
569 obj1[1] = 6;
570 byte[] obj2 = new byte[2];
571 obj2[0] = 5;
572 obj2[1] = 6;
573 byte[] obj3 = new byte[3];
574 obj3[0] = 5;
575 obj3[1] = 6;
576 obj3[2] = 7;
577
578 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
579 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
580 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
581 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
582
583 obj1[1] = 7;
584 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
585 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
586
587 assertTrue(new CompareToBuilder().append(obj1, null).toComparison() > 0);
588 assertTrue(new CompareToBuilder().append((byte[]) null, (byte[]) null).toComparison() == 0);
589 assertTrue(new CompareToBuilder().append(null, obj1).toComparison() < 0);
590 }
591
592 public void testDoubleArray() {
593 double[] obj1 = new double[2];
594 obj1[0] = 5;
595 obj1[1] = 6;
596 double[] obj2 = new double[2];
597 obj2[0] = 5;
598 obj2[1] = 6;
599 double[] obj3 = new double[3];
600 obj3[0] = 5;
601 obj3[1] = 6;
602 obj3[2] = 7;
603
604 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
605 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
606 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
607 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
608
609 obj1[1] = 7;
610 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
611 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
612
613 assertTrue(new CompareToBuilder().append(obj1, null).toComparison() > 0);
614 assertTrue(new CompareToBuilder().append((double[]) null, (double[]) null).toComparison() == 0);
615 assertTrue(new CompareToBuilder().append(null, obj1).toComparison() < 0);
616 }
617
618 public void testFloatArray() {
619 float[] obj1 = new float[2];
620 obj1[0] = 5;
621 obj1[1] = 6;
622 float[] obj2 = new float[2];
623 obj2[0] = 5;
624 obj2[1] = 6;
625 float[] obj3 = new float[3];
626 obj3[0] = 5;
627 obj3[1] = 6;
628 obj3[2] = 7;
629
630 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
631 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
632 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
633 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
634
635 obj1[1] = 7;
636 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
637 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
638
639 assertTrue(new CompareToBuilder().append(obj1, null).toComparison() > 0);
640 assertTrue(new CompareToBuilder().append((float[]) null, (float[]) null).toComparison() == 0);
641 assertTrue(new CompareToBuilder().append(null, obj1).toComparison() < 0);
642 }
643
644 public void testBooleanArray() {
645 boolean[] obj1 = new boolean[2];
646 obj1[0] = true;
647 obj1[1] = false;
648 boolean[] obj2 = new boolean[2];
649 obj2[0] = true;
650 obj2[1] = false;
651 boolean[] obj3 = new boolean[3];
652 obj3[0] = true;
653 obj3[1] = false;
654 obj3[2] = true;
655
656 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
657 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
658 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
659 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
660
661 obj1[1] = true;
662 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
663 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
664
665 assertTrue(new CompareToBuilder().append(obj1, null).toComparison() > 0);
666 assertTrue(new CompareToBuilder().append((boolean[]) null, (boolean[]) null).toComparison() == 0);
667 assertTrue(new CompareToBuilder().append(null, obj1).toComparison() < 0);
668 }
669
670 public void testMultiLongArray() {
671 long[][] array1 = new long[2][2];
672 long[][] array2 = new long[2][2];
673 long[][] array3 = new long[2][3];
674 for (int i = 0; i < array1.length; ++i) {
675 for (int j = 0; j < array1[0].length; j++) {
676 array1[i][j] = (i + 1) * (j + 1);
677 array2[i][j] = (i + 1) * (j + 1);
678 array3[i][j] = (i + 1) * (j + 1);
679 }
680 }
681 array3[1][2] = 100;
682 array3[1][2] = 100;
683
684 assertTrue(new CompareToBuilder().append(array1, array1).toComparison() == 0);
685 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() == 0);
686 assertTrue(new CompareToBuilder().append(array1, array3).toComparison() < 0);
687 assertTrue(new CompareToBuilder().append(array3, array1).toComparison() > 0);
688 array1[1][1] = 200;
689 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() > 0);
690 assertTrue(new CompareToBuilder().append(array2, array1).toComparison() < 0);
691 }
692
693 public void testMultiIntArray() {
694 int[][] array1 = new int[2][2];
695 int[][] array2 = new int[2][2];
696 int[][] array3 = new int[2][3];
697 for (int i = 0; i < array1.length; ++i) {
698 for (int j = 0; j < array1[0].length; j++) {
699 array1[i][j] = (i + 1) * (j + 1);
700 array2[i][j] = (i + 1) * (j + 1);
701 array3[i][j] = (i + 1) * (j + 1);
702 }
703 }
704 array3[1][2] = 100;
705 array3[1][2] = 100;
706
707 assertTrue(new CompareToBuilder().append(array1, array1).toComparison() == 0);
708 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() == 0);
709 assertTrue(new CompareToBuilder().append(array1, array3).toComparison() < 0);
710 assertTrue(new CompareToBuilder().append(array3, array1).toComparison() > 0);
711 array1[1][1] = 200;
712 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() > 0);
713 assertTrue(new CompareToBuilder().append(array2, array1).toComparison() < 0);
714 }
715
716 public void testMultiShortArray() {
717 short[][] array1 = new short[2][2];
718 short[][] array2 = new short[2][2];
719 short[][] array3 = new short[2][3];
720 for (short i = 0; i < array1.length; ++i) {
721 for (short j = 0; j < array1[0].length; j++) {
722 array1[i][j] = (short)((i + 1) * (j + 1));
723 array2[i][j] = (short)((i + 1) * (j + 1));
724 array3[i][j] = (short)((i + 1) * (j + 1));
725 }
726 }
727 array3[1][2] = 100;
728 array3[1][2] = 100;
729
730 assertTrue(new CompareToBuilder().append(array1, array1).toComparison() == 0);
731 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() == 0);
732 assertTrue(new CompareToBuilder().append(array1, array3).toComparison() < 0);
733 assertTrue(new CompareToBuilder().append(array3, array1).toComparison() > 0);
734 array1[1][1] = 200;
735 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() > 0);
736 assertTrue(new CompareToBuilder().append(array2, array1).toComparison() < 0);
737 }
738
739 public void testMultiCharArray() {
740 char[][] array1 = new char[2][2];
741 char[][] array2 = new char[2][2];
742 char[][] array3 = new char[2][3];
743 for (short i = 0; i < array1.length; ++i) {
744 for (short j = 0; j < array1[0].length; j++) {
745 array1[i][j] = (char)((i + 1) * (j + 1));
746 array2[i][j] = (char)((i + 1) * (j + 1));
747 array3[i][j] = (char)((i + 1) * (j + 1));
748 }
749 }
750 array3[1][2] = 100;
751 array3[1][2] = 100;
752
753 assertTrue(new CompareToBuilder().append(array1, array1).toComparison() == 0);
754 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() == 0);
755 assertTrue(new CompareToBuilder().append(array1, array3).toComparison() < 0);
756 assertTrue(new CompareToBuilder().append(array3, array1).toComparison() > 0);
757 array1[1][1] = 200;
758 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() > 0);
759 assertTrue(new CompareToBuilder().append(array2, array1).toComparison() < 0);
760 }
761
762 public void testMultiByteArray() {
763 byte[][] array1 = new byte[2][2];
764 byte[][] array2 = new byte[2][2];
765 byte[][] array3 = new byte[2][3];
766 for (byte i = 0; i < array1.length; ++i) {
767 for (byte j = 0; j < array1[0].length; j++) {
768 array1[i][j] = (byte)((i + 1) * (j + 1));
769 array2[i][j] = (byte)((i + 1) * (j + 1));
770 array3[i][j] = (byte)((i + 1) * (j + 1));
771 }
772 }
773 array3[1][2] = 100;
774 array3[1][2] = 100;
775
776 assertTrue(new CompareToBuilder().append(array1, array1).toComparison() == 0);
777 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() == 0);
778 assertTrue(new CompareToBuilder().append(array1, array3).toComparison() < 0);
779 assertTrue(new CompareToBuilder().append(array3, array1).toComparison() > 0);
780 array1[1][1] = 127;
781 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() > 0);
782 assertTrue(new CompareToBuilder().append(array2, array1).toComparison() < 0);
783 }
784
785 public void testMultiFloatArray() {
786 float[][] array1 = new float[2][2];
787 float[][] array2 = new float[2][2];
788 float[][] array3 = new float[2][3];
789 for (int i = 0; i < array1.length; ++i) {
790 for (int j = 0; j < array1[0].length; j++) {
791 array1[i][j] = ((i + 1) * (j + 1));
792 array2[i][j] = ((i + 1) * (j + 1));
793 array3[i][j] = ((i + 1) * (j + 1));
794 }
795 }
796 array3[1][2] = 100;
797 array3[1][2] = 100;
798
799 assertTrue(new CompareToBuilder().append(array1, array1).toComparison() == 0);
800 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() == 0);
801 assertTrue(new CompareToBuilder().append(array1, array3).toComparison() < 0);
802 assertTrue(new CompareToBuilder().append(array3, array1).toComparison() > 0);
803 array1[1][1] = 127;
804 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() > 0);
805 assertTrue(new CompareToBuilder().append(array2, array1).toComparison() < 0);
806 }
807
808 public void testMultiDoubleArray() {
809 double[][] array1 = new double[2][2];
810 double[][] array2 = new double[2][2];
811 double[][] array3 = new double[2][3];
812 for (int i = 0; i < array1.length; ++i) {
813 for (int j = 0; j < array1[0].length; j++) {
814 array1[i][j] = ((i + 1) * (j + 1));
815 array2[i][j] = ((i + 1) * (j + 1));
816 array3[i][j] = ((i + 1) * (j + 1));
817 }
818 }
819 array3[1][2] = 100;
820 array3[1][2] = 100;
821
822 assertTrue(new CompareToBuilder().append(array1, array1).toComparison() == 0);
823 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() == 0);
824 assertTrue(new CompareToBuilder().append(array1, array3).toComparison() < 0);
825 assertTrue(new CompareToBuilder().append(array3, array1).toComparison() > 0);
826 array1[1][1] = 127;
827 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() > 0);
828 assertTrue(new CompareToBuilder().append(array2, array1).toComparison() < 0);
829 }
830
831 public void testMultiBooleanArray() {
832 boolean[][] array1 = new boolean[2][2];
833 boolean[][] array2 = new boolean[2][2];
834 boolean[][] array3 = new boolean[2][3];
835 for (int i = 0; i < array1.length; ++i) {
836 for (int j = 0; j < array1[0].length; j++) {
837 array1[i][j] = ((i == 1) ^ (j == 1));
838 array2[i][j] = ((i == 1) ^ (j == 1));
839 array3[i][j] = ((i == 1) ^ (j == 1));
840 }
841 }
842 array3[1][2] = false;
843 array3[1][2] = false;
844
845 assertTrue(new CompareToBuilder().append(array1, array1).toComparison() == 0);
846 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() == 0);
847 assertTrue(new CompareToBuilder().append(array1, array3).toComparison() < 0);
848 assertTrue(new CompareToBuilder().append(array3, array1).toComparison() > 0);
849 array1[1][1] = true;
850 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() > 0);
851 assertTrue(new CompareToBuilder().append(array2, array1).toComparison() < 0);
852 }
853
854 public void testRaggedArray() {
855 long array1[][] = new long[2][];
856 long array2[][] = new long[2][];
857 long array3[][] = new long[3][];
858 for (int i = 0; i < array1.length; ++i) {
859 array1[i] = new long[2];
860 array2[i] = new long[2];
861 array3[i] = new long[3];
862 for (int j = 0; j < array1[i].length; ++j) {
863 array1[i][j] = (i + 1) * (j + 1);
864 array2[i][j] = (i + 1) * (j + 1);
865 array3[i][j] = (i + 1) * (j + 1);
866 }
867 }
868 array3[1][2] = 100;
869 array3[1][2] = 100;
870
871
872 assertTrue(new CompareToBuilder().append(array1, array1).toComparison() == 0);
873 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() == 0);
874 assertTrue(new CompareToBuilder().append(array1, array3).toComparison() < 0);
875 assertTrue(new CompareToBuilder().append(array3, array1).toComparison() > 0);
876 array1[1][1] = 200;
877 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() > 0);
878 assertTrue(new CompareToBuilder().append(array2, array1).toComparison() < 0);
879 }
880
881 public void testMixedArray() {
882 Object array1[] = new Object[2];
883 Object array2[] = new Object[2];
884 Object array3[] = new Object[2];
885 for (int i = 0; i < array1.length; ++i) {
886 array1[i] = new long[2];
887 array2[i] = new long[2];
888 array3[i] = new long[3];
889 for (int j = 0; j < 2; ++j) {
890 ((long[]) array1[i])[j] = (i + 1) * (j + 1);
891 ((long[]) array2[i])[j] = (i + 1) * (j + 1);
892 ((long[]) array3[i])[j] = (i + 1) * (j + 1);
893 }
894 }
895 ((long[]) array3[0])[2] = 1;
896 ((long[]) array3[1])[2] = 1;
897 assertTrue(new CompareToBuilder().append(array1, array1).toComparison() == 0);
898 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() == 0);
899 assertTrue(new CompareToBuilder().append(array1, array3).toComparison() < 0);
900 assertTrue(new CompareToBuilder().append(array3, array1).toComparison() > 0);
901 ((long[]) array1[1])[1] = 200;
902 assertTrue(new CompareToBuilder().append(array1, array2).toComparison() > 0);
903 assertTrue(new CompareToBuilder().append(array2, array1).toComparison() < 0);
904 }
905
906 public void testObjectArrayHiddenByObject() {
907 TestObject[] array1 = new TestObject[2];
908 array1[0] = new TestObject(4);
909 array1[1] = new TestObject(5);
910 TestObject[] array2 = new TestObject[2];
911 array2[0] = new TestObject(4);
912 array2[1] = new TestObject(5);
913 TestObject[] array3 = new TestObject[3];
914 array3[0] = new TestObject(4);
915 array3[1] = new TestObject(5);
916 array3[2] = new TestObject(6);
917
918 Object obj1 = array1;
919 Object obj2 = array2;
920 Object obj3 = array3;
921
922 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
923 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
924 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
925 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
926
927 array1[1] = new TestObject(7);
928 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
929 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
930 }
931
932 public void testLongArrayHiddenByObject() {
933 long[] array1 = new long[2];
934 array1[0] = 5L;
935 array1[1] = 6L;
936 long[] array2 = new long[2];
937 array2[0] = 5L;
938 array2[1] = 6L;
939 long[] array3 = new long[3];
940 array3[0] = 5L;
941 array3[1] = 6L;
942 array3[2] = 7L;
943 Object obj1 = array1;
944 Object obj2 = array2;
945 Object obj3 = array3;
946 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
947 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
948 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
949 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
950
951 array1[1] = 7;
952 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
953 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
954 }
955
956 public void testIntArrayHiddenByObject() {
957 int[] array1 = new int[2];
958 array1[0] = 5;
959 array1[1] = 6;
960 int[] array2 = new int[2];
961 array2[0] = 5;
962 array2[1] = 6;
963 int[] array3 = new int[3];
964 array3[0] = 5;
965 array3[1] = 6;
966 array3[2] = 7;
967 Object obj1 = array1;
968 Object obj2 = array2;
969 Object obj3 = array3;
970 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
971 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
972 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
973 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
974
975 array1[1] = 7;
976 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
977 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
978 }
979
980 public void testShortArrayHiddenByObject() {
981 short[] array1 = new short[2];
982 array1[0] = 5;
983 array1[1] = 6;
984 short[] array2 = new short[2];
985 array2[0] = 5;
986 array2[1] = 6;
987 short[] array3 = new short[3];
988 array3[0] = 5;
989 array3[1] = 6;
990 array3[2] = 7;
991 Object obj1 = array1;
992 Object obj2 = array2;
993 Object obj3 = array3;
994 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
995 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
996 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
997 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
998
999 array1[1] = 7;
1000 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
1001 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
1002 }
1003
1004 public void testCharArrayHiddenByObject() {
1005 char[] array1 = new char[2];
1006 array1[0] = 5;
1007 array1[1] = 6;
1008 char[] array2 = new char[2];
1009 array2[0] = 5;
1010 array2[1] = 6;
1011 char[] array3 = new char[3];
1012 array3[0] = 5;
1013 array3[1] = 6;
1014 array3[2] = 7;
1015 Object obj1 = array1;
1016 Object obj2 = array2;
1017 Object obj3 = array3;
1018 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
1019 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
1020 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
1021 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
1022
1023 array1[1] = 7;
1024 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
1025 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
1026 }
1027
1028 public void testByteArrayHiddenByObject() {
1029 byte[] array1 = new byte[2];
1030 array1[0] = 5;
1031 array1[1] = 6;
1032 byte[] array2 = new byte[2];
1033 array2[0] = 5;
1034 array2[1] = 6;
1035 byte[] array3 = new byte[3];
1036 array3[0] = 5;
1037 array3[1] = 6;
1038 array3[2] = 7;
1039 Object obj1 = array1;
1040 Object obj2 = array2;
1041 Object obj3 = array3;
1042 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
1043 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
1044 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
1045 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
1046
1047 array1[1] = 7;
1048 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
1049 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
1050 }
1051
1052 public void testDoubleArrayHiddenByObject() {
1053 double[] array1 = new double[2];
1054 array1[0] = 5;
1055 array1[1] = 6;
1056 double[] array2 = new double[2];
1057 array2[0] = 5;
1058 array2[1] = 6;
1059 double[] array3 = new double[3];
1060 array3[0] = 5;
1061 array3[1] = 6;
1062 array3[2] = 7;
1063 Object obj1 = array1;
1064 Object obj2 = array2;
1065 Object obj3 = array3;
1066 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
1067 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
1068 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
1069 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
1070
1071 array1[1] = 7;
1072 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
1073 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
1074 }
1075
1076 public void testFloatArrayHiddenByObject() {
1077 float[] array1 = new float[2];
1078 array1[0] = 5;
1079 array1[1] = 6;
1080 float[] array2 = new float[2];
1081 array2[0] = 5;
1082 array2[1] = 6;
1083 float[] array3 = new float[3];
1084 array3[0] = 5;
1085 array3[1] = 6;
1086 array3[2] = 7;
1087 Object obj1 = array1;
1088 Object obj2 = array2;
1089 Object obj3 = array3;
1090 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
1091 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
1092 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
1093 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
1094
1095 array1[1] = 7;
1096 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
1097 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
1098 }
1099
1100 public void testBooleanArrayHiddenByObject() {
1101 boolean[] array1 = new boolean[2];
1102 array1[0] = true;
1103 array1[1] = false;
1104 boolean[] array2 = new boolean[2];
1105 array2[0] = true;
1106 array2[1] = false;
1107 boolean[] array3 = new boolean[3];
1108 array3[0] = true;
1109 array3[1] = false;
1110 array3[2] = true;
1111 Object obj1 = array1;
1112 Object obj2 = array2;
1113 Object obj3 = array3;
1114 assertTrue(new CompareToBuilder().append(obj1, obj1).toComparison() == 0);
1115 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() == 0);
1116 assertTrue(new CompareToBuilder().append(obj1, obj3).toComparison() < 0);
1117 assertTrue(new CompareToBuilder().append(obj3, obj1).toComparison() > 0);
1118
1119 array1[1] = true;
1120 assertTrue(new CompareToBuilder().append(obj1, obj2).toComparison() > 0);
1121 assertTrue(new CompareToBuilder().append(obj2, obj1).toComparison() < 0);
1122 }
1123
1124 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20
21 import junit.framework.TestCase;
22
23 import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
24
25 /**
26 * Unit tests {@link org.apache.commons.lang3.builder.DefaultToStringStyleTest}.
27 *
28 * @version $Id: DefaultToStringStyleTest.java 1153484 2011-08-03 13:39:42Z ggregory $
29 */
30 public class DefaultToStringStyleTest extends TestCase {
31
32 private final Integer base = Integer.valueOf(5);
33 private final String baseStr = base.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(base));
34
35 public DefaultToStringStyleTest(String name) {
36 super(name);
37 }
38
39 @Override
40 protected void setUp() throws Exception {
41 super.setUp();
42 ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
43 }
44
45 @Override
46 protected void tearDown() throws Exception {
47 super.tearDown();
48 ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
49 }
50
51 //----------------------------------------------------------------
52
53 public void testBlank() {
54 assertEquals(baseStr + "[]", new ToStringBuilder(base).toString());
55 }
56
57 public void testAppendSuper() {
58 assertEquals(baseStr + "[]", new ToStringBuilder(base).appendSuper("Integer@8888[]").toString());
59 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").toString());
60
61 assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper("Integer@8888[]").append("a", "hello").toString());
62 assertEquals(baseStr + "[<null>,a=hello]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").append("a", "hello").toString());
63 assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper(null).append("a", "hello").toString());
64 }
65
66 public void testObject() {
67 Integer i3 = Integer.valueOf(3);
68 Integer i4 = Integer.valueOf(4);
69 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) null).toString());
70 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(i3).toString());
71 assertEquals(baseStr + "[a=<null>]", new ToStringBuilder(base).append("a", (Object) null).toString());
72 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", i3).toString());
73 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", i3).append("b", i4).toString());
74 assertEquals(baseStr + "[a=<Integer>]", new ToStringBuilder(base).append("a", i3, false).toString());
75 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), false).toString());
76 assertEquals(baseStr + "[a=[]]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), true).toString());
77 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), false).toString());
78 assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), true).toString());
79 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", (Object) new String[0], false).toString());
80 assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", (Object) new String[0], true).toString());
81 }
82
83 public void testPerson() {
84 Person p = new Person();
85 p.name = "John Doe";
86 p.age = 33;
87 p.smoker = false;
88 String pBaseStr = p.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(p));
89 assertEquals(pBaseStr + "[name=John Doe,age=33,smoker=false]", new ToStringBuilder(p).append("name", p.name).append("age", p.age).append("smoker", p.smoker).toString());
90 }
91
92 public void testLong() {
93 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(3L).toString());
94 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", 3L).toString());
95 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", 3L).append("b", 4L).toString());
96 }
97
98 public void testObjectArray() {
99 Object[] array = new Object[] {null, base, new int[] {3, 6}};
100 assertEquals(baseStr + "[{<null>,5,{3,6}}]", new ToStringBuilder(base).append(array).toString());
101 assertEquals(baseStr + "[{<null>,5,{3,6}}]", new ToStringBuilder(base).append((Object) array).toString());
102 array = null;
103 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
104 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
105 }
106
107 public void testLongArray() {
108 long[] array = new long[] {1, 2, -3, 4};
109 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append(array).toString());
110 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append((Object) array).toString());
111 array = null;
112 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
113 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
114 }
115
116 public void testLongArrayArray() {
117 long[][] array = new long[][] {{1, 2}, null, {5}};
118 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append(array).toString());
119 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append((Object) array).toString());
120 array = null;
121 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
122 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
123 }
124
125 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.util.Arrays;
19
20 import junit.framework.TestCase;
21
22 /**
23 * Unit tests {@link org.apache.commons.lang3.builder.EqualsBuilder}.
24 *
25 * @version $Id: EqualsBuilderTest.java 1153484 2011-08-03 13:39:42Z ggregory $
26 */
27 public class EqualsBuilderTest extends TestCase {
28
29 public EqualsBuilderTest(String name) {
30 super(name);
31 }
32
33 //-----------------------------------------------------------------------
34
35 static class TestObject {
36 private int a;
37 public TestObject() {
38 }
39 public TestObject(int a) {
40 this.a = a;
41 }
42 @Override
43 public boolean equals(Object o) {
44 if (o == null) { return false; }
45 if (o == this) { return true; }
46 if (o.getClass() != getClass()) {
47 return false;
48 }
49
50 TestObject rhs = (TestObject) o;
51 return (a == rhs.a);
52 }
53
54 public void setA(int a) {
55 this.a = a;
56 }
57
58 public int getA() {
59 return a;
60 }
61 }
62
63 static class TestSubObject extends TestObject {
64 private int b;
65 public TestSubObject() {
66 super(0);
67 }
68 public TestSubObject(int a, int b) {
69 super(a);
70 this.b = b;
71 }
72 @Override
73 public boolean equals(Object o) {
74 if (o == null) { return false; }
75 if (o == this) { return true; }
76 if (o.getClass() != getClass()) {
77 return false;
78 }
79
80 TestSubObject rhs = (TestSubObject) o;
81 return super.equals(o) && (b == rhs.b);
82 }
83
84 public void setB(int b) {
85 this.b = b;
86 }
87
88 public int getB() {
89 return b;
90 }
91 }
92
93 static class TestEmptySubObject extends TestObject {
94 public TestEmptySubObject(int a) {
95 super(a);
96 }
97 }
98
99 static class TestTSubObject extends TestObject {
100 @SuppressWarnings("unused")
101 private transient int t;
102 public TestTSubObject(int a, int t) {
103 super(a);
104 this.t = t;
105 }
106 }
107
108 static class TestTTSubObject extends TestTSubObject {
109 @SuppressWarnings("unused")
110 private transient int tt;
111 public TestTTSubObject(int a, int t, int tt) {
112 super(a, t);
113 this.tt = tt;
114 }
115 }
116
117 static class TestTTLeafObject extends TestTTSubObject {
118 @SuppressWarnings("unused")
119 private int leafValue;
120 public TestTTLeafObject(int a, int t, int tt, int leafValue) {
121 super(a, t, tt);
122 this.leafValue = leafValue;
123 }
124 }
125
126 static class TestTSubObject2 extends TestObject {
127 private transient int t;
128 public TestTSubObject2(int a, int t) {
129 super(a);
130 }
131 public int getT() {
132 return t;
133 }
134 public void setT(int t) {
135 this.t = t;
136 }
137 }
138
139 public void testReflectionEquals() {
140 TestObject o1 = new TestObject(4);
141 TestObject o2 = new TestObject(5);
142 assertTrue(EqualsBuilder.reflectionEquals(o1, o1));
143 assertTrue(!EqualsBuilder.reflectionEquals(o1, o2));
144 o2.setA(4);
145 assertTrue(EqualsBuilder.reflectionEquals(o1, o2));
146
147 assertTrue(!EqualsBuilder.reflectionEquals(o1, this));
148
149 assertTrue(!EqualsBuilder.reflectionEquals(o1, null));
150 assertTrue(!EqualsBuilder.reflectionEquals(null, o2));
151 assertTrue(EqualsBuilder.reflectionEquals((Object) null, (Object) null));
152 }
153
154 public void testReflectionHierarchyEquals() {
155 testReflectionHierarchyEquals(false);
156 testReflectionHierarchyEquals(true);
157 // Transients
158 assertTrue(EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), true));
159 assertTrue(EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), false));
160 assertTrue(!EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 0, 0, 4), new TestTTLeafObject(1, 2, 3, 4), true));
161 assertTrue(!EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 0), true));
162 assertTrue(!EqualsBuilder.reflectionEquals(new TestTTLeafObject(0, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), true));
163 }
164
165 public void testReflectionHierarchyEquals(boolean testTransients) {
166 TestObject to1 = new TestObject(4);
167 TestObject to1Bis = new TestObject(4);
168 TestObject to1Ter = new TestObject(4);
169 TestObject to2 = new TestObject(5);
170 TestEmptySubObject teso = new TestEmptySubObject(4);
171 TestTSubObject ttso = new TestTSubObject(4, 1);
172 TestTTSubObject tttso = new TestTTSubObject(4, 1, 2);
173 TestTTLeafObject ttlo = new TestTTLeafObject(4, 1, 2, 3);
174 TestSubObject tso1 = new TestSubObject(1, 4);
175 TestSubObject tso1bis = new TestSubObject(1, 4);
176 TestSubObject tso1ter = new TestSubObject(1, 4);
177 TestSubObject tso2 = new TestSubObject(2, 5);
178
179 testReflectionEqualsEquivalenceRelationship(to1, to1Bis, to1Ter, to2, new TestObject(), testTransients);
180 testReflectionEqualsEquivalenceRelationship(tso1, tso1bis, tso1ter, tso2, new TestSubObject(), testTransients);
181
182 // More sanity checks:
183
184 // same values
185 assertTrue(EqualsBuilder.reflectionEquals(ttlo, ttlo, testTransients));
186 assertTrue(EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(1, 10), testTransients));
187 // same super values, diff sub values
188 assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(1, 11), testTransients));
189 assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(1, 11), new TestSubObject(1, 10), testTransients));
190 // diff super values, same sub values
191 assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(0, 10), new TestSubObject(1, 10), testTransients));
192 assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(0, 10), testTransients));
193
194 // mix super and sub types: equals
195 assertTrue(EqualsBuilder.reflectionEquals(to1, teso, testTransients));
196 assertTrue(EqualsBuilder.reflectionEquals(teso, to1, testTransients));
197
198 assertTrue(EqualsBuilder.reflectionEquals(to1, ttso, false)); // Force testTransients = false for this assert
199 assertTrue(EqualsBuilder.reflectionEquals(ttso, to1, false)); // Force testTransients = false for this assert
200
201 assertTrue(EqualsBuilder.reflectionEquals(to1, tttso, false)); // Force testTransients = false for this assert
202 assertTrue(EqualsBuilder.reflectionEquals(tttso, to1, false)); // Force testTransients = false for this assert
203
204 assertTrue(EqualsBuilder.reflectionEquals(ttso, tttso, false)); // Force testTransients = false for this assert
205 assertTrue(EqualsBuilder.reflectionEquals(tttso, ttso, false)); // Force testTransients = false for this assert
206
207 // mix super and sub types: NOT equals
208 assertTrue(!EqualsBuilder.reflectionEquals(new TestObject(0), new TestEmptySubObject(1), testTransients));
209 assertTrue(!EqualsBuilder.reflectionEquals(new TestEmptySubObject(1), new TestObject(0), testTransients));
210
211 assertTrue(!EqualsBuilder.reflectionEquals(new TestObject(0), new TestTSubObject(1, 1), testTransients));
212 assertTrue(!EqualsBuilder.reflectionEquals(new TestTSubObject(1, 1), new TestObject(0), testTransients));
213
214 assertTrue(!EqualsBuilder.reflectionEquals(new TestObject(1), new TestSubObject(0, 10), testTransients));
215 assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(0, 10), new TestObject(1), testTransients));
216
217 assertTrue(!EqualsBuilder.reflectionEquals(to1, ttlo));
218 assertTrue(!EqualsBuilder.reflectionEquals(tso1, this));
219 }
220
221 /**
222 * Equivalence relationship tests inspired by "Effective Java":
223 * <ul>
224 * <li>reflection</li>
225 * <li>symmetry</li>
226 * <li>transitive</li>
227 * <li>consistency</li>
228 * <li>non-null reference</li>
229 * </ul>
230 * @param to a TestObject
231 * @param toBis a TestObject, equal to to and toTer
232 * @param toTer Left hand side, equal to to and toBis
233 * @param to2 a different TestObject
234 * @param oToChange a TestObject that will be changed
235 * @param testTransients whether to test transient instance variables
236 */
237 public void testReflectionEqualsEquivalenceRelationship(
238 TestObject to,
239 TestObject toBis,
240 TestObject toTer,
241 TestObject to2,
242 TestObject oToChange,
243 boolean testTransients) {
244
245 // reflection test
246 assertTrue(EqualsBuilder.reflectionEquals(to, to, testTransients));
247 assertTrue(EqualsBuilder.reflectionEquals(to2, to2, testTransients));
248
249 // symmetry test
250 assertTrue(EqualsBuilder.reflectionEquals(to, toBis, testTransients) && EqualsBuilder.reflectionEquals(toBis, to, testTransients));
251
252 // transitive test
253 assertTrue(
254 EqualsBuilder.reflectionEquals(to, toBis, testTransients)
255 && EqualsBuilder.reflectionEquals(toBis, toTer, testTransients)
256 && EqualsBuilder.reflectionEquals(to, toTer, testTransients));
257
258 // consistency test
259 oToChange.setA(to.getA());
260 if (oToChange instanceof TestSubObject) {
261 ((TestSubObject) oToChange).setB(((TestSubObject) to).getB());
262 }
263 assertTrue(EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
264 assertTrue(EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
265 oToChange.setA(to.getA() + 1);
266 if (oToChange instanceof TestSubObject) {
267 ((TestSubObject) oToChange).setB(((TestSubObject) to).getB() + 1);
268 }
269 assertTrue(!EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
270 assertTrue(!EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
271
272 // non-null reference test
273 assertTrue(!EqualsBuilder.reflectionEquals(to, null, testTransients));
274 assertTrue(!EqualsBuilder.reflectionEquals(to2, null, testTransients));
275 assertTrue(!EqualsBuilder.reflectionEquals(null, to, testTransients));
276 assertTrue(!EqualsBuilder.reflectionEquals(null, to2, testTransients));
277 assertTrue(EqualsBuilder.reflectionEquals((Object) null, (Object) null, testTransients));
278 }
279
280 public void testSuper() {
281 TestObject o1 = new TestObject(4);
282 TestObject o2 = new TestObject(5);
283 assertEquals(true, new EqualsBuilder().appendSuper(true).append(o1, o1).isEquals());
284 assertEquals(false, new EqualsBuilder().appendSuper(false).append(o1, o1).isEquals());
285 assertEquals(false, new EqualsBuilder().appendSuper(true).append(o1, o2).isEquals());
286 assertEquals(false, new EqualsBuilder().appendSuper(false).append(o1, o2).isEquals());
287 }
288
289 public void testObject() {
290 TestObject o1 = new TestObject(4);
291 TestObject o2 = new TestObject(5);
292 assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
293 assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
294 o2.setA(4);
295 assertTrue(new EqualsBuilder().append(o1, o2).isEquals());
296
297 assertTrue(!new EqualsBuilder().append(o1, this).isEquals());
298
299 assertTrue(!new EqualsBuilder().append(o1, null).isEquals());
300 assertTrue(!new EqualsBuilder().append(null, o2).isEquals());
301 assertTrue(new EqualsBuilder().append((Object) null, (Object) null).isEquals());
302 }
303
304 public void testObjectBuild() {
305 TestObject o1 = new TestObject(4);
306 TestObject o2 = new TestObject(5);
307 assertTrue(new EqualsBuilder().append(o1, o1).build());
308 assertTrue(!new EqualsBuilder().append(o1, o2).build());
309 o2.setA(4);
310 assertTrue(new EqualsBuilder().append(o1, o2).build());
311
312 assertTrue(!new EqualsBuilder().append(o1, this).build());
313
314 assertTrue(!new EqualsBuilder().append(o1, null).build());
315 assertTrue(!new EqualsBuilder().append(null, o2).build());
316 assertTrue(new EqualsBuilder().append((Object) null, (Object) null).build());
317 }
318
319 public void testLong() {
320 long o1 = 1L;
321 long o2 = 2L;
322 assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
323 assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
324 }
325
326 public void testInt() {
327 int o1 = 1;
328 int o2 = 2;
329 assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
330 assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
331 }
332
333 public void testShort() {
334 short o1 = 1;
335 short o2 = 2;
336 assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
337 assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
338 }
339
340 public void testChar() {
341 char o1 = 1;
342 char o2 = 2;
343 assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
344 assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
345 }
346
347 public void testByte() {
348 byte o1 = 1;
349 byte o2 = 2;
350 assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
351 assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
352 }
353
354 public void testDouble() {
355 double o1 = 1;
356 double o2 = 2;
357 assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
358 assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
359 assertTrue(!new EqualsBuilder().append(o1, Double.NaN).isEquals());
360 assertTrue(new EqualsBuilder().append(Double.NaN, Double.NaN).isEquals());
361 assertTrue(new EqualsBuilder().append(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY).isEquals());
362 }
363
364 public void testFloat() {
365 float o1 = 1;
366 float o2 = 2;
367 assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
368 assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
369 assertTrue(!new EqualsBuilder().append(o1, Float.NaN).isEquals());
370 assertTrue(new EqualsBuilder().append(Float.NaN, Float.NaN).isEquals());
371 assertTrue(new EqualsBuilder().append(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY).isEquals());
372 }
373
374 public void testAccessors() {
375 EqualsBuilder equalsBuilder = new EqualsBuilder();
376 assertTrue(equalsBuilder.isEquals());
377 equalsBuilder.setEquals(true);
378 assertTrue(equalsBuilder.isEquals());
379 equalsBuilder.setEquals(false);
380 assertFalse(equalsBuilder.isEquals());
381 }
382
383 public void testReset() {
384 EqualsBuilder equalsBuilder = new EqualsBuilder();
385 assertTrue(equalsBuilder.isEquals());
386 equalsBuilder.setEquals(false);
387 assertFalse(equalsBuilder.isEquals());
388 equalsBuilder.reset();
389 assertTrue(equalsBuilder.isEquals());
390 }
391
392 public void testBoolean() {
393 boolean o1 = true;
394 boolean o2 = false;
395 assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
396 assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
397 }
398
399 public void testObjectArray() {
400 TestObject[] obj1 = new TestObject[3];
401 obj1[0] = new TestObject(4);
402 obj1[1] = new TestObject(5);
403 obj1[2] = null;
404 TestObject[] obj2 = new TestObject[3];
405 obj2[0] = new TestObject(4);
406 obj2[1] = new TestObject(5);
407 obj2[2] = null;
408
409 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
410 assertTrue(new EqualsBuilder().append(obj2, obj2).isEquals());
411 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
412 obj1[1].setA(6);
413 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
414 obj1[1].setA(5);
415 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
416 obj1[2] = obj1[1];
417 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
418 obj1[2] = null;
419 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
420
421 obj2 = null;
422 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
423 obj1 = null;
424 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
425 }
426
427 public void testLongArray() {
428 long[] obj1 = new long[2];
429 obj1[0] = 5L;
430 obj1[1] = 6L;
431 long[] obj2 = new long[2];
432 obj2[0] = 5L;
433 obj2[1] = 6L;
434 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
435 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
436 obj1[1] = 7;
437 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
438
439 obj2 = null;
440 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
441 obj1 = null;
442 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
443 }
444
445 public void testIntArray() {
446 int[] obj1 = new int[2];
447 obj1[0] = 5;
448 obj1[1] = 6;
449 int[] obj2 = new int[2];
450 obj2[0] = 5;
451 obj2[1] = 6;
452 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
453 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
454 obj1[1] = 7;
455 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
456
457 obj2 = null;
458 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
459 obj1 = null;
460 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
461 }
462
463 public void testShortArray() {
464 short[] obj1 = new short[2];
465 obj1[0] = 5;
466 obj1[1] = 6;
467 short[] obj2 = new short[2];
468 obj2[0] = 5;
469 obj2[1] = 6;
470 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
471 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
472 obj1[1] = 7;
473 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
474
475 obj2 = null;
476 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
477 obj1 = null;
478 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
479 }
480
481 public void testCharArray() {
482 char[] obj1 = new char[2];
483 obj1[0] = 5;
484 obj1[1] = 6;
485 char[] obj2 = new char[2];
486 obj2[0] = 5;
487 obj2[1] = 6;
488 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
489 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
490 obj1[1] = 7;
491 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
492
493 obj2 = null;
494 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
495 obj1 = null;
496 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
497 }
498
499 public void testByteArray() {
500 byte[] obj1 = new byte[2];
501 obj1[0] = 5;
502 obj1[1] = 6;
503 byte[] obj2 = new byte[2];
504 obj2[0] = 5;
505 obj2[1] = 6;
506 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
507 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
508 obj1[1] = 7;
509 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
510
511 obj2 = null;
512 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
513 obj1 = null;
514 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
515 }
516
517 public void testDoubleArray() {
518 double[] obj1 = new double[2];
519 obj1[0] = 5;
520 obj1[1] = 6;
521 double[] obj2 = new double[2];
522 obj2[0] = 5;
523 obj2[1] = 6;
524 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
525 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
526 obj1[1] = 7;
527 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
528
529 obj2 = null;
530 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
531 obj1 = null;
532 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
533 }
534
535 public void testFloatArray() {
536 float[] obj1 = new float[2];
537 obj1[0] = 5;
538 obj1[1] = 6;
539 float[] obj2 = new float[2];
540 obj2[0] = 5;
541 obj2[1] = 6;
542 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
543 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
544 obj1[1] = 7;
545 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
546
547 obj2 = null;
548 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
549 obj1 = null;
550 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
551 }
552
553 public void testBooleanArray() {
554 boolean[] obj1 = new boolean[2];
555 obj1[0] = true;
556 obj1[1] = false;
557 boolean[] obj2 = new boolean[2];
558 obj2[0] = true;
559 obj2[1] = false;
560 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
561 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
562 obj1[1] = true;
563 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
564
565 obj2 = null;
566 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
567 obj1 = null;
568 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
569 }
570
571 public void testMultiLongArray() {
572 long[][] array1 = new long[2][2];
573 long[][] array2 = new long[2][2];
574 for (int i = 0; i < array1.length; ++i) {
575 for (int j = 0; j < array1[0].length; j++) {
576 array1[i][j] = (i + 1) * (j + 1);
577 array2[i][j] = (i + 1) * (j + 1);
578 }
579 }
580 assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
581 assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
582 array1[1][1] = 0;
583 assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
584 }
585
586 public void testMultiIntArray() {
587 int[][] array1 = new int[2][2];
588 int[][] array2 = new int[2][2];
589 for (int i = 0; i < array1.length; ++i) {
590 for (int j = 0; j < array1[0].length; j++) {
591 array1[i][j] = (i + 1) * (j + 1);
592 array2[i][j] = (i + 1) * (j + 1);
593 }
594 }
595 assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
596 assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
597 array1[1][1] = 0;
598 assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
599 }
600
601 public void testMultiShortArray() {
602 short[][] array1 = new short[2][2];
603 short[][] array2 = new short[2][2];
604 for (short i = 0; i < array1.length; ++i) {
605 for (short j = 0; j < array1[0].length; j++) {
606 array1[i][j] = i;
607 array2[i][j] = i;
608 }
609 }
610 assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
611 assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
612 array1[1][1] = 0;
613 assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
614 }
615
616 public void testMultiCharArray() {
617 char[][] array1 = new char[2][2];
618 char[][] array2 = new char[2][2];
619 for (char i = 0; i < array1.length; ++i) {
620 for (char j = 0; j < array1[0].length; j++) {
621 array1[i][j] = i;
622 array2[i][j] = i;
623 }
624 }
625 assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
626 assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
627 array1[1][1] = 0;
628 assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
629 }
630
631 public void testMultiByteArray() {
632 byte[][] array1 = new byte[2][2];
633 byte[][] array2 = new byte[2][2];
634 for (byte i = 0; i < array1.length; ++i) {
635 for (byte j = 0; j < array1[0].length; j++) {
636 array1[i][j] = i;
637 array2[i][j] = i;
638 }
639 }
640 assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
641 assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
642 array1[1][1] = 0;
643 assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
644 }
645 public void testMultiFloatArray() {
646 float[][] array1 = new float[2][2];
647 float[][] array2 = new float[2][2];
648 for (int i = 0; i < array1.length; ++i) {
649 for (int j = 0; j < array1[0].length; j++) {
650 array1[i][j] = (i + 1) * (j + 1);
651 array2[i][j] = (i + 1) * (j + 1);
652 }
653 }
654 assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
655 assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
656 array1[1][1] = 0;
657 assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
658 }
659
660 public void testMultiDoubleArray() {
661 double[][] array1 = new double[2][2];
662 double[][] array2 = new double[2][2];
663 for (int i = 0; i < array1.length; ++i) {
664 for (int j = 0; j < array1[0].length; j++) {
665 array1[i][j] = (i + 1) * (j + 1);
666 array2[i][j] = (i + 1) * (j + 1);
667 }
668 }
669 assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
670 assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
671 array1[1][1] = 0;
672 assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
673 }
674
675 public void testMultiBooleanArray() {
676 boolean[][] array1 = new boolean[2][2];
677 boolean[][] array2 = new boolean[2][2];
678 for (int i = 0; i < array1.length; ++i) {
679 for (int j = 0; j < array1[0].length; j++) {
680 array1[i][j] = (i == 1) || (j == 1);
681 array2[i][j] = (i == 1) || (j == 1);
682 }
683 }
684 assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
685 assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
686 array1[1][1] = false;
687 assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
688
689 // compare 1 dim to 2.
690 boolean[] array3 = new boolean[]{true, true};
691 assertFalse(new EqualsBuilder().append(array1, array3).isEquals());
692 assertFalse(new EqualsBuilder().append(array3, array1).isEquals());
693 assertFalse(new EqualsBuilder().append(array2, array3).isEquals());
694 assertFalse(new EqualsBuilder().append(array3, array2).isEquals());
695 }
696
697 public void testRaggedArray() {
698 long array1[][] = new long[2][];
699 long array2[][] = new long[2][];
700 for (int i = 0; i < array1.length; ++i) {
701 array1[i] = new long[2];
702 array2[i] = new long[2];
703 for (int j = 0; j < array1[i].length; ++j) {
704 array1[i][j] = (i + 1) * (j + 1);
705 array2[i][j] = (i + 1) * (j + 1);
706 }
707 }
708 assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
709 assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
710 array1[1][1] = 0;
711 assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
712 }
713
714 public void testMixedArray() {
715 Object array1[] = new Object[2];
716 Object array2[] = new Object[2];
717 for (int i = 0; i < array1.length; ++i) {
718 array1[i] = new long[2];
719 array2[i] = new long[2];
720 for (int j = 0; j < 2; ++j) {
721 ((long[]) array1[i])[j] = (i + 1) * (j + 1);
722 ((long[]) array2[i])[j] = (i + 1) * (j + 1);
723 }
724 }
725 assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
726 assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
727 ((long[]) array1[1])[1] = 0;
728 assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
729 }
730
731 public void testObjectArrayHiddenByObject() {
732 TestObject[] array1 = new TestObject[2];
733 array1[0] = new TestObject(4);
734 array1[1] = new TestObject(5);
735 TestObject[] array2 = new TestObject[2];
736 array2[0] = new TestObject(4);
737 array2[1] = new TestObject(5);
738 Object obj1 = array1;
739 Object obj2 = array2;
740 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
741 assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
742 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
743 assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
744 array1[1].setA(6);
745 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
746 }
747
748 public void testLongArrayHiddenByObject() {
749 long[] array1 = new long[2];
750 array1[0] = 5L;
751 array1[1] = 6L;
752 long[] array2 = new long[2];
753 array2[0] = 5L;
754 array2[1] = 6L;
755 Object obj1 = array1;
756 Object obj2 = array2;
757 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
758 assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
759 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
760 assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
761 array1[1] = 7;
762 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
763 }
764
765 public void testIntArrayHiddenByObject() {
766 int[] array1 = new int[2];
767 array1[0] = 5;
768 array1[1] = 6;
769 int[] array2 = new int[2];
770 array2[0] = 5;
771 array2[1] = 6;
772 Object obj1 = array1;
773 Object obj2 = array2;
774 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
775 assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
776 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
777 assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
778 array1[1] = 7;
779 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
780 }
781
782 public void testShortArrayHiddenByObject() {
783 short[] array1 = new short[2];
784 array1[0] = 5;
785 array1[1] = 6;
786 short[] array2 = new short[2];
787 array2[0] = 5;
788 array2[1] = 6;
789 Object obj1 = array1;
790 Object obj2 = array2;
791 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
792 assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
793 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
794 assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
795 array1[1] = 7;
796 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
797 }
798
799 public void testCharArrayHiddenByObject() {
800 char[] array1 = new char[2];
801 array1[0] = 5;
802 array1[1] = 6;
803 char[] array2 = new char[2];
804 array2[0] = 5;
805 array2[1] = 6;
806 Object obj1 = array1;
807 Object obj2 = array2;
808 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
809 assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
810 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
811 assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
812 array1[1] = 7;
813 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
814 }
815
816 public void testByteArrayHiddenByObject() {
817 byte[] array1 = new byte[2];
818 array1[0] = 5;
819 array1[1] = 6;
820 byte[] array2 = new byte[2];
821 array2[0] = 5;
822 array2[1] = 6;
823 Object obj1 = array1;
824 Object obj2 = array2;
825 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
826 assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
827 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
828 assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
829 array1[1] = 7;
830 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
831 }
832
833 public void testDoubleArrayHiddenByObject() {
834 double[] array1 = new double[2];
835 array1[0] = 5;
836 array1[1] = 6;
837 double[] array2 = new double[2];
838 array2[0] = 5;
839 array2[1] = 6;
840 Object obj1 = array1;
841 Object obj2 = array2;
842 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
843 assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
844 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
845 assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
846 array1[1] = 7;
847 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
848 }
849
850 public void testFloatArrayHiddenByObject() {
851 float[] array1 = new float[2];
852 array1[0] = 5;
853 array1[1] = 6;
854 float[] array2 = new float[2];
855 array2[0] = 5;
856 array2[1] = 6;
857 Object obj1 = array1;
858 Object obj2 = array2;
859 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
860 assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
861 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
862 assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
863 array1[1] = 7;
864 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
865 }
866
867 public void testBooleanArrayHiddenByObject() {
868 boolean[] array1 = new boolean[2];
869 array1[0] = true;
870 array1[1] = false;
871 boolean[] array2 = new boolean[2];
872 array2[0] = true;
873 array2[1] = false;
874 Object obj1 = array1;
875 Object obj2 = array2;
876 assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
877 assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
878 assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
879 assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
880 array1[1] = true;
881 assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
882 }
883
884 public static class TestACanEqualB {
885 private int a;
886
887 public TestACanEqualB(int a) {
888 this.a = a;
889 }
890
891 @Override
892 public boolean equals(Object o) {
893 if (o == this)
894 return true;
895 if (o instanceof TestACanEqualB)
896 return this.a == ((TestACanEqualB) o).getA();
897 if (o instanceof TestBCanEqualA)
898 return this.a == ((TestBCanEqualA) o).getB();
899 return false;
900 }
901
902 public int getA() {
903 return this.a;
904 }
905 }
906
907 public static class TestBCanEqualA {
908 private int b;
909
910 public TestBCanEqualA(int b) {
911 this.b = b;
912 }
913
914 @Override
915 public boolean equals(Object o) {
916 if (o == this)
917 return true;
918 if (o instanceof TestACanEqualB)
919 return this.b == ((TestACanEqualB) o).getA();
920 if (o instanceof TestBCanEqualA)
921 return this.b == ((TestBCanEqualA) o).getB();
922 return false;
923 }
924
925 public int getB() {
926 return this.b;
927 }
928 }
929
930 /**
931 * Tests two instances of classes that can be equal and that are not "related". The two classes are not subclasses
932 * of each other and do not share a parent aside from Object.
933 * See http://issues.apache.org/bugzilla/show_bug.cgi?id=33069
934 */
935 public void testUnrelatedClasses() {
936 Object[] x = new Object[]{new TestACanEqualB(1)};
937 Object[] y = new Object[]{new TestBCanEqualA(1)};
938
939 // sanity checks:
940 assertTrue(Arrays.equals(x, x));
941 assertTrue(Arrays.equals(y, y));
942 assertTrue(Arrays.equals(x, y));
943 assertTrue(Arrays.equals(y, x));
944 // real tests:
945 assertTrue(x[0].equals(x[0]));
946 assertTrue(y[0].equals(y[0]));
947 assertTrue(x[0].equals(y[0]));
948 assertTrue(y[0].equals(x[0]));
949 assertTrue(new EqualsBuilder().append(x, x).isEquals());
950 assertTrue(new EqualsBuilder().append(y, y).isEquals());
951 assertTrue(new EqualsBuilder().append(x, y).isEquals());
952 assertTrue(new EqualsBuilder().append(y, x).isEquals());
953 }
954
955 /**
956 * Test from http://issues.apache.org/bugzilla/show_bug.cgi?id=33067
957 */
958 public void testNpeForNullElement() {
959 Object[] x1 = new Object[] { Integer.valueOf(1), null, Integer.valueOf(3) };
960 Object[] x2 = new Object[] { Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3) };
961
962 // causes an NPE in 2.0 according to:
963 // http://issues.apache.org/bugzilla/show_bug.cgi?id=33067
964 new EqualsBuilder().append(x1, x2);
965 }
966
967 public void testReflectionEqualsExcludeFields() throws Exception {
968 TestObjectWithMultipleFields x1 = new TestObjectWithMultipleFields(1, 2, 3);
969 TestObjectWithMultipleFields x2 = new TestObjectWithMultipleFields(1, 3, 4);
970
971 // not equal when including all fields
972 assertTrue(!EqualsBuilder.reflectionEquals(x1, x2));
973
974 // doesn't barf on null, empty array, or non-existent field, but still tests as not equal
975 assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, (String[]) null));
976 assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {}));
977 assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {"xxx"}));
978
979 // not equal if only one of the differing fields excluded
980 assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {"two"}));
981 assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {"three"}));
982
983 // equal if both differing fields excluded
984 assertTrue(EqualsBuilder.reflectionEquals(x1, x2, new String[] {"two", "three"}));
985
986 // still equal as long as both differing fields are among excluded
987 assertTrue(EqualsBuilder.reflectionEquals(x1, x2, new String[] {"one", "two", "three"}));
988 assertTrue(EqualsBuilder.reflectionEquals(x1, x2, new String[] {"one", "two", "three", "xxx"}));
989 }
990
991 static class TestObjectWithMultipleFields {
992 @SuppressWarnings("unused")
993 private TestObject one;
994 @SuppressWarnings("unused")
995 private TestObject two;
996 @SuppressWarnings("unused")
997 private TestObject three;
998
999 public TestObjectWithMultipleFields(int one, int two, int three) {
1000 this.one = new TestObject(one);
1001 this.two = new TestObject(two);
1002 this.three = new TestObject(three);
1003 }
1004 }
1005
1006 /**
1007 * Test cyclical object references which cause a StackOverflowException if
1008 * not handled properly. s. LANG-606
1009 */
1010 public void testCyclicalObjectReferences() {
1011 TestObjectReference refX1 = new TestObjectReference(1);
1012 TestObjectReference x1 = new TestObjectReference(1);
1013 x1.setObjectReference(refX1);
1014 refX1.setObjectReference(x1);
1015
1016 TestObjectReference refX2 = new TestObjectReference(1);
1017 TestObjectReference x2 = new TestObjectReference(1);
1018 x2.setObjectReference(refX2);
1019 refX2.setObjectReference(x2);
1020
1021 TestObjectReference refX3 = new TestObjectReference(2);
1022 TestObjectReference x3 = new TestObjectReference(2);
1023 x3.setObjectReference(refX3);
1024 refX3.setObjectReference(x3);
1025
1026 assertTrue(x1.equals(x2));
1027 assertNull(EqualsBuilder.getRegistry());
1028 assertFalse(x1.equals(x3));
1029 assertNull(EqualsBuilder.getRegistry());
1030 assertFalse(x2.equals(x3));
1031 assertNull(EqualsBuilder.getRegistry());
1032 }
1033
1034 static class TestObjectReference {
1035 @SuppressWarnings("unused")
1036 private TestObjectReference reference;
1037 @SuppressWarnings("unused")
1038 private TestObject one;
1039
1040 public TestObjectReference(int one) {
1041 this.one = new TestObject(one);
1042 }
1043
1044 public void setObjectReference(TestObjectReference reference) {
1045 this.reference = reference;
1046 }
1047
1048 @Override
1049 public boolean equals(Object obj) {
1050 return EqualsBuilder.reflectionEquals(this, obj);
1051 }
1052 }
1053 }
1054
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import junit.framework.TestCase;
19
20 /**
21 * Tests {@link org.apache.commons.lang3.builder.HashCodeBuilder} and
22 * {@link org.apache.commons.lang3.builder.EqualsBuilderTest} to insure that equal
23 * objects must have equal hash codes.
24 *
25 * @version $Id: HashCodeBuilderAndEqualsBuilderTest.java 1153484 2011-08-03 13:39:42Z ggregory $
26 */
27 public class HashCodeBuilderAndEqualsBuilderTest extends TestCase {
28
29 /**
30 * Constructor for HashCodeBuilderAndEqualsBuilderTest.
31 * @param name
32 */
33 public HashCodeBuilderAndEqualsBuilderTest(String name) {
34 super(name);
35 }
36
37 //-----------------------------------------------------------------------
38
39 public void testInteger(boolean testTransients) {
40 Integer i1 = Integer.valueOf(12345);
41 Integer i2 = Integer.valueOf(12345);
42 assertEqualsAndHashCodeContract(i1, i2, testTransients);
43 }
44
45 public void testInteger() {
46 testInteger(false);
47 }
48
49 public void testIntegerWithTransients() {
50 testInteger(true);
51 }
52
53 public void testFixture() {
54 testFixture(false);
55 }
56
57 public void testFixtureWithTransients() {
58 testFixture(true);
59 }
60
61 public void testFixture(boolean testTransients) {
62 assertEqualsAndHashCodeContract(new TestFixture(2, 'c', "Test", (short) 2), new TestFixture(2, 'c', "Test", (short) 2), testTransients);
63 assertEqualsAndHashCodeContract(
64 new AllTransientFixture(2, 'c', "Test", (short) 2),
65 new AllTransientFixture(2, 'c', "Test", (short) 2),
66 testTransients);
67 assertEqualsAndHashCodeContract(
68 new SubTestFixture(2, 'c', "Test", (short) 2, "Same"),
69 new SubTestFixture(2, 'c', "Test", (short) 2, "Same"),
70 testTransients);
71 assertEqualsAndHashCodeContract(
72 new SubAllTransientFixture(2, 'c', "Test", (short) 2, "Same"),
73 new SubAllTransientFixture(2, 'c', "Test", (short) 2, "Same"),
74 testTransients);
75 }
76
77 /**
78 * Asserts that if <code>lhs</code> equals <code>rhs</code>
79 * then their hash codes MUST be identical.
80 *
81 * @param lhs The Left-Hand-Side of the equals test
82 * @param rhs The Right-Hand-Side of the equals test
83 * @param testTransients wether to test transient fields
84 */
85 public void assertEqualsAndHashCodeContract(Object lhs, Object rhs, boolean testTransients) {
86 if (EqualsBuilder.reflectionEquals(lhs, rhs, testTransients)) {
87 // test a couple of times for consistency.
88 assertEquals(HashCodeBuilder.reflectionHashCode(lhs, testTransients), HashCodeBuilder.reflectionHashCode(rhs, testTransients));
89 assertEquals(HashCodeBuilder.reflectionHashCode(lhs, testTransients), HashCodeBuilder.reflectionHashCode(rhs, testTransients));
90 assertEquals(HashCodeBuilder.reflectionHashCode(lhs, testTransients), HashCodeBuilder.reflectionHashCode(rhs, testTransients));
91 }
92 }
93
94 static class TestFixture {
95 int i;
96 char c;
97 String string;
98 short s;
99
100 TestFixture(int i, char c, String string, short s) {
101 this.i = i;
102 this.c = c;
103 this.string = string;
104 this.s = s;
105 }
106 }
107
108 static class SubTestFixture extends TestFixture {
109 transient String tString;
110
111 SubTestFixture(int i, char c, String string, short s, String tString) {
112 super(i, c, string, s);
113 this.tString = tString;
114 }
115 }
116
117 static class AllTransientFixture {
118 transient int i;
119 transient char c;
120 transient String string;
121 transient short s;
122
123 AllTransientFixture(int i, char c, String string, short s) {
124 this.i = i;
125 this.c = c;
126 this.string = string;
127 this.s = s;
128 }
129 }
130
131 static class SubAllTransientFixture extends AllTransientFixture {
132 transient String tString;
133
134 SubAllTransientFixture(int i, char c, String string, short s, String tString) {
135 super(i, c, string, s);
136 this.tString = tString;
137 }
138 }
139
140
141 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.builder;
18
19 import junit.framework.TestCase;
20
21 /**
22 * Unit tests {@link org.apache.commons.lang3.builder.HashCodeBuilder}.
23 *
24 * @version $Id: HashCodeBuilderTest.java 1088899 2011-04-05 05:31:27Z bayard $
25 */
26 public class HashCodeBuilderTest extends TestCase {
27
28 /**
29 * A reflection test fixture.
30 */
31 static class ReflectionTestCycleA {
32 ReflectionTestCycleB b;
33
34 @Override
35 public int hashCode() {
36 return HashCodeBuilder.reflectionHashCode(this);
37 }
38 }
39
40 /**
41 * A reflection test fixture.
42 */
43 static class ReflectionTestCycleB {
44 ReflectionTestCycleA a;
45
46 @Override
47 public int hashCode() {
48 return HashCodeBuilder.reflectionHashCode(this);
49 }
50 }
51
52 public HashCodeBuilderTest(String name) {
53 super(name);
54 }
55
56 // -----------------------------------------------------------------------
57
58 public void testConstructorEx1() {
59 try {
60 new HashCodeBuilder(0, 0);
61
62 } catch (IllegalArgumentException ex) {
63 return;
64 }
65 fail();
66 }
67
68 public void testConstructorEx2() {
69 try {
70 new HashCodeBuilder(2, 2);
71
72 } catch (IllegalArgumentException ex) {
73 return;
74 }
75 fail();
76 }
77
78 static class TestObject {
79 private int a;
80
81 public TestObject(int a) {
82 this.a = a;
83 }
84
85 @Override
86 public boolean equals(Object o) {
87 if (o == this) {
88 return true;
89 }
90 if (!(o instanceof TestObject)) {
91 return false;
92 }
93 TestObject rhs = (TestObject) o;
94 return (a == rhs.a);
95 }
96
97 public void setA(int a) {
98 this.a = a;
99 }
100
101 public int getA() {
102 return a;
103 }
104 }
105
106 static class TestSubObject extends TestObject {
107 private int b;
108
109 @SuppressWarnings("unused")
110 transient private int t;
111
112 public TestSubObject() {
113 super(0);
114 }
115
116 public TestSubObject(int a, int b, int t) {
117 super(a);
118 this.b = b;
119 this.t = t;
120 }
121
122 @Override
123 public boolean equals(Object o) {
124 if (o == this) {
125 return true;
126 }
127 if (!(o instanceof TestSubObject)) {
128 return false;
129 }
130 TestSubObject rhs = (TestSubObject) o;
131 return super.equals(o) && (b == rhs.b);
132 }
133 }
134
135 public void testReflectionHashCode() {
136 assertEquals(17 * 37, HashCodeBuilder.reflectionHashCode(new TestObject(0)));
137 assertEquals(17 * 37 + 123456, HashCodeBuilder.reflectionHashCode(new TestObject(123456)));
138 }
139
140 public void testReflectionHierarchyHashCode() {
141 assertEquals(17 * 37 * 37, HashCodeBuilder.reflectionHashCode(new TestSubObject(0, 0, 0)));
142 assertEquals(17 * 37 * 37 * 37, HashCodeBuilder.reflectionHashCode(new TestSubObject(0, 0, 0), true));
143 assertEquals((17 * 37 + 7890) * 37 + 123456, HashCodeBuilder.reflectionHashCode(new TestSubObject(123456, 7890,
144 0)));
145 assertEquals(((17 * 37 + 7890) * 37 + 0) * 37 + 123456, HashCodeBuilder.reflectionHashCode(new TestSubObject(
146 123456, 7890, 0), true));
147 }
148
149 public void testReflectionHierarchyHashCodeEx1() {
150 try {
151 HashCodeBuilder.reflectionHashCode(0, 0, new TestSubObject(0, 0, 0), true);
152 } catch (IllegalArgumentException ex) {
153 return;
154 }
155 fail();
156 }
157
158 public void testReflectionHierarchyHashCodeEx2() {
159 try {
160 HashCodeBuilder.reflectionHashCode(2, 2, new TestSubObject(0, 0, 0), true);
161 } catch (IllegalArgumentException ex) {
162 return;
163 }
164 fail();
165 }
166
167 public void testReflectionHashCodeEx1() {
168 try {
169 HashCodeBuilder.reflectionHashCode(0, 0, new TestObject(0), true);
170 } catch (IllegalArgumentException ex) {
171 return;
172 }
173 fail();
174 }
175
176 public void testReflectionHashCodeEx2() {
177 try {
178 HashCodeBuilder.reflectionHashCode(2, 2, new TestObject(0), true);
179 } catch (IllegalArgumentException ex) {
180 return;
181 }
182 fail();
183 }
184
185 public void testReflectionHashCodeEx3() {
186 try {
187 HashCodeBuilder.reflectionHashCode(13, 19, null, true);
188 } catch (IllegalArgumentException ex) {
189 return;
190 }
191 fail();
192 }
193
194 public void testSuper() {
195 Object obj = new Object();
196 assertEquals(17 * 37 + (19 * 41 + obj.hashCode()), new HashCodeBuilder(17, 37).appendSuper(
197 new HashCodeBuilder(19, 41).append(obj).toHashCode()).toHashCode());
198 }
199
200 public void testObject() {
201 Object obj = null;
202 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
203 obj = new Object();
204 assertEquals(17 * 37 + obj.hashCode(), new HashCodeBuilder(17, 37).append(obj).toHashCode());
205 }
206
207 public void testObjectBuild() {
208 Object obj = null;
209 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append(obj).build().intValue());
210 obj = new Object();
211 assertEquals(17 * 37 + obj.hashCode(), new HashCodeBuilder(17, 37).append(obj).build().intValue());
212 }
213
214 @SuppressWarnings("cast") // cast is not really needed, keep for consistency
215 public void testLong() {
216 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((long) 0L).toHashCode());
217 assertEquals(17 * 37 + (int) (123456789L ^ (123456789L >> 32)), new HashCodeBuilder(17, 37).append(
218 (long) 123456789L).toHashCode());
219 }
220
221 @SuppressWarnings("cast") // cast is not really needed, keep for consistency
222 public void testInt() {
223 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((int) 0).toHashCode());
224 assertEquals(17 * 37 + 123456, new HashCodeBuilder(17, 37).append((int) 123456).toHashCode());
225 }
226
227 public void testShort() {
228 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((short) 0).toHashCode());
229 assertEquals(17 * 37 + 12345, new HashCodeBuilder(17, 37).append((short) 12345).toHashCode());
230 }
231
232 public void testChar() {
233 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((char) 0).toHashCode());
234 assertEquals(17 * 37 + 1234, new HashCodeBuilder(17, 37).append((char) 1234).toHashCode());
235 }
236
237 public void testByte() {
238 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((byte) 0).toHashCode());
239 assertEquals(17 * 37 + 123, new HashCodeBuilder(17, 37).append((byte) 123).toHashCode());
240 }
241
242 @SuppressWarnings("cast") // cast is not really needed, keep for consistency
243 public void testDouble() {
244 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((double) 0d).toHashCode());
245 double d = 1234567.89;
246 long l = Double.doubleToLongBits(d);
247 assertEquals(17 * 37 + (int) (l ^ (l >> 32)), new HashCodeBuilder(17, 37).append(d).toHashCode());
248 }
249
250 @SuppressWarnings("cast") // cast is not really needed, keep for consistency
251 public void testFloat() {
252 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((float) 0f).toHashCode());
253 float f = 1234.89f;
254 int i = Float.floatToIntBits(f);
255 assertEquals(17 * 37 + i, new HashCodeBuilder(17, 37).append(f).toHashCode());
256 }
257
258 public void testBoolean() {
259 assertEquals(17 * 37 + 0, new HashCodeBuilder(17, 37).append(true).toHashCode());
260 assertEquals(17 * 37 + 1, new HashCodeBuilder(17, 37).append(false).toHashCode());
261 }
262
263 public void testObjectArray() {
264 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((Object[]) null).toHashCode());
265 Object[] obj = new Object[2];
266 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
267 obj[0] = new Object();
268 assertEquals((17 * 37 + obj[0].hashCode()) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
269 obj[1] = new Object();
270 assertEquals((17 * 37 + obj[0].hashCode()) * 37 + obj[1].hashCode(), new HashCodeBuilder(17, 37).append(obj)
271 .toHashCode());
272 }
273
274 public void testObjectArrayAsObject() {
275 Object[] obj = new Object[2];
276 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
277 obj[0] = new Object();
278 assertEquals((17 * 37 + obj[0].hashCode()) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
279 obj[1] = new Object();
280 assertEquals((17 * 37 + obj[0].hashCode()) * 37 + obj[1].hashCode(), new HashCodeBuilder(17, 37).append(
281 (Object) obj).toHashCode());
282 }
283
284 public void testLongArray() {
285 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((long[]) null).toHashCode());
286 long[] obj = new long[2];
287 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
288 obj[0] = 5L;
289 int h1 = (int) (5L ^ (5L >> 32));
290 assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
291 obj[1] = 6L;
292 int h2 = (int) (6L ^ (6L >> 32));
293 assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append(obj).toHashCode());
294 }
295
296 public void testLongArrayAsObject() {
297 long[] obj = new long[2];
298 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
299 obj[0] = 5L;
300 int h1 = (int) (5L ^ (5L >> 32));
301 assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
302 obj[1] = 6L;
303 int h2 = (int) (6L ^ (6L >> 32));
304 assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
305 }
306
307 public void testIntArray() {
308 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((int[]) null).toHashCode());
309 int[] obj = new int[2];
310 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
311 obj[0] = 5;
312 assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
313 obj[1] = 6;
314 assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append(obj).toHashCode());
315 }
316
317 public void testIntArrayAsObject() {
318 int[] obj = new int[2];
319 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
320 obj[0] = 5;
321 assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
322 obj[1] = 6;
323 assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
324 }
325
326 public void testShortArray() {
327 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((short[]) null).toHashCode());
328 short[] obj = new short[2];
329 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
330 obj[0] = (short) 5;
331 assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
332 obj[1] = (short) 6;
333 assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append(obj).toHashCode());
334 }
335
336 public void testShortArrayAsObject() {
337 short[] obj = new short[2];
338 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
339 obj[0] = (short) 5;
340 assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
341 obj[1] = (short) 6;
342 assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
343 }
344
345 public void testCharArray() {
346 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((char[]) null).toHashCode());
347 char[] obj = new char[2];
348 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
349 obj[0] = (char) 5;
350 assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
351 obj[1] = (char) 6;
352 assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append(obj).toHashCode());
353 }
354
355 public void testCharArrayAsObject() {
356 char[] obj = new char[2];
357 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
358 obj[0] = (char) 5;
359 assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
360 obj[1] = (char) 6;
361 assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
362 }
363
364 public void testByteArray() {
365 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((byte[]) null).toHashCode());
366 byte[] obj = new byte[2];
367 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
368 obj[0] = (byte) 5;
369 assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
370 obj[1] = (byte) 6;
371 assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append(obj).toHashCode());
372 }
373
374 public void testByteArrayAsObject() {
375 byte[] obj = new byte[2];
376 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
377 obj[0] = (byte) 5;
378 assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
379 obj[1] = (byte) 6;
380 assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
381 }
382
383 public void testDoubleArray() {
384 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((double[]) null).toHashCode());
385 double[] obj = new double[2];
386 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
387 obj[0] = 5.4d;
388 long l1 = Double.doubleToLongBits(5.4d);
389 int h1 = (int) (l1 ^ (l1 >> 32));
390 assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
391 obj[1] = 6.3d;
392 long l2 = Double.doubleToLongBits(6.3d);
393 int h2 = (int) (l2 ^ (l2 >> 32));
394 assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append(obj).toHashCode());
395 }
396
397 public void testDoubleArrayAsObject() {
398 double[] obj = new double[2];
399 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
400 obj[0] = 5.4d;
401 long l1 = Double.doubleToLongBits(5.4d);
402 int h1 = (int) (l1 ^ (l1 >> 32));
403 assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
404 obj[1] = 6.3d;
405 long l2 = Double.doubleToLongBits(6.3d);
406 int h2 = (int) (l2 ^ (l2 >> 32));
407 assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
408 }
409
410 public void testFloatArray() {
411 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((float[]) null).toHashCode());
412 float[] obj = new float[2];
413 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
414 obj[0] = 5.4f;
415 int h1 = Float.floatToIntBits(5.4f);
416 assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
417 obj[1] = 6.3f;
418 int h2 = Float.floatToIntBits(6.3f);
419 assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append(obj).toHashCode());
420 }
421
422 public void testFloatArrayAsObject() {
423 float[] obj = new float[2];
424 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
425 obj[0] = 5.4f;
426 int h1 = Float.floatToIntBits(5.4f);
427 assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
428 obj[1] = 6.3f;
429 int h2 = Float.floatToIntBits(6.3f);
430 assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
431 }
432
433 public void testBooleanArray() {
434 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((boolean[]) null).toHashCode());
435 boolean[] obj = new boolean[2];
436 assertEquals((17 * 37 + 1) * 37 + 1, new HashCodeBuilder(17, 37).append(obj).toHashCode());
437 obj[0] = true;
438 assertEquals((17 * 37 + 0) * 37 + 1, new HashCodeBuilder(17, 37).append(obj).toHashCode());
439 obj[1] = false;
440 assertEquals((17 * 37 + 0) * 37 + 1, new HashCodeBuilder(17, 37).append(obj).toHashCode());
441 }
442
443 public void testBooleanArrayAsObject() {
444 boolean[] obj = new boolean[2];
445 assertEquals((17 * 37 + 1) * 37 + 1, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
446 obj[0] = true;
447 assertEquals((17 * 37 + 0) * 37 + 1, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
448 obj[1] = false;
449 assertEquals((17 * 37 + 0) * 37 + 1, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
450 }
451
452 public void testBooleanMultiArray() {
453 boolean[][] obj = new boolean[2][];
454 assertEquals((17 * 37) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
455 obj[0] = new boolean[0];
456 assertEquals(17 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
457 obj[0] = new boolean[1];
458 assertEquals((17 * 37 + 1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
459 obj[0] = new boolean[2];
460 assertEquals(((17 * 37 + 1) * 37 + 1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
461 obj[0][0] = true;
462 assertEquals(((17 * 37 + 0) * 37 + 1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
463 obj[1] = new boolean[1];
464 assertEquals((((17 * 37 + 0) * 37 + 1) * 37 + 1), new HashCodeBuilder(17, 37).append(obj).toHashCode());
465 }
466
467 public void testReflectionHashCodeExcludeFields() throws Exception {
468 TestObjectWithMultipleFields x = new TestObjectWithMultipleFields(1, 2, 3);
469
470 assertEquals((((17 * 37 + 1) * 37 + 2) * 37 + 3), HashCodeBuilder.reflectionHashCode(x));
471
472 assertEquals((((17 * 37 + 1) * 37 + 2) * 37 + 3), HashCodeBuilder.reflectionHashCode(x, (String[]) null));
473 assertEquals((((17 * 37 + 1) * 37 + 2) * 37 + 3), HashCodeBuilder.reflectionHashCode(x, new String[]{}));
474 assertEquals((((17 * 37 + 1) * 37 + 2) * 37 + 3), HashCodeBuilder.reflectionHashCode(x, new String[]{"xxx"}));
475
476 assertEquals(((17 * 37 + 1) * 37 + 3), HashCodeBuilder.reflectionHashCode(x, new String[]{"two"}));
477 assertEquals(((17 * 37 + 1) * 37 + 2), HashCodeBuilder.reflectionHashCode(x, new String[]{"three"}));
478
479 assertEquals((17 * 37 + 1), HashCodeBuilder.reflectionHashCode(x, new String[]{"two", "three"}));
480
481 assertEquals(17, HashCodeBuilder.reflectionHashCode(x, new String[]{"one", "two", "three"}));
482 assertEquals(17, HashCodeBuilder.reflectionHashCode(x, new String[]{"one", "two", "three", "xxx"}));
483 }
484
485 static class TestObjectWithMultipleFields {
486 @SuppressWarnings("unused")
487 private int one = 0;
488
489 @SuppressWarnings("unused")
490 private int two = 0;
491
492 @SuppressWarnings("unused")
493 private int three = 0;
494
495 public TestObjectWithMultipleFields(int one, int two, int three) {
496 this.one = one;
497 this.two = two;
498 this.three = three;
499 }
500 }
501
502 /**
503 * Test Objects pointing to each other.
504 */
505 public void testReflectionObjectCycle() {
506 ReflectionTestCycleA a = new ReflectionTestCycleA();
507 ReflectionTestCycleB b = new ReflectionTestCycleB();
508 a.b = b;
509 b.a = a;
510
511 // Used to caused:
512 // java.lang.StackOverflowError
513 // at java.lang.ClassLoader.getCallerClassLoader(Native Method)
514 // at java.lang.Class.getDeclaredFields(Class.java:992)
515 // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionAppend(HashCodeBuilder.java:373)
516 // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:349)
517 // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:155)
518 // at
519 // org.apache.commons.lang.builder.HashCodeBuilderTest$ReflectionTestCycleB.hashCode(HashCodeBuilderTest.java:53)
520 // at org.apache.commons.lang.builder.HashCodeBuilder.append(HashCodeBuilder.java:422)
521 // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionAppend(HashCodeBuilder.java:383)
522 // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:349)
523 // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:155)
524 // at
525 // org.apache.commons.lang.builder.HashCodeBuilderTest$ReflectionTestCycleA.hashCode(HashCodeBuilderTest.java:42)
526 // at org.apache.commons.lang.builder.HashCodeBuilder.append(HashCodeBuilder.java:422)
527
528 a.hashCode();
529 assertNull(HashCodeBuilder.getRegistry());
530 b.hashCode();
531 assertNull(HashCodeBuilder.getRegistry());
532 }
533
534 /**
535 * Ensures LANG-520 remains true
536 */
537 public void testToHashCodeEqualsHashCode() {
538 HashCodeBuilder hcb = new HashCodeBuilder(17, 37).append(new Object()).append('a');
539 assertEquals("hashCode() is no longer returning the same value as toHashCode() - see LANG-520",
540 hcb.toHashCode(), hcb.hashCode());
541 }
542
543 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20
21 import junit.framework.TestCase;
22
23 import org.apache.commons.lang3.SystemUtils;
24 import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
25
26 /**
27 * Unit tests {@link org.apache.commons.lang3.builder.MultiLineToStringStyleTest}.
28 *
29 * @version $Id: MultiLineToStringStyleTest.java 1153484 2011-08-03 13:39:42Z ggregory $
30 */
31 public class MultiLineToStringStyleTest extends TestCase {
32
33 private final Integer base = Integer.valueOf(5);
34 private final String baseStr = base.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(base));
35
36 public MultiLineToStringStyleTest(String name) {
37 super(name);
38 }
39
40 @Override
41 protected void setUp() throws Exception {
42 super.setUp();
43 ToStringBuilder.setDefaultStyle(ToStringStyle.MULTI_LINE_STYLE);
44 }
45
46 @Override
47 protected void tearDown() throws Exception {
48 super.tearDown();
49 ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
50 }
51
52 //----------------------------------------------------------------
53
54 public void testBlank() {
55 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).toString());
56 }
57
58 public void testAppendSuper() {
59 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).appendSuper("Integer@8888[" + SystemUtils.LINE_SEPARATOR + "]").toString());
60 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).appendSuper("Integer@8888[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + "]").toString());
61
62 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=hello" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).appendSuper("Integer@8888[" + SystemUtils.LINE_SEPARATOR + "]").append("a", "hello").toString());
63 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + " a=hello" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).appendSuper("Integer@8888[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + "]").append("a", "hello").toString());
64 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=hello" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).appendSuper(null).append("a", "hello").toString());
65 }
66
67 public void testObject() {
68 Integer i3 = Integer.valueOf(3);
69 Integer i4 = Integer.valueOf(4);
70 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append((Object) null).toString());
71 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " 3" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append(i3).toString());
72 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=<null>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", (Object) null).toString());
73 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=3" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", i3).toString());
74 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=3" + SystemUtils.LINE_SEPARATOR + " b=4" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", i3).append("b", i4).toString());
75 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=<Integer>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", i3, false).toString());
76 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=<size=0>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), false).toString());
77 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=[]" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), true).toString());
78 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=<size=0>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), false).toString());
79 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a={}" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), true).toString());
80 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=<size=0>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", (Object) new String[0], false).toString());
81 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a={}" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", (Object) new String[0], true).toString());
82 }
83
84 public void testPerson() {
85 Person p = new Person();
86 p.name = "Jane Doe";
87 p.age = 25;
88 p.smoker = true;
89 String pBaseStr = p.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(p));
90 assertEquals(pBaseStr + "[" + SystemUtils.LINE_SEPARATOR + " name=Jane Doe" + SystemUtils.LINE_SEPARATOR + " age=25" + SystemUtils.LINE_SEPARATOR + " smoker=true" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(p).append("name", p.name).append("age", p.age).append("smoker", p.smoker).toString());
91 }
92
93 public void testLong() {
94 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " 3" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append(3L).toString());
95 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=3" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", 3L).toString());
96 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " a=3" + SystemUtils.LINE_SEPARATOR + " b=4" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append("a", 3L).append("b", 4L).toString());
97 }
98
99 public void testObjectArray() {
100 Object[] array = new Object[] {null, base, new int[] {3, 6}};
101 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " {<null>,5,{3,6}}" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append(array).toString());
102 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " {<null>,5,{3,6}}" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append((Object) array).toString());
103 array = null;
104 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append(array).toString());
105 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append((Object) array).toString());
106 }
107
108 public void testLongArray() {
109 long[] array = new long[] {1, 2, -3, 4};
110 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " {1,2,-3,4}" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append(array).toString());
111 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " {1,2,-3,4}" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append((Object) array).toString());
112 array = null;
113 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append(array).toString());
114 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append((Object) array).toString());
115 }
116
117 public void testLongArrayArray() {
118 long[][] array = new long[][] {{1, 2}, null, {5}};
119 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " {{1,2},<null>,{5}}" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append(array).toString());
120 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " {{1,2},<null>,{5}}" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append((Object) array).toString());
121 array = null;
122 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append(array).toString());
123 assertEquals(baseStr + "[" + SystemUtils.LINE_SEPARATOR + " <null>" + SystemUtils.LINE_SEPARATOR + "]", new ToStringBuilder(base).append((Object) array).toString());
124 }
125
126 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20
21 import junit.framework.TestCase;
22
23 import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
24
25 /**
26 * Unit tests {@link org.apache.commons.lang3.builder.NoFieldNamesToStringStyleTest}.
27 *
28 * @version $Id: NoFieldNamesToStringStyleTest.java 1153484 2011-08-03 13:39:42Z ggregory $
29 */
30 public class NoFieldNamesToStringStyleTest extends TestCase {
31
32 private final Integer base = Integer.valueOf(5);
33 private final String baseStr = base.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(base));
34
35 public NoFieldNamesToStringStyleTest(String name) {
36 super(name);
37 }
38
39 @Override
40 protected void setUp() throws Exception {
41 super.setUp();
42 ToStringBuilder.setDefaultStyle(ToStringStyle.NO_FIELD_NAMES_STYLE);
43 }
44
45 @Override
46 protected void tearDown() throws Exception {
47 super.tearDown();
48 ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
49 }
50
51 //----------------------------------------------------------------
52
53 public void testBlank() {
54 assertEquals(baseStr + "[]", new ToStringBuilder(base).toString());
55 }
56
57 public void testAppendSuper() {
58 assertEquals(baseStr + "[]", new ToStringBuilder(base).appendSuper("Integer@8888[]").toString());
59 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").toString());
60
61 assertEquals(baseStr + "[hello]", new ToStringBuilder(base).appendSuper("Integer@8888[]").append("a", "hello").toString());
62 assertEquals(baseStr + "[<null>,hello]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").append("a", "hello").toString());
63 assertEquals(baseStr + "[hello]", new ToStringBuilder(base).appendSuper(null).append("a", "hello").toString());
64 }
65
66 public void testObject() {
67 Integer i3 = Integer.valueOf(3);
68 Integer i4 = Integer.valueOf(4);
69 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) null).toString());
70 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(i3).toString());
71 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append("a", (Object) null).toString());
72 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append("a", i3).toString());
73 assertEquals(baseStr + "[3,4]", new ToStringBuilder(base).append("a", i3).append("b", i4).toString());
74 assertEquals(baseStr + "[<Integer>]", new ToStringBuilder(base).append("a", i3, false).toString());
75 assertEquals(baseStr + "[<size=0>]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), false).toString());
76 assertEquals(baseStr + "[[]]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), true).toString());
77 assertEquals(baseStr + "[<size=0>]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), false).toString());
78 assertEquals(baseStr + "[{}]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), true).toString());
79 assertEquals(baseStr + "[<size=0>]", new ToStringBuilder(base).append("a", (Object) new String[0], false).toString());
80 assertEquals(baseStr + "[{}]", new ToStringBuilder(base).append("a", (Object) new String[0], true).toString());
81 }
82
83 public void testPerson() {
84 Person p = new Person();
85 p.name = "Ron Paul";
86 p.age = 72;
87 p.smoker = false;
88 String pBaseStr = p.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(p));
89 assertEquals(pBaseStr + "[Ron Paul,72,false]", new ToStringBuilder(p).append("name", p.name).append("age", p.age).append("smoker", p.smoker).toString());
90 }
91
92 public void testLong() {
93 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(3L).toString());
94 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append("a", 3L).toString());
95 assertEquals(baseStr + "[3,4]", new ToStringBuilder(base).append("a", 3L).append("b", 4L).toString());
96 }
97
98 public void testObjectArray() {
99 Object[] array = new Object[] {null, base, new int[] {3, 6}};
100 assertEquals(baseStr + "[{<null>,5,{3,6}}]", new ToStringBuilder(base).append(array).toString());
101 assertEquals(baseStr + "[{<null>,5,{3,6}}]", new ToStringBuilder(base).append((Object) array).toString());
102 array = null;
103 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
104 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
105 }
106
107 public void testLongArray() {
108 long[] array = new long[] {1, 2, -3, 4};
109 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append(array).toString());
110 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append((Object) array).toString());
111 array = null;
112 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
113 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
114 }
115
116 public void testLongArrayArray() {
117 long[][] array = new long[][] {{1, 2}, null, {5}};
118 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append(array).toString());
119 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append((Object) array).toString());
120 array = null;
121 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
122 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
123 }
124
125 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.builder;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.List;
22
23 import junit.framework.Assert;
24 import junit.framework.TestCase;
25
26 import org.apache.commons.lang3.ArrayUtils;
27
28 /**
29 * @version $Id: ReflectionToStringBuilderExcludeTest.java 1088899 2011-04-05 05:31:27Z bayard $
30 */
31 public class ReflectionToStringBuilderExcludeTest extends TestCase {
32
33 class TestFixture {
34 @SuppressWarnings("unused")
35 private String secretField = SECRET_VALUE;
36
37 @SuppressWarnings("unused")
38 private String showField = NOT_SECRET_VALUE;
39 }
40
41 private static final String NOT_SECRET_FIELD = "showField";
42
43 private static final String NOT_SECRET_VALUE = "Hello World!";
44
45 private static final String SECRET_FIELD = "secretField";
46
47 private static final String SECRET_VALUE = "secret value";
48
49 public void test_toStringExclude() {
50 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), SECRET_FIELD);
51 this.validateSecretFieldAbsent(toString);
52 }
53
54 public void test_toStringExcludeArray() {
55 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), new String[]{SECRET_FIELD});
56 this.validateSecretFieldAbsent(toString);
57 }
58
59 public void test_toStringExcludeArrayWithNull() {
60 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), new String[]{null});
61 this.validateSecretFieldPresent(toString);
62 }
63
64 public void test_toStringExcludeArrayWithNulls() {
65 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), new String[]{null, null});
66 this.validateSecretFieldPresent(toString);
67 }
68
69 public void test_toStringExcludeCollection() {
70 List<String> excludeList = new ArrayList<String>();
71 excludeList.add(SECRET_FIELD);
72 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), excludeList);
73 this.validateSecretFieldAbsent(toString);
74 }
75
76 public void test_toStringExcludeCollectionWithNull() {
77 List<String> excludeList = new ArrayList<String>();
78 excludeList.add(null);
79 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), excludeList);
80 this.validateSecretFieldPresent(toString);
81 }
82
83 public void test_toStringExcludeCollectionWithNulls() {
84 List<String> excludeList = new ArrayList<String>();
85 excludeList.add(null);
86 excludeList.add(null);
87 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), excludeList);
88 this.validateSecretFieldPresent(toString);
89 }
90
91 public void test_toStringExcludeEmptyArray() {
92 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), ArrayUtils.EMPTY_STRING_ARRAY);
93 this.validateSecretFieldPresent(toString);
94 }
95
96 public void test_toStringExcludeEmptyCollection() {
97 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), new ArrayList<String>());
98 this.validateSecretFieldPresent(toString);
99 }
100
101 public void test_toStringExcludeNullArray() {
102 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), (String[]) null);
103 this.validateSecretFieldPresent(toString);
104 }
105
106 public void test_toStringExcludeNullCollection() {
107 String toString = ReflectionToStringBuilder.toStringExclude(new TestFixture(), (Collection<String>) null);
108 this.validateSecretFieldPresent(toString);
109 }
110
111 private void validateNonSecretField(String toString) {
112 Assert.assertTrue(toString.indexOf(NOT_SECRET_FIELD) > ArrayUtils.INDEX_NOT_FOUND);
113 Assert.assertTrue(toString.indexOf(NOT_SECRET_VALUE) > ArrayUtils.INDEX_NOT_FOUND);
114 }
115
116 private void validateSecretFieldAbsent(String toString) {
117 Assert.assertEquals(ArrayUtils.INDEX_NOT_FOUND, toString.indexOf(SECRET_VALUE));
118 this.validateNonSecretField(toString);
119 }
120
121 private void validateSecretFieldPresent(String toString) {
122 Assert.assertTrue(toString.indexOf(SECRET_VALUE) > 0);
123 this.validateNonSecretField(toString);
124 }
125 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20
21 import junit.framework.TestCase;
22
23 import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
24
25 /**
26 * Unit tests {@link org.apache.commons.lang3.builder.ToStringStyle#SHORT_PREFIX_STYLE}.
27 *
28 * @version $Id: ShortPrefixToStringStyleTest.java 1153484 2011-08-03 13:39:42Z ggregory $
29 */
30 public class ShortPrefixToStringStyleTest extends TestCase {
31
32 private final Integer base = Integer.valueOf(5);
33 private final String baseStr = "Integer";
34
35 @Override
36 protected void setUp() throws Exception {
37 super.setUp();
38 ToStringBuilder.setDefaultStyle(ToStringStyle.SHORT_PREFIX_STYLE);
39 }
40
41 @Override
42 protected void tearDown() throws Exception {
43 super.tearDown();
44 ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
45 }
46
47 //----------------------------------------------------------------
48
49 public void testBlank() {
50 assertEquals(baseStr + "[]", new ToStringBuilder(base).toString());
51 }
52
53 public void testAppendSuper() {
54 assertEquals(baseStr + "[]", new ToStringBuilder(base).appendSuper("Integer@8888[]").toString());
55 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").toString());
56
57 assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper("Integer@8888[]").append("a", "hello").toString());
58 assertEquals(baseStr + "[<null>,a=hello]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").append("a", "hello").toString());
59 assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper(null).append("a", "hello").toString());
60 }
61
62 public void testObject() {
63 Integer i3 = Integer.valueOf(3);
64 Integer i4 = Integer.valueOf(4);
65 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) null).toString());
66 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(i3).toString());
67 assertEquals(baseStr + "[a=<null>]", new ToStringBuilder(base).append("a", (Object) null).toString());
68 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", i3).toString());
69 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", i3).append("b", i4).toString());
70 assertEquals(baseStr + "[a=<Integer>]", new ToStringBuilder(base).append("a", i3, false).toString());
71 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), false).toString());
72 assertEquals(baseStr + "[a=[]]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), true).toString());
73 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), false).toString());
74 assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), true).toString());
75 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", (Object) new String[0], false).toString());
76 assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", (Object) new String[0], true).toString());
77 }
78
79 public void testPerson() {
80 Person p = new Person();
81 p.name = "John Q. Public";
82 p.age = 45;
83 p.smoker = true;
84 String pBaseStr = "ToStringStyleTest.Person";
85 assertEquals(pBaseStr + "[name=John Q. Public,age=45,smoker=true]", new ToStringBuilder(p).append("name", p.name).append("age", p.age).append("smoker", p.smoker).toString());
86 }
87
88 public void testLong() {
89 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(3L).toString());
90 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", 3L).toString());
91 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", 3L).append("b", 4L).toString());
92 }
93
94 public void testObjectArray() {
95 Object[] array = new Object[] {null, base, new int[] {3, 6}};
96 assertEquals(baseStr + "[{<null>,5,{3,6}}]", new ToStringBuilder(base).append(array).toString());
97 assertEquals(baseStr + "[{<null>,5,{3,6}}]", new ToStringBuilder(base).append((Object) array).toString());
98 array = null;
99 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
100 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
101 }
102
103 public void testLongArray() {
104 long[] array = new long[] {1, 2, -3, 4};
105 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append(array).toString());
106 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append((Object) array).toString());
107 array = null;
108 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
109 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
110 }
111
112 public void testLongArrayArray() {
113 long[][] array = new long[][] {{1, 2}, null, {5}};
114 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append(array).toString());
115 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append((Object) array).toString());
116 array = null;
117 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
118 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
119 }
120
121 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20
21 import junit.framework.TestCase;
22
23 import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
24
25 /**
26 * Unit tests {@link org.apache.commons.lang3.builder.SimpleToStringStyleTest}.
27 *
28 * @version $Id: SimpleToStringStyleTest.java 1153484 2011-08-03 13:39:42Z ggregory $
29 */
30 public class SimpleToStringStyleTest extends TestCase {
31
32 private final Integer base = Integer.valueOf(5);
33
34 public SimpleToStringStyleTest(String name) {
35 super(name);
36 }
37
38 @Override
39 protected void setUp() throws Exception {
40 super.setUp();
41 ToStringBuilder.setDefaultStyle(ToStringStyle.SIMPLE_STYLE);
42 }
43
44 @Override
45 protected void tearDown() throws Exception {
46 super.tearDown();
47 ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
48 }
49
50 //----------------------------------------------------------------
51
52 public void testBlank() {
53 assertEquals("", new ToStringBuilder(base).toString());
54 }
55
56 public void testAppendSuper() {
57 assertEquals("", new ToStringBuilder(base).appendSuper("").toString());
58 assertEquals("<null>", new ToStringBuilder(base).appendSuper("<null>").toString());
59
60 assertEquals("hello", new ToStringBuilder(base).appendSuper("").append("a", "hello").toString());
61 assertEquals("<null>,hello", new ToStringBuilder(base).appendSuper("<null>").append("a", "hello").toString());
62 assertEquals("hello", new ToStringBuilder(base).appendSuper(null).append("a", "hello").toString());
63 }
64
65 public void testObject() {
66 Integer i3 = Integer.valueOf(3);
67 Integer i4 = Integer.valueOf(4);
68 assertEquals("<null>", new ToStringBuilder(base).append((Object) null).toString());
69 assertEquals("3", new ToStringBuilder(base).append(i3).toString());
70 assertEquals("<null>", new ToStringBuilder(base).append("a", (Object) null).toString());
71 assertEquals("3", new ToStringBuilder(base).append("a", i3).toString());
72 assertEquals("3,4", new ToStringBuilder(base).append("a", i3).append("b", i4).toString());
73 assertEquals("<Integer>", new ToStringBuilder(base).append("a", i3, false).toString());
74 assertEquals("<size=0>", new ToStringBuilder(base).append("a", new ArrayList<Object>(), false).toString());
75 assertEquals("[]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), true).toString());
76 assertEquals("<size=0>", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), false).toString());
77 assertEquals("{}", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), true).toString());
78 assertEquals("<size=0>", new ToStringBuilder(base).append("a", (Object) new String[0], false).toString());
79 assertEquals("{}", new ToStringBuilder(base).append("a", (Object) new String[0], true).toString());
80 }
81
82 public void testPerson() {
83 Person p = new Person();
84 p.name = "Jane Q. Public";
85 p.age = 47;
86 p.smoker = false;
87 assertEquals("Jane Q. Public,47,false", new ToStringBuilder(p).append("name", p.name).append("age", p.age).append("smoker", p.smoker).toString());
88 }
89
90 public void testLong() {
91 assertEquals("3", new ToStringBuilder(base).append(3L).toString());
92 assertEquals("3", new ToStringBuilder(base).append("a", 3L).toString());
93 assertEquals("3,4", new ToStringBuilder(base).append("a", 3L).append("b", 4L).toString());
94 }
95
96 public void testObjectArray() {
97 Object[] array = new Object[] {null, base, new int[] {3, 6}};
98 assertEquals("{<null>,5,{3,6}}", new ToStringBuilder(base).append(array).toString());
99 assertEquals("{<null>,5,{3,6}}", new ToStringBuilder(base).append((Object) array).toString());
100 array = null;
101 assertEquals("<null>", new ToStringBuilder(base).append(array).toString());
102 assertEquals("<null>", new ToStringBuilder(base).append((Object) array).toString());
103 }
104
105 public void testLongArray() {
106 long[] array = new long[] {1, 2, -3, 4};
107 assertEquals("{1,2,-3,4}", new ToStringBuilder(base).append(array).toString());
108 assertEquals("{1,2,-3,4}", new ToStringBuilder(base).append((Object) array).toString());
109 array = null;
110 assertEquals("<null>", new ToStringBuilder(base).append(array).toString());
111 assertEquals("<null>", new ToStringBuilder(base).append((Object) array).toString());
112 }
113
114 public void testLongArrayArray() {
115 long[][] array = new long[][] {{1, 2}, null, {5}};
116 assertEquals("{{1,2},<null>,{5}}", new ToStringBuilder(base).append(array).toString());
117 assertEquals("{{1,2},<null>,{5}}", new ToStringBuilder(base).append((Object) array).toString());
118 array = null;
119 assertEquals("<null>", new ToStringBuilder(base).append(array).toString());
120 assertEquals("<null>", new ToStringBuilder(base).append((Object) array).toString());
121 }
122
123 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20
21 import junit.framework.TestCase;
22
23 import org.apache.commons.lang3.builder.ToStringStyleTest.Person;
24
25 /**
26 * Unit tests {@link org.apache.commons.lang3.builder.ToStringStyle}.
27 *
28 * @version $Id: StandardToStringStyleTest.java 1153484 2011-08-03 13:39:42Z ggregory $
29 */
30 public class StandardToStringStyleTest extends TestCase {
31
32 private final Integer base = Integer.valueOf(5);
33 private final String baseStr = "Integer";
34
35 private static final StandardToStringStyle STYLE = new StandardToStringStyle();
36
37 static {
38 STYLE.setUseShortClassName(true);
39 STYLE.setUseIdentityHashCode(false);
40 STYLE.setArrayStart("[");
41 STYLE.setArraySeparator(", ");
42 STYLE.setArrayEnd("]");
43 STYLE.setNullText("%NULL%");
44 STYLE.setSizeStartText("%SIZE=");
45 STYLE.setSizeEndText("%");
46 STYLE.setSummaryObjectStartText("%");
47 STYLE.setSummaryObjectEndText("%");
48 }
49
50 public StandardToStringStyleTest(String name) {
51 super(name);
52 }
53
54 @Override
55 protected void setUp() throws Exception {
56 super.setUp();
57 ToStringBuilder.setDefaultStyle(STYLE);
58 }
59
60 @Override
61 protected void tearDown() throws Exception {
62 super.tearDown();
63 ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
64 }
65
66 //----------------------------------------------------------------
67
68 public void testBlank() {
69 assertEquals(baseStr + "[]", new ToStringBuilder(base).toString());
70 }
71
72 public void testAppendSuper() {
73 assertEquals(baseStr + "[]", new ToStringBuilder(base).appendSuper("Integer@8888[]").toString());
74 assertEquals(baseStr + "[%NULL%]", new ToStringBuilder(base).appendSuper("Integer@8888[%NULL%]").toString());
75
76 assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper("Integer@8888[]").append("a", "hello").toString());
77 assertEquals(baseStr + "[%NULL%,a=hello]", new ToStringBuilder(base).appendSuper("Integer@8888[%NULL%]").append("a", "hello").toString());
78 assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper(null).append("a", "hello").toString());
79 }
80
81 public void testObject() {
82 Integer i3 = Integer.valueOf(3);
83 Integer i4 = Integer.valueOf(4);
84 assertEquals(baseStr + "[%NULL%]", new ToStringBuilder(base).append((Object) null).toString());
85 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(i3).toString());
86 assertEquals(baseStr + "[a=%NULL%]", new ToStringBuilder(base).append("a", (Object) null).toString());
87 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", i3).toString());
88 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", i3).append("b", i4).toString());
89 assertEquals(baseStr + "[a=%Integer%]", new ToStringBuilder(base).append("a", i3, false).toString());
90 assertEquals(baseStr + "[a=%SIZE=0%]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), false).toString());
91 assertEquals(baseStr + "[a=[]]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), true).toString());
92 assertEquals(baseStr + "[a=%SIZE=0%]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), false).toString());
93 assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), true).toString());
94 assertEquals(baseStr + "[a=%SIZE=0%]", new ToStringBuilder(base).append("a", (Object) new String[0], false).toString());
95 assertEquals(baseStr + "[a=[]]", new ToStringBuilder(base).append("a", (Object) new String[0], true).toString());
96 }
97
98 public void testPerson() {
99 Person p = new Person();
100 p.name = "Suzy Queue";
101 p.age = 19;
102 p.smoker = false;
103 String pBaseStr = "ToStringStyleTest.Person";
104 assertEquals(pBaseStr + "[name=Suzy Queue,age=19,smoker=false]", new ToStringBuilder(p).append("name", p.name).append("age", p.age).append("smoker", p.smoker).toString());
105 }
106
107 public void testLong() {
108 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(3L).toString());
109 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", 3L).toString());
110 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", 3L).append("b", 4L).toString());
111 }
112
113 public void testObjectArray() {
114 Object[] array = new Object[] {null, base, new int[] {3, 6}};
115 assertEquals(baseStr + "[[%NULL%, 5, [3, 6]]]", new ToStringBuilder(base).append(array).toString());
116 assertEquals(baseStr + "[[%NULL%, 5, [3, 6]]]", new ToStringBuilder(base).append((Object) array).toString());
117 array = null;
118 assertEquals(baseStr + "[%NULL%]", new ToStringBuilder(base).append(array).toString());
119 assertEquals(baseStr + "[%NULL%]", new ToStringBuilder(base).append((Object) array).toString());
120 }
121
122 public void testLongArray() {
123 long[] array = new long[] {1, 2, -3, 4};
124 assertEquals(baseStr + "[[1, 2, -3, 4]]", new ToStringBuilder(base).append(array).toString());
125 assertEquals(baseStr + "[[1, 2, -3, 4]]", new ToStringBuilder(base).append((Object) array).toString());
126 array = null;
127 assertEquals(baseStr + "[%NULL%]", new ToStringBuilder(base).append(array).toString());
128 assertEquals(baseStr + "[%NULL%]", new ToStringBuilder(base).append((Object) array).toString());
129 }
130
131 public void testLongArrayArray() {
132 long[][] array = new long[][] {{1, 2}, null, {5}};
133 assertEquals(baseStr + "[[[1, 2], %NULL%, [5]]]", new ToStringBuilder(base).append(array).toString());
134 assertEquals(baseStr + "[[[1, 2], %NULL%, [5]]]", new ToStringBuilder(base).append((Object) array).toString());
135 array = null;
136 assertEquals(baseStr + "[%NULL%]", new ToStringBuilder(base).append(array).toString());
137 assertEquals(baseStr + "[%NULL%]", new ToStringBuilder(base).append((Object) array).toString());
138 }
139
140 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import static org.junit.Assert.*;
19
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
23
24 import org.junit.Test;
25
26 import org.apache.commons.lang3.SystemUtils;
27
28 /**
29 * Unit tests for {@link org.apache.commons.lang3.builder.ToStringBuilder}.
30 *
31 * @version $Id: ToStringBuilderTest.java 1154530 2011-08-06 15:43:07Z joehni $
32 */
33 public class ToStringBuilderTest {
34
35 private final Integer base = Integer.valueOf(5);
36 private final String baseStr = base.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(base));
37
38 //-----------------------------------------------------------------------
39
40 @Test
41 public void testConstructorEx1() {
42 assertEquals("<null>", new ToStringBuilder(null).toString());
43 }
44
45 @Test
46 public void testConstructorEx2() {
47 assertEquals("<null>", new ToStringBuilder(null, null).toString());
48 new ToStringBuilder(this.base, null).toString();
49 }
50
51 @Test
52 public void testConstructorEx3() {
53 assertEquals("<null>", new ToStringBuilder(null, null, null).toString());
54 new ToStringBuilder(this.base, null, null);
55 new ToStringBuilder(this.base, ToStringStyle.DEFAULT_STYLE, null);
56 }
57
58 @Test
59 public void testGetSetDefault() {
60 try {
61 ToStringBuilder.setDefaultStyle(ToStringStyle.NO_FIELD_NAMES_STYLE);
62 assertSame(ToStringStyle.NO_FIELD_NAMES_STYLE, ToStringBuilder.getDefaultStyle());
63 } finally {
64 // reset for other tests
65 ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
66 }
67 }
68
69 @Test
70 public void testSetDefaultEx() {
71 try {
72 ToStringBuilder.setDefaultStyle(null);
73
74 } catch (IllegalArgumentException ex) {
75 return;
76 }
77 fail();
78 }
79
80 @Test
81 public void testBlank() {
82 assertEquals(baseStr + "[]", new ToStringBuilder(base).toString());
83 }
84
85 /**
86 * Test wrapper for int primitive.
87 */
88 @Test
89 public void testReflectionInteger() {
90 assertEquals(baseStr + "[value=5]", ToStringBuilder.reflectionToString(base));
91 }
92
93 /**
94 * Test wrapper for char primitive.
95 */
96 @Test
97 public void testReflectionCharacter() {
98 Character c = new Character('A');
99 assertEquals(this.toBaseString(c) + "[value=A]", ToStringBuilder.reflectionToString(c));
100 }
101
102 /**
103 * Test wrapper for char boolean.
104 */
105 @Test
106 public void testReflectionBoolean() {
107 Boolean b;
108 b = Boolean.TRUE;
109 assertEquals(this.toBaseString(b) + "[value=true]", ToStringBuilder.reflectionToString(b));
110 b = Boolean.FALSE;
111 assertEquals(this.toBaseString(b) + "[value=false]", ToStringBuilder.reflectionToString(b));
112 }
113
114 /**
115 * Create the same toString() as Object.toString().
116 * @param o the object to create the string for.
117 * @return a String in the Object.toString format.
118 */
119 private String toBaseString(Object o) {
120 return o.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(o));
121 }
122
123 // Reflection Array tests
124
125 //
126 // Note on the following line of code repeated in the reflection array tests.
127 //
128 // assertReflectionArray("<null>", array);
129 //
130 // The expected value is not baseStr + "[<null>]" since array==null and is typed as Object.
131 // The null array does not carry array type information.
132 // If we added a primitive array type constructor and pile of associated methods,
133 // then type declaring type information could be carried forward. IMHO, null is null.
134 //
135 // Gary Gregory - 2003-03-12 - ggregory@seagullsw.com
136 //
137
138 public void assertReflectionArray(String expected, Object actual) {
139 if (actual == null) {
140 // Until ToStringBuilder supports null objects.
141 return;
142 }
143 assertEquals(expected, ToStringBuilder.reflectionToString(actual));
144 assertEquals(expected, ToStringBuilder.reflectionToString(actual, null));
145 assertEquals(expected, ToStringBuilder.reflectionToString(actual, null, true));
146 assertEquals(expected, ToStringBuilder.reflectionToString(actual, null, false));
147 }
148
149 @Test
150 public void testReflectionObjectArray() {
151 Object[] array = new Object[] { null, base, new int[] { 3, 6 } };
152 String baseStr = this.toBaseString(array);
153 assertEquals(baseStr + "[{<null>,5,{3,6}}]", ToStringBuilder.reflectionToString(array));
154 array = null;
155 assertReflectionArray("<null>", array);
156 this.validateNullToStringStyleRegistry();
157 }
158
159 @Test
160 public void testReflectionLongArray() {
161 long[] array = new long[] { 1, 2, -3, 4 };
162 String baseStr = this.toBaseString(array);
163 assertEquals(baseStr + "[{1,2,-3,4}]", ToStringBuilder.reflectionToString(array));
164 array = null;
165 assertReflectionArray("<null>", array);
166 this.validateNullToStringStyleRegistry();
167 }
168
169 @Test
170 public void testReflectionIntArray() {
171 int[] array = new int[] { 1, 2, -3, 4 };
172 String baseStr = this.toBaseString(array);
173 assertEquals(baseStr + "[{1,2,-3,4}]", ToStringBuilder.reflectionToString(array));
174 array = null;
175 assertReflectionArray("<null>", array);
176 this.validateNullToStringStyleRegistry();
177 }
178
179 @Test
180 public void testReflectionShortArray() {
181 short[] array = new short[] { 1, 2, -3, 4 };
182 String baseStr = this.toBaseString(array);
183 assertEquals(baseStr + "[{1,2,-3,4}]", ToStringBuilder.reflectionToString(array));
184 array = null;
185 assertReflectionArray("<null>", array);
186 this.validateNullToStringStyleRegistry();
187 }
188
189 @Test
190 public void testReflectionyteArray() {
191 byte[] array = new byte[] { 1, 2, -3, 4 };
192 String baseStr = this.toBaseString(array);
193 assertEquals(baseStr + "[{1,2,-3,4}]", ToStringBuilder.reflectionToString(array));
194 array = null;
195 assertReflectionArray("<null>", array);
196 this.validateNullToStringStyleRegistry();
197 }
198
199 @Test
200 public void testReflectionCharArray() {
201 char[] array = new char[] { 'A', '2', '_', 'D' };
202 String baseStr = this.toBaseString(array);
203 assertEquals(baseStr + "[{A,2,_,D}]", ToStringBuilder.reflectionToString(array));
204 array = null;
205 assertReflectionArray("<null>", array);
206 this.validateNullToStringStyleRegistry();
207 }
208
209 @Test
210 public void testReflectionDoubleArray() {
211 double[] array = new double[] { 1.0, 2.9876, -3.00001, 4.3 };
212 String baseStr = this.toBaseString(array);
213 assertEquals(baseStr + "[{1.0,2.9876,-3.00001,4.3}]", ToStringBuilder.reflectionToString(array));
214 array = null;
215 assertReflectionArray("<null>", array);
216 this.validateNullToStringStyleRegistry();
217 }
218
219 @Test
220 public void testReflectionFloatArray() {
221 float[] array = new float[] { 1.0f, 2.9876f, -3.00001f, 4.3f };
222 String baseStr = this.toBaseString(array);
223 assertEquals(baseStr + "[{1.0,2.9876,-3.00001,4.3}]", ToStringBuilder.reflectionToString(array));
224 array = null;
225 assertReflectionArray("<null>", array);
226 this.validateNullToStringStyleRegistry();
227 }
228
229 @Test
230 public void testReflectionBooleanArray() {
231 boolean[] array = new boolean[] { true, false, false };
232 String baseStr = this.toBaseString(array);
233 assertEquals(baseStr + "[{true,false,false}]", ToStringBuilder.reflectionToString(array));
234 array = null;
235 assertReflectionArray("<null>", array);
236 this.validateNullToStringStyleRegistry();
237 }
238
239 // Reflection Array Array tests
240
241 @Test
242 public void testReflectionFloatArrayArray() {
243 float[][] array = new float[][] { { 1.0f, 2.29686f }, null, { Float.NaN } };
244 String baseStr = this.toBaseString(array);
245 assertEquals(baseStr + "[{{1.0,2.29686},<null>,{NaN}}]", ToStringBuilder.reflectionToString(array));
246 array = null;
247 assertReflectionArray("<null>", array);
248 this.validateNullToStringStyleRegistry();
249 }
250
251
252 @Test
253 public void testReflectionLongArrayArray() {
254 long[][] array = new long[][] { { 1, 2 }, null, { 5 } };
255 String baseStr = this.toBaseString(array);
256 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", ToStringBuilder.reflectionToString(array));
257 array = null;
258 assertReflectionArray("<null>", array);
259 this.validateNullToStringStyleRegistry();
260 }
261
262 @Test
263 public void testReflectionIntArrayArray() {
264 int[][] array = new int[][] { { 1, 2 }, null, { 5 } };
265 String baseStr = this.toBaseString(array);
266 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", ToStringBuilder.reflectionToString(array));
267 array = null;
268 assertReflectionArray("<null>", array);
269 this.validateNullToStringStyleRegistry();
270 }
271
272 @Test
273 public void testReflectionhortArrayArray() {
274 short[][] array = new short[][] { { 1, 2 }, null, { 5 } };
275 String baseStr = this.toBaseString(array);
276 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", ToStringBuilder.reflectionToString(array));
277 array = null;
278 assertReflectionArray("<null>", array);
279 this.validateNullToStringStyleRegistry();
280 }
281
282 @Test
283 public void testReflectionByteArrayArray() {
284 byte[][] array = new byte[][] { { 1, 2 }, null, { 5 } };
285 String baseStr = this.toBaseString(array);
286 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", ToStringBuilder.reflectionToString(array));
287 array = null;
288 assertReflectionArray("<null>", array);
289 this.validateNullToStringStyleRegistry();
290 }
291
292 @Test
293 public void testReflectionCharArrayArray() {
294 char[][] array = new char[][] { { 'A', 'B' }, null, { 'p' } };
295 String baseStr = this.toBaseString(array);
296 assertEquals(baseStr + "[{{A,B},<null>,{p}}]", ToStringBuilder.reflectionToString(array));
297 array = null;
298 assertReflectionArray("<null>", array);
299 this.validateNullToStringStyleRegistry();
300 }
301
302 @Test
303 public void testReflectionDoubleArrayArray() {
304 double[][] array = new double[][] { { 1.0, 2.29686 }, null, { Double.NaN } };
305 String baseStr = this.toBaseString(array);
306 assertEquals(baseStr + "[{{1.0,2.29686},<null>,{NaN}}]", ToStringBuilder.reflectionToString(array));
307 array = null;
308 assertReflectionArray("<null>", array);
309 this.validateNullToStringStyleRegistry();
310 }
311
312 @Test
313 public void testReflectionBooleanArrayArray() {
314 boolean[][] array = new boolean[][] { { true, false }, null, { false } };
315 String baseStr = this.toBaseString(array);
316 assertEquals(baseStr + "[{{true,false},<null>,{false}}]", ToStringBuilder.reflectionToString(array));
317 assertEquals(baseStr + "[{{true,false},<null>,{false}}]", ToStringBuilder.reflectionToString(array));
318 array = null;
319 assertReflectionArray("<null>", array);
320 this.validateNullToStringStyleRegistry();
321 }
322
323 // Reflection hierarchy tests
324 @Test
325 public void testReflectionHierarchyArrayList() {
326 List<Object> base = new ArrayList<Object>();
327 String baseStr = this.toBaseString(base);
328 // note, the test data depends on the internal representation of the ArrayList, which may differ between JDK versions and vendors
329 String expectedWithTransients = baseStr + "[elementData={<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>},size=0,modCount=0]";
330 String toStringWithTransients = ToStringBuilder.reflectionToString(base, null, true);
331 if (!expectedWithTransients.equals(toStringWithTransients)) {
332 // representation different for IBM JDK 1.6.0, LANG-727
333 if (!("IBM Corporation".equals(SystemUtils.JAVA_VENDOR) && "1.6".equals(SystemUtils.JAVA_SPECIFICATION_VERSION))) {
334 assertEquals(expectedWithTransients, toStringWithTransients);
335 }
336 }
337 String expectedWithoutTransients = baseStr + "[size=0]";
338 String toStringWithoutTransients = ToStringBuilder.reflectionToString(base, null, false);
339 if (!expectedWithoutTransients.equals(toStringWithoutTransients)) {
340 // representation different for IBM JDK 1.6.0, LANG-727
341 if (!("IBM Corporation".equals(SystemUtils.JAVA_VENDOR) && "1.6".equals(SystemUtils.JAVA_SPECIFICATION_VERSION))) {
342 assertEquals(expectedWithoutTransients, toStringWithoutTransients);
343 }
344 }
345 this.validateNullToStringStyleRegistry();
346 }
347
348 @Test
349 public void testReflectionHierarchy() {
350 ReflectionTestFixtureA baseA = new ReflectionTestFixtureA();
351 String baseStr = this.toBaseString(baseA);
352 assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA));
353 assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null));
354 assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null, false));
355 assertEquals(baseStr + "[a=a,transientA=t]", ToStringBuilder.reflectionToString(baseA, null, true));
356 assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null, false, null));
357 assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null, false, Object.class));
358 assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null, false, ReflectionTestFixtureA.class));
359
360 ReflectionTestFixtureB baseB = new ReflectionTestFixtureB();
361 baseStr = this.toBaseString(baseB);
362 assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB));
363 assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB));
364 assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null));
365 assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null, false));
366 assertEquals(baseStr + "[b=b,transientB=t,a=a,transientA=t]", ToStringBuilder.reflectionToString(baseB, null, true));
367 assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null, false, null));
368 assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null, false, Object.class));
369 assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null, false, ReflectionTestFixtureA.class));
370 assertEquals(baseStr + "[b=b]", ToStringBuilder.reflectionToString(baseB, null, false, ReflectionTestFixtureB.class));
371 this.validateNullToStringStyleRegistry();
372 }
373
374 static class ReflectionTestFixtureA {
375 @SuppressWarnings("unused")
376 private char a='a';
377 @SuppressWarnings("unused")
378 private transient char transientA='t';
379 }
380
381 static class ReflectionTestFixtureB extends ReflectionTestFixtureA {
382 @SuppressWarnings("unused")
383 private char b='b';
384 @SuppressWarnings("unused")
385 private transient char transientB='t';
386 }
387
388 @Test
389 public void testInnerClassReflection() {
390 Outer outer = new Outer();
391 assertEquals(toBaseString(outer) + "[inner=" + toBaseString(outer.inner) + "[]]", outer.toString());
392 }
393
394 static class Outer {
395 Inner inner = new Inner();
396 class Inner {
397 @Override
398 public String toString() {
399 return ToStringBuilder.reflectionToString(this);
400 }
401 }
402 @Override
403 public String toString() {
404 return ToStringBuilder.reflectionToString(this);
405 }
406 }
407
408 // Reflection cycle tests
409
410 /**
411 * Test an array element pointing to its container.
412 */
413 @Test
414 public void testReflectionArrayCycle() throws Exception {
415 Object[] objects = new Object[1];
416 objects[0] = objects;
417 assertEquals(
418 this.toBaseString(objects) + "[{" + this.toBaseString(objects) + "}]",
419 ToStringBuilder.reflectionToString(objects));
420 this.validateNullToStringStyleRegistry();
421 }
422
423 /**
424 * Test an array element pointing to its container.
425 */
426 @Test
427 public void testReflectionArrayCycleLevel2() throws Exception {
428 Object[] objects = new Object[1];
429 Object[] objectsLevel2 = new Object[1];
430 objects[0] = objectsLevel2;
431 objectsLevel2[0] = objects;
432 assertEquals(
433 this.toBaseString(objects) + "[{{" + this.toBaseString(objects) + "}}]",
434 ToStringBuilder.reflectionToString(objects));
435 assertEquals(
436 this.toBaseString(objectsLevel2) + "[{{" + this.toBaseString(objectsLevel2) + "}}]",
437 ToStringBuilder.reflectionToString(objectsLevel2));
438 this.validateNullToStringStyleRegistry();
439 }
440
441 @Test
442 public void testReflectionArrayArrayCycle() throws Exception {
443 Object[][] objects = new Object[2][2];
444 objects[0][0] = objects;
445 objects[0][1] = objects;
446 objects[1][0] = objects;
447 objects[1][1] = objects;
448 String basicToString = this.toBaseString(objects);
449 assertEquals(
450 basicToString
451 + "[{{"
452 + basicToString
453 + ","
454 + basicToString
455 + "},{"
456 + basicToString
457 + ","
458 + basicToString
459 + "}}]",
460 ToStringBuilder.reflectionToString(objects));
461 this.validateNullToStringStyleRegistry();
462 }
463
464 /**
465 * A reflection test fixture.
466 */
467 static class ReflectionTestCycleA {
468 ReflectionTestCycleB b;
469
470 @Override
471 public String toString() {
472 return ToStringBuilder.reflectionToString(this);
473 }
474 }
475
476 /**
477 * A reflection test fixture.
478 */
479 static class ReflectionTestCycleB {
480 ReflectionTestCycleA a;
481
482 @Override
483 public String toString() {
484 return ToStringBuilder.reflectionToString(this);
485 }
486 }
487
488 /**
489 * A reflection test fixture.
490 */
491 static class SimpleReflectionTestFixture {
492 Object o;
493
494 public SimpleReflectionTestFixture() {
495 }
496
497 public SimpleReflectionTestFixture(Object o) {
498 this.o = o;
499 }
500
501 @Override
502 public String toString() {
503 return ToStringBuilder.reflectionToString(this);
504 }
505 }
506
507 private static class SelfInstanceVarReflectionTestFixture {
508 @SuppressWarnings("unused")
509 private SelfInstanceVarReflectionTestFixture typeIsSelf;
510
511 public SelfInstanceVarReflectionTestFixture() {
512 this.typeIsSelf = this;
513 }
514
515 @Override
516 public String toString() {
517 return ToStringBuilder.reflectionToString(this);
518 }
519 }
520
521 private static class SelfInstanceTwoVarsReflectionTestFixture {
522 @SuppressWarnings("unused")
523 private SelfInstanceTwoVarsReflectionTestFixture typeIsSelf;
524 private String otherType = "The Other Type";
525
526 public SelfInstanceTwoVarsReflectionTestFixture() {
527 this.typeIsSelf = this;
528 }
529
530 public String getOtherType(){
531 return this.otherType;
532 }
533
534 @Override
535 public String toString() {
536 return ToStringBuilder.reflectionToString(this);
537 }
538 }
539
540
541 /**
542 * Test an Object pointing to itself, the simplest test.
543 *
544 * @throws Exception
545 */
546 @Test
547 public void testSimpleReflectionObjectCycle() throws Exception {
548 SimpleReflectionTestFixture simple = new SimpleReflectionTestFixture();
549 simple.o = simple;
550 assertEquals(this.toBaseString(simple) + "[o=" + this.toBaseString(simple) + "]", simple.toString());
551 this.validateNullToStringStyleRegistry();
552 }
553
554 /**
555 * Test a class that defines an ivar pointing to itself.
556 *
557 * @throws Exception
558 */
559 @Test
560 public void testSelfInstanceVarReflectionObjectCycle() throws Exception {
561 SelfInstanceVarReflectionTestFixture test = new SelfInstanceVarReflectionTestFixture();
562 assertEquals(this.toBaseString(test) + "[typeIsSelf=" + this.toBaseString(test) + "]", test.toString());
563 this.validateNullToStringStyleRegistry();
564 }
565
566 /**
567 * Test a class that defines an ivar pointing to itself. This test was
568 * created to show that handling cyclical object resulted in a missing endFieldSeparator call.
569 *
570 * @throws Exception
571 */
572 @Test
573 public void testSelfInstanceTwoVarsReflectionObjectCycle() throws Exception {
574 SelfInstanceTwoVarsReflectionTestFixture test = new SelfInstanceTwoVarsReflectionTestFixture();
575 assertEquals(this.toBaseString(test) + "[typeIsSelf=" + this.toBaseString(test) + ",otherType=" + test.getOtherType().toString() + "]", test.toString());
576 this.validateNullToStringStyleRegistry();
577 }
578
579
580 /**
581 * Test Objects pointing to each other.
582 *
583 * @throws Exception
584 */
585 @Test
586 public void testReflectionObjectCycle() throws Exception {
587 ReflectionTestCycleA a = new ReflectionTestCycleA();
588 ReflectionTestCycleB b = new ReflectionTestCycleB();
589 a.b = b;
590 b.a = a;
591 assertEquals(
592 this.toBaseString(a) + "[b=" + this.toBaseString(b) + "[a=" + this.toBaseString(a) + "]]",
593 a.toString());
594 this.validateNullToStringStyleRegistry();
595 }
596
597 /**
598 * Test a nasty combination of arrays and Objects pointing to each other.
599 * objects[0] -> SimpleReflectionTestFixture[ o -> objects ]
600 *
601 * @throws Exception
602 */
603 @Test
604 public void testReflectionArrayAndObjectCycle() throws Exception {
605 Object[] objects = new Object[1];
606 SimpleReflectionTestFixture simple = new SimpleReflectionTestFixture(objects);
607 objects[0] = simple;
608 assertEquals(
609 this.toBaseString(objects)
610 + "[{"
611 + this.toBaseString(simple)
612 + "[o="
613 + this.toBaseString(objects)
614 + "]"
615 + "}]",
616 ToStringBuilder.reflectionToString(objects));
617 assertEquals(
618 this.toBaseString(simple)
619 + "[o={"
620 + this.toBaseString(simple)
621 + "}]",
622 ToStringBuilder.reflectionToString(simple));
623 this.validateNullToStringStyleRegistry();
624 }
625
626 void validateNullToStringStyleRegistry() {
627 if (ToStringStyle.getRegistry() != null) {
628 System.out.println(ToStringStyle.getRegistry());
629 }
630
631 assertNull(ToStringStyle.getRegistry());
632 }
633 // End: Reflection cycle tests
634
635 @Test
636 public void testAppendSuper() {
637 assertEquals(baseStr + "[]", new ToStringBuilder(base).appendSuper("Integer@8888[]").toString());
638 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").toString());
639
640 assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper("Integer@8888[]").append("a", "hello").toString());
641 assertEquals(baseStr + "[<null>,a=hello]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").append("a", "hello").toString());
642 assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper(null).append("a", "hello").toString());
643 }
644
645 @Test
646 public void testAppendToString() {
647 assertEquals(baseStr + "[]", new ToStringBuilder(base).appendToString("Integer@8888[]").toString());
648 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).appendToString("Integer@8888[<null>]").toString());
649
650 assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendToString("Integer@8888[]").append("a", "hello").toString());
651 assertEquals(baseStr + "[<null>,a=hello]", new ToStringBuilder(base).appendToString("Integer@8888[<null>]").append("a", "hello").toString());
652 assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendToString(null).append("a", "hello").toString());
653 }
654
655 @Test
656 public void testObject() {
657 Integer i3 = Integer.valueOf(3);
658 Integer i4 = Integer.valueOf(4);
659 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) null).toString());
660 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(i3).toString());
661 assertEquals(baseStr + "[a=<null>]", new ToStringBuilder(base).append("a", (Object) null).toString());
662 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", i3).toString());
663 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", i3).append("b", i4).toString());
664 assertEquals(baseStr + "[a=<Integer>]", new ToStringBuilder(base).append("a", i3, false).toString());
665 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), false).toString());
666 assertEquals(baseStr + "[a=[]]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), true).toString());
667 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), false).toString());
668 assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), true).toString());
669 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", (Object) new String[0], false).toString());
670 assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", (Object) new String[0], true).toString());
671 }
672
673 @Test
674 public void testObjectBuild() {
675 Integer i3 = Integer.valueOf(3);
676 Integer i4 = Integer.valueOf(4);
677 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) null).build());
678 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(i3).build());
679 assertEquals(baseStr + "[a=<null>]", new ToStringBuilder(base).append("a", (Object) null).build());
680 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", i3).build());
681 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", i3).append("b", i4).build());
682 assertEquals(baseStr + "[a=<Integer>]", new ToStringBuilder(base).append("a", i3, false).build());
683 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), false).build());
684 assertEquals(baseStr + "[a=[]]", new ToStringBuilder(base).append("a", new ArrayList<Object>(), true).build());
685 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), false).build());
686 assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", new HashMap<Object, Object>(), true).build());
687 assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a", (Object) new String[0], false).build());
688 assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", (Object) new String[0], true).build());
689 }
690
691 @Test
692 public void testLong() {
693 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(3L).toString());
694 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", 3L).toString());
695 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", 3L).append("b", 4L).toString());
696 }
697
698 @SuppressWarnings("cast") // cast is not really needed, keep for consistency
699 @Test
700 public void testInt() {
701 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append((int) 3).toString());
702 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", (int) 3).toString());
703 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", (int) 3).append("b", (int) 4).toString());
704 }
705
706 @Test
707 public void testShort() {
708 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append((short) 3).toString());
709 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", (short) 3).toString());
710 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", (short) 3).append("b", (short) 4).toString());
711 }
712
713 @Test
714 public void testChar() {
715 assertEquals(baseStr + "[A]", new ToStringBuilder(base).append((char) 65).toString());
716 assertEquals(baseStr + "[a=A]", new ToStringBuilder(base).append("a", (char) 65).toString());
717 assertEquals(baseStr + "[a=A,b=B]", new ToStringBuilder(base).append("a", (char) 65).append("b", (char) 66).toString());
718 }
719
720 @Test
721 public void testByte() {
722 assertEquals(baseStr + "[3]", new ToStringBuilder(base).append((byte) 3).toString());
723 assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", (byte) 3).toString());
724 assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", (byte) 3).append("b", (byte) 4).toString());
725 }
726
727 @SuppressWarnings("cast")
728 @Test
729 public void testDouble() {
730 assertEquals(baseStr + "[3.2]", new ToStringBuilder(base).append((double) 3.2).toString());
731 assertEquals(baseStr + "[a=3.2]", new ToStringBuilder(base).append("a", (double) 3.2).toString());
732 assertEquals(baseStr + "[a=3.2,b=4.3]", new ToStringBuilder(base).append("a", (double) 3.2).append("b", (double) 4.3).toString());
733 }
734
735 @Test
736 public void testFloat() {
737 assertEquals(baseStr + "[3.2]", new ToStringBuilder(base).append((float) 3.2).toString());
738 assertEquals(baseStr + "[a=3.2]", new ToStringBuilder(base).append("a", (float) 3.2).toString());
739 assertEquals(baseStr + "[a=3.2,b=4.3]", new ToStringBuilder(base).append("a", (float) 3.2).append("b", (float) 4.3).toString());
740 }
741
742 @Test
743 public void testBoolean() {
744 assertEquals(baseStr + "[true]", new ToStringBuilder(base).append(true).toString());
745 assertEquals(baseStr + "[a=true]", new ToStringBuilder(base).append("a", true).toString());
746 assertEquals(baseStr + "[a=true,b=false]", new ToStringBuilder(base).append("a", true).append("b", false).toString());
747 }
748
749
750 @Test
751 public void testObjectArray() {
752 Object[] array = new Object[] {null, base, new int[] {3, 6}};
753 assertEquals(baseStr + "[{<null>,5,{3,6}}]", new ToStringBuilder(base).append(array).toString());
754 assertEquals(baseStr + "[{<null>,5,{3,6}}]", new ToStringBuilder(base).append((Object) array).toString());
755 array = null;
756 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
757 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
758 }
759
760 @Test
761 public void testLongArray() {
762 long[] array = new long[] {1, 2, -3, 4};
763 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append(array).toString());
764 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append((Object) array).toString());
765 array = null;
766 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
767 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
768 }
769
770 @Test
771 public void testIntArray() {
772 int[] array = new int[] {1, 2, -3, 4};
773 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append(array).toString());
774 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append((Object) array).toString());
775 array = null;
776 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
777 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
778 }
779
780 @Test
781 public void testShortArray() {
782 short[] array = new short[] {1, 2, -3, 4};
783 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append(array).toString());
784 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append((Object) array).toString());
785 array = null;
786 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
787 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
788 }
789
790 @Test
791 public void testByteArray() {
792 byte[] array = new byte[] {1, 2, -3, 4};
793 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append(array).toString());
794 assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append((Object) array).toString());
795 array = null;
796 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
797 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
798 }
799
800 @Test
801 public void testCharArray() {
802 char[] array = new char[] {'A', '2', '_', 'D'};
803 assertEquals(baseStr + "[{A,2,_,D}]", new ToStringBuilder(base).append(array).toString());
804 assertEquals(baseStr + "[{A,2,_,D}]", new ToStringBuilder(base).append((Object) array).toString());
805 array = null;
806 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
807 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
808 }
809
810 @Test
811 public void testDoubleArray() {
812 double[] array = new double[] {1.0, 2.9876, -3.00001, 4.3};
813 assertEquals(baseStr + "[{1.0,2.9876,-3.00001,4.3}]", new ToStringBuilder(base).append(array).toString());
814 assertEquals(baseStr + "[{1.0,2.9876,-3.00001,4.3}]", new ToStringBuilder(base).append((Object) array).toString());
815 array = null;
816 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
817 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
818 }
819
820 @Test
821 public void testFloatArray() {
822 float[] array = new float[] {1.0f, 2.9876f, -3.00001f, 4.3f};
823 assertEquals(baseStr + "[{1.0,2.9876,-3.00001,4.3}]", new ToStringBuilder(base).append(array).toString());
824 assertEquals(baseStr + "[{1.0,2.9876,-3.00001,4.3}]", new ToStringBuilder(base).append((Object) array).toString());
825 array = null;
826 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
827 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
828 }
829
830 @Test
831 public void testBooleanArray() {
832 boolean[] array = new boolean[] {true, false, false};
833 assertEquals(baseStr + "[{true,false,false}]", new ToStringBuilder(base).append(array).toString());
834 assertEquals(baseStr + "[{true,false,false}]", new ToStringBuilder(base).append((Object) array).toString());
835 array = null;
836 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
837 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
838 }
839
840 @Test
841 public void testLongArrayArray() {
842 long[][] array = new long[][] {{1, 2}, null, {5}};
843 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append(array).toString());
844 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append((Object) array).toString());
845 array = null;
846 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
847 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
848 }
849
850 @Test
851 public void testIntArrayArray() {
852 int[][] array = new int[][] {{1, 2}, null, {5}};
853 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append(array).toString());
854 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append((Object) array).toString());
855 array = null;
856 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
857 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
858 }
859
860 @Test
861 public void testShortArrayArray() {
862 short[][] array = new short[][] {{1, 2}, null, {5}};
863 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append(array).toString());
864 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append((Object) array).toString());
865 array = null;
866 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
867 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
868 }
869
870 @Test
871 public void testByteArrayArray() {
872 byte[][] array = new byte[][] {{1, 2}, null, {5}};
873 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append(array).toString());
874 assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append((Object) array).toString());
875 array = null;
876 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
877 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
878 }
879
880 @Test
881 public void testCharArrayArray() {
882 char[][] array = new char[][] {{'A', 'B'}, null, {'p'}};
883 assertEquals(baseStr + "[{{A,B},<null>,{p}}]", new ToStringBuilder(base).append(array).toString());
884 assertEquals(baseStr + "[{{A,B},<null>,{p}}]", new ToStringBuilder(base).append((Object) array).toString());
885 array = null;
886 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
887 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
888 }
889
890 @Test
891 public void testDoubleArrayArray() {
892 double[][] array = new double[][] {{1.0, 2.29686}, null, {Double.NaN}};
893 assertEquals(baseStr + "[{{1.0,2.29686},<null>,{NaN}}]", new ToStringBuilder(base).append(array).toString());
894 assertEquals(baseStr + "[{{1.0,2.29686},<null>,{NaN}}]", new ToStringBuilder(base).append((Object) array).toString());
895 array = null;
896 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
897 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
898 }
899
900 @Test
901 public void testFloatArrayArray() {
902 float[][] array = new float[][] {{1.0f, 2.29686f}, null, {Float.NaN}};
903 assertEquals(baseStr + "[{{1.0,2.29686},<null>,{NaN}}]", new ToStringBuilder(base).append(array).toString());
904 assertEquals(baseStr + "[{{1.0,2.29686},<null>,{NaN}}]", new ToStringBuilder(base).append((Object) array).toString());
905 array = null;
906 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
907 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
908 }
909
910 @Test
911 public void testBooleanArrayArray() {
912 boolean[][] array = new boolean[][] {{true, false}, null, {false}};
913 assertEquals(baseStr + "[{{true,false},<null>,{false}}]", new ToStringBuilder(base).append(array).toString());
914 assertEquals(baseStr + "[{{true,false},<null>,{false}}]", new ToStringBuilder(base).append((Object) array).toString());
915 array = null;
916 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
917 assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
918 }
919
920 @Test
921 public void testObjectCycle() {
922 ObjectCycle a = new ObjectCycle();
923 ObjectCycle b = new ObjectCycle();
924 a.obj = b;
925 b.obj = a;
926
927 String expected = toBaseString(a) + "[" + toBaseString(b) + "[" + toBaseString(a) + "]]";
928 assertEquals(expected, a.toString());
929 validateNullToStringStyleRegistry();
930 }
931
932 static class ObjectCycle {
933 Object obj;
934
935 @Override
936 public String toString() {
937 return new ToStringBuilder(this).append(obj).toString();
938 }
939 }
940
941 @Test
942 public void testSimpleReflectionStatics() {
943 SimpleReflectionStaticFieldsFixture instance1 = new SimpleReflectionStaticFieldsFixture();
944 assertEquals(
945 this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345]",
946 ReflectionToStringBuilder.toString(instance1, null, false, true, SimpleReflectionStaticFieldsFixture.class));
947 assertEquals(
948 this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345]",
949 ReflectionToStringBuilder.toString(instance1, null, true, true, SimpleReflectionStaticFieldsFixture.class));
950 assertEquals(
951 this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345]",
952 this.toStringWithStatics(instance1, null, SimpleReflectionStaticFieldsFixture.class));
953 assertEquals(
954 this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345]",
955 this.toStringWithStatics(instance1, null, SimpleReflectionStaticFieldsFixture.class));
956 }
957
958 /**
959 * Tests ReflectionToStringBuilder.toString() for statics.
960 */
961 @Test
962 public void testReflectionStatics() {
963 ReflectionStaticFieldsFixture instance1 = new ReflectionStaticFieldsFixture();
964 assertEquals(
965 this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345,instanceString=instanceString,instanceInt=67890]",
966 ReflectionToStringBuilder.toString(instance1, null, false, true, ReflectionStaticFieldsFixture.class));
967 assertEquals(
968 this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345,staticTransientString=staticTransientString,staticTransientInt=54321,instanceString=instanceString,instanceInt=67890,transientString=transientString,transientInt=98765]",
969 ReflectionToStringBuilder.toString(instance1, null, true, true, ReflectionStaticFieldsFixture.class));
970 assertEquals(
971 this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345,instanceString=instanceString,instanceInt=67890]",
972 this.toStringWithStatics(instance1, null, ReflectionStaticFieldsFixture.class));
973 assertEquals(
974 this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345,instanceString=instanceString,instanceInt=67890]",
975 this.toStringWithStatics(instance1, null, ReflectionStaticFieldsFixture.class));
976 }
977
978 /**
979 * Tests ReflectionToStringBuilder.toString() for statics.
980 */
981 @Test
982 public void testInheritedReflectionStatics() {
983 InheritedReflectionStaticFieldsFixture instance1 = new InheritedReflectionStaticFieldsFixture();
984 assertEquals(
985 this.toBaseString(instance1) + "[staticString2=staticString2,staticInt2=67890]",
986 ReflectionToStringBuilder.toString(instance1, null, false, true, InheritedReflectionStaticFieldsFixture.class));
987 assertEquals(
988 this.toBaseString(instance1) + "[staticString2=staticString2,staticInt2=67890,staticString=staticString,staticInt=12345]",
989 ReflectionToStringBuilder.toString(instance1, null, false, true, SimpleReflectionStaticFieldsFixture.class));
990 assertEquals(
991 this.toBaseString(instance1) + "[staticString2=staticString2,staticInt2=67890,staticString=staticString,staticInt=12345]",
992 this.toStringWithStatics(instance1, null, SimpleReflectionStaticFieldsFixture.class));
993 assertEquals(
994 this.toBaseString(instance1) + "[staticString2=staticString2,staticInt2=67890,staticString=staticString,staticInt=12345]",
995 this.toStringWithStatics(instance1, null, SimpleReflectionStaticFieldsFixture.class));
996 }
997
998 /**
999 * <p>This method uses reflection to build a suitable
1000 * <code>toString</code> value which includes static fields.</p>
1001 *
1002 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
1003 * fields. This means that it will throw a security exception if run
1004 * under a security manager, if the permissions are not set up correctly.
1005 * It is also not as efficient as testing explicitly. </p>
1006 *
1007 * <p>Transient fields are not output.</p>
1008 *
1009 * <p>Superclass fields will be appended up to and including the specified superclass.
1010 * A null superclass is treated as <code>java.lang.Object</code>.</p>
1011 *
1012 * <p>If the style is <code>null</code>, the default
1013 * <code>ToStringStyle</code> is used.</p>
1014 *
1015 * @param object the Object to be output
1016 * @param style the style of the <code>toString</code> to create,
1017 * may be <code>null</code>
1018 * @param reflectUpToClass the superclass to reflect up to (inclusive),
1019 * may be <code>null</code>
1020 * @return the String result
1021 * @throws IllegalArgumentException if the Object is <code>null</code>
1022 */
1023 public <T> String toStringWithStatics(T object, ToStringStyle style, Class<? super T> reflectUpToClass) {
1024 return ReflectionToStringBuilder.toString(object, style, false, true, reflectUpToClass);
1025 }
1026
1027 /**
1028 * Tests ReflectionToStringBuilder setUpToClass().
1029 */
1030 @Test
1031 public void test_setUpToClass_valid() {
1032 Integer val = Integer.valueOf(5);
1033 ReflectionToStringBuilder test = new ReflectionToStringBuilder(val);
1034 test.setUpToClass(Number.class);
1035 }
1036
1037 /**
1038 * Tests ReflectionToStringBuilder setUpToClass().
1039 */
1040 @Test
1041 public void test_setUpToClass_invalid() {
1042 Integer val = Integer.valueOf(5);
1043 ReflectionToStringBuilder test = new ReflectionToStringBuilder(val);
1044 try {
1045 test.setUpToClass(String.class);
1046 fail();
1047 } catch (IllegalArgumentException ex) {
1048 // expected
1049 }
1050 }
1051
1052 /**
1053 * Tests ReflectionToStringBuilder.toString() for statics.
1054 */
1055 class ReflectionStaticFieldsFixture {
1056 static final String staticString = "staticString";
1057 static final int staticInt = 12345;
1058 static final transient String staticTransientString = "staticTransientString";
1059 static final transient int staticTransientInt = 54321;
1060 String instanceString = "instanceString";
1061 int instanceInt = 67890;
1062 transient String transientString = "transientString";
1063 transient int transientInt = 98765;
1064 }
1065
1066 /**
1067 * Test fixture for ReflectionToStringBuilder.toString() for statics.
1068 */
1069 class SimpleReflectionStaticFieldsFixture {
1070 static final String staticString = "staticString";
1071 static final int staticInt = 12345;
1072 }
1073
1074 /**
1075 * Test fixture for ReflectionToStringBuilder.toString() for statics.
1076 */
1077 class InheritedReflectionStaticFieldsFixture extends SimpleReflectionStaticFieldsFixture {
1078 static final String staticString2 = "staticString2";
1079 static final int staticInt2 = 67890;
1080 }
1081
1082 @Test
1083 public void testReflectionNull() {
1084 assertEquals("<null>", ReflectionToStringBuilder.toString(null));
1085 }
1086
1087 /**
1088 * Points out failure to print anything from appendToString methods using MULTI_LINE_STYLE.
1089 * See issue LANG-372.
1090 */
1091 class MultiLineTestObject {
1092 Integer i = Integer.valueOf(31337);
1093 @Override
1094 public String toString() {
1095 return new ToStringBuilder(this).append("testInt", i).toString();
1096 }
1097 }
1098
1099 @Test
1100 public void testAppendToStringUsingMultiLineStyle() {
1101 MultiLineTestObject obj = new MultiLineTestObject();
1102 ToStringBuilder testBuilder = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
1103 .appendToString(obj.toString());
1104 assertEquals(testBuilder.toString().indexOf("testInt=31337"), -1);
1105 }
1106
1107 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.builder;
17
18 import junit.framework.TestCase;
19
20 /**
21 * Test case for ToStringStyle.
22 *
23 * @version $Id: ToStringStyleTest.java 1088899 2011-04-05 05:31:27Z bayard $
24 */
25 public class ToStringStyleTest extends TestCase {
26
27 public ToStringStyleTest(String name) {
28 super(name);
29 }
30
31 private static class ToStringStyleImpl extends ToStringStyle {
32 }
33
34 //-----------------------------------------------------------------------
35 public void testSetArrayStart() {
36 ToStringStyle style = new ToStringStyleImpl();
37 style.setArrayStart(null);
38 assertEquals("", style.getArrayStart());
39 }
40
41 public void testSetArrayEnd() {
42 ToStringStyle style = new ToStringStyleImpl();
43 style.setArrayEnd(null);
44 assertEquals("", style.getArrayEnd());
45 }
46
47 public void testSetArraySeparator() {
48 ToStringStyle style = new ToStringStyleImpl();
49 style.setArraySeparator(null);
50 assertEquals("", style.getArraySeparator());
51 }
52
53 public void testSetContentStart() {
54 ToStringStyle style = new ToStringStyleImpl();
55 style.setContentStart(null);
56 assertEquals("", style.getContentStart());
57 }
58
59 public void testSetContentEnd() {
60 ToStringStyle style = new ToStringStyleImpl();
61 style.setContentEnd(null);
62 assertEquals("", style.getContentEnd());
63 }
64
65 public void testSetFieldNameValueSeparator() {
66 ToStringStyle style = new ToStringStyleImpl();
67 style.setFieldNameValueSeparator(null);
68 assertEquals("", style.getFieldNameValueSeparator());
69 }
70
71 public void testSetFieldSeparator() {
72 ToStringStyle style = new ToStringStyleImpl();
73 style.setFieldSeparator(null);
74 assertEquals("", style.getFieldSeparator());
75 }
76
77 public void testSetNullText() {
78 ToStringStyle style = new ToStringStyleImpl();
79 style.setNullText(null);
80 assertEquals("", style.getNullText());
81 }
82
83 public void testSetSizeStartText() {
84 ToStringStyle style = new ToStringStyleImpl();
85 style.setSizeStartText(null);
86 assertEquals("", style.getSizeStartText());
87 }
88
89 public void testSetSizeEndText() {
90 ToStringStyle style = new ToStringStyleImpl();
91 style.setSizeEndText(null);
92 assertEquals("", style.getSizeEndText());
93 }
94
95 public void testSetSummaryObjectStartText() {
96 ToStringStyle style = new ToStringStyleImpl();
97 style.setSummaryObjectStartText(null);
98 assertEquals("", style.getSummaryObjectStartText());
99 }
100
101 public void testSetSummaryObjectEndText() {
102 ToStringStyle style = new ToStringStyleImpl();
103 style.setSummaryObjectEndText(null);
104 assertEquals("", style.getSummaryObjectEndText());
105 }
106
107 /**
108 * An object used to test {@link ToStringStyle}.
109 *
110 */
111 static class Person {
112 /**
113 * Test String field.
114 */
115 String name;
116
117 /**
118 * Test integer field.
119 */
120 int age;
121
122 /**
123 * Test boolean field.
124 */
125 boolean smoker;
126 }
127 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20
21 import java.util.concurrent.CountDownLatch;
22
23 import org.junit.Test;
24
25 /**
26 * <p>
27 * An abstract base class for tests of concrete {@code ConcurrentInitializer}
28 * implementations.
29 * </p>
30 * <p>
31 * This class provides some basic tests for initializer implementations. Derived
32 * class have to create a {@link ConcurrentInitializer} object on which the
33 * tests are executed.
34 * </p>
35 *
36 * @version $Id: AbstractConcurrentInitializerTest.java 1088899 2011-04-05 05:31:27Z bayard $
37 */
38 public abstract class AbstractConcurrentInitializerTest {
39 /**
40 * Tests a simple invocation of the get() method.
41 */
42 @Test
43 public void testGet() throws ConcurrentException {
44 assertNotNull("No managed object", createInitializer().get());
45 }
46
47 /**
48 * Tests whether sequential get() invocations always return the same
49 * instance.
50 */
51 @Test
52 public void testGetMultipleTimes() throws ConcurrentException {
53 ConcurrentInitializer<Object> initializer = createInitializer();
54 Object obj = initializer.get();
55 for (int i = 0; i < 10; i++) {
56 assertEquals("Got different object at " + i, obj, initializer.get());
57 }
58 }
59
60 /**
61 * Tests whether get() can be invoked from multiple threads concurrently.
62 * Always the same object should be returned.
63 */
64 @Test
65 public void testGetConcurrent() throws ConcurrentException,
66 InterruptedException {
67 final ConcurrentInitializer<Object> initializer = createInitializer();
68 final int threadCount = 20;
69 final CountDownLatch startLatch = new CountDownLatch(1);
70 class GetThread extends Thread {
71 Object object;
72
73 @Override
74 public void run() {
75 try {
76 // wait until all threads are ready for maximum parallelism
77 startLatch.await();
78 // access the initializer
79 object = initializer.get();
80 } catch (InterruptedException iex) {
81 // ignore
82 } catch (ConcurrentException cex) {
83 object = cex;
84 }
85 }
86 }
87
88 GetThread[] threads = new GetThread[threadCount];
89 for (int i = 0; i < threadCount; i++) {
90 threads[i] = new GetThread();
91 threads[i].start();
92 }
93
94 // fire all threads and wait until they are ready
95 startLatch.countDown();
96 for (Thread t : threads) {
97 t.join();
98 }
99
100 // check results
101 Object managedObject = initializer.get();
102 for (GetThread t : threads) {
103 assertEquals("Wrong object", managedObject, t.object);
104 }
105 }
106
107 /**
108 * Creates the {@link ConcurrentInitializer} object to be tested. This
109 * method is called whenever the test fixture needs to be obtained.
110 *
111 * @return the initializer object to be tested
112 */
113 protected abstract ConcurrentInitializer<Object> createInitializer();
114 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 /**
19 * Test class for {@code AtomicInitializer}.
20 *
21 * @version $Id: AtomicInitializerTest.java 1088899 2011-04-05 05:31:27Z bayard $
22 */
23 public class AtomicInitializerTest extends AbstractConcurrentInitializerTest {
24 /**
25 * Returns the initializer to be tested.
26 *
27 * @return the {@code AtomicInitializer}
28 */
29 @Override
30 protected ConcurrentInitializer<Object> createInitializer() {
31 return new AtomicInitializer<Object>() {
32 @Override
33 protected Object initialize() throws ConcurrentException {
34 return new Object();
35 }
36 };
37 }
38 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import static org.junit.Assert.assertEquals;
19
20 import java.util.concurrent.atomic.AtomicInteger;
21
22 import org.junit.Before;
23 import org.junit.Test;
24
25 /**
26 * Test class for {@code AtomicSafeInitializer}.
27 *
28 * @version $Id: AtomicSafeInitializerTest.java 1088899 2011-04-05 05:31:27Z bayard $
29 */
30 public class AtomicSafeInitializerTest extends
31 AbstractConcurrentInitializerTest {
32 /** The instance to be tested. */
33 private AtomicSafeInitializerTestImpl initializer;
34
35 @Before
36 public void setUp() throws Exception {
37 initializer = new AtomicSafeInitializerTestImpl();
38 }
39
40 /**
41 * Returns the initializer to be tested.
42 *
43 * @return the {@code AtomicSafeInitializer} under test
44 */
45 @Override
46 protected ConcurrentInitializer<Object> createInitializer() {
47 return initializer;
48 }
49
50 /**
51 * Tests that initialize() is called only once.
52 */
53 @Test
54 public void testNumberOfInitializeInvocations() throws ConcurrentException,
55 InterruptedException {
56 testGetConcurrent();
57 assertEquals("Wrong number of invocations", 1,
58 initializer.initCounter.get());
59 }
60
61 /**
62 * A concrete test implementation of {@code AtomicSafeInitializer}. This
63 * implementation also counts the number of invocations of the initialize()
64 * method.
65 */
66 private static class AtomicSafeInitializerTestImpl extends
67 AtomicSafeInitializer<Object> {
68 /** A counter for initialize() invocations. */
69 final AtomicInteger initCounter = new AtomicInteger();
70
71 @Override
72 protected Object initialize() throws ConcurrentException {
73 initCounter.incrementAndGet();
74 return new Object();
75 }
76 }
77 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import java.util.concurrent.CountDownLatch;
19 import java.util.concurrent.ExecutorService;
20 import java.util.concurrent.Executors;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.atomic.AtomicReference;
23
24 import junit.framework.TestCase;
25
26 public class BackgroundInitializerTest extends TestCase {
27 /**
28 * Helper method for checking whether the initialize() method was correctly
29 * called. start() must already have been invoked.
30 *
31 * @param init the initializer to test
32 */
33 private void checkInitialize(BackgroundInitializerTestImpl init) {
34 try {
35 Integer result = init.get();
36 assertEquals("Wrong result", 1, result.intValue());
37 assertEquals("Wrong number of invocations", 1, init.initializeCalls);
38 assertNotNull("No future", init.getFuture());
39 } catch (ConcurrentException cex) {
40 fail("Unexpected exception: " + cex);
41 }
42 }
43
44 /**
45 * Tests whether initialize() is invoked.
46 */
47 public void testInitialize() {
48 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
49 init.start();
50 checkInitialize(init);
51 }
52
53 /**
54 * Tries to obtain the executor before start(). It should not have been
55 * initialized yet.
56 */
57 public void testGetActiveExecutorBeforeStart() {
58 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
59 assertNull("Got an executor", init.getActiveExecutor());
60 }
61
62 /**
63 * Tests whether an external executor is correctly detected.
64 */
65 public void testGetActiveExecutorExternal() {
66 ExecutorService exec = Executors.newSingleThreadExecutor();
67 try {
68 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl(
69 exec);
70 init.start();
71 assertSame("Wrong executor", exec, init.getActiveExecutor());
72 checkInitialize(init);
73 } finally {
74 exec.shutdown();
75 }
76 }
77
78 /**
79 * Tests getActiveExecutor() for a temporary executor.
80 */
81 public void testGetActiveExecutorTemp() {
82 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
83 init.start();
84 assertNotNull("No active executor", init.getActiveExecutor());
85 checkInitialize(init);
86 }
87
88 /**
89 * Tests the execution of the background task if a temporary executor has to
90 * be created.
91 */
92 public void testInitializeTempExecutor() {
93 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
94 assertTrue("Wrong result of start()", init.start());
95 checkInitialize(init);
96 assertTrue("Executor not shutdown", init.getActiveExecutor()
97 .isShutdown());
98 }
99
100 /**
101 * Tests whether an external executor can be set using the
102 * setExternalExecutor() method.
103 */
104 public void testSetExternalExecutor() throws Exception {
105 ExecutorService exec = Executors.newCachedThreadPool();
106 try {
107 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
108 init.setExternalExecutor(exec);
109 assertEquals("Wrong executor service", exec, init
110 .getExternalExecutor());
111 assertTrue("Wrong result of start()", init.start());
112 assertSame("Wrong active executor", exec, init.getActiveExecutor());
113 checkInitialize(init);
114 assertFalse("Executor was shutdown", exec.isShutdown());
115 } finally {
116 exec.shutdown();
117 }
118 }
119
120 /**
121 * Tests that setting an executor after start() causes an exception.
122 */
123 public void testSetExternalExecutorAfterStart() throws ConcurrentException {
124 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
125 init.start();
126 try {
127 init.setExternalExecutor(Executors.newSingleThreadExecutor());
128 fail("Could set executor after start()!");
129 } catch (IllegalStateException istex) {
130 init.get();
131 }
132 }
133
134 /**
135 * Tests invoking start() multiple times. Only the first invocation should
136 * have an effect.
137 */
138 public void testStartMultipleTimes() {
139 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
140 assertTrue("Wrong result for start()", init.start());
141 for (int i = 0; i < 10; i++) {
142 assertFalse("Could start again", init.start());
143 }
144 checkInitialize(init);
145 }
146
147 /**
148 * Tests calling get() before start(). This should cause an exception.
149 */
150 public void testGetBeforeStart() throws ConcurrentException {
151 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
152 try {
153 init.get();
154 fail("Could call get() before start()!");
155 } catch (IllegalStateException istex) {
156 // ok
157 }
158 }
159
160 /**
161 * Tests the get() method if background processing causes a runtime
162 * exception.
163 */
164 public void testGetRuntimeException() throws Exception {
165 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
166 RuntimeException rex = new RuntimeException();
167 init.ex = rex;
168 init.start();
169 try {
170 init.get();
171 fail("Exception not thrown!");
172 } catch (Exception ex) {
173 assertEquals("Runtime exception not thrown", rex, ex);
174 }
175 }
176
177 /**
178 * Tests the get() method if background processing causes a checked
179 * exception.
180 */
181 public void testGetCheckedException() throws Exception {
182 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
183 Exception ex = new Exception();
184 init.ex = ex;
185 init.start();
186 try {
187 init.get();
188 fail("Exception not thrown!");
189 } catch (ConcurrentException cex) {
190 assertEquals("Exception not thrown", ex, cex.getCause());
191 }
192 }
193
194 /**
195 * Tests the get() method if waiting for the initialization is interrupted.
196 */
197 public void testGetInterruptedException() throws Exception {
198 ExecutorService exec = Executors.newSingleThreadExecutor();
199 final BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl(
200 exec);
201 final CountDownLatch latch1 = new CountDownLatch(1);
202 init.shouldSleep = true;
203 init.start();
204 final AtomicReference<InterruptedException> iex = new AtomicReference<InterruptedException>();
205 Thread getThread = new Thread() {
206 @Override
207 public void run() {
208 try {
209 init.get();
210 } catch (ConcurrentException cex) {
211 if (cex.getCause() instanceof InterruptedException) {
212 iex.set((InterruptedException) cex.getCause());
213 }
214 } finally {
215 assertTrue("Thread not interrupted", isInterrupted());
216 latch1.countDown();
217 }
218 }
219 };
220 getThread.start();
221 getThread.interrupt();
222 latch1.await();
223 exec.shutdownNow();
224 exec.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
225 assertNotNull("No interrupted exception", iex.get());
226 }
227
228 /**
229 * Tests isStarted() before start() was called.
230 */
231 public void testIsStartedFalse() {
232 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
233 assertFalse("Already started", init.isStarted());
234 }
235
236 /**
237 * Tests isStarted() after start().
238 */
239 public void testIsStartedTrue() {
240 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
241 init.start();
242 assertTrue("Not started", init.isStarted());
243 }
244
245 /**
246 * Tests isStarted() after the background task has finished.
247 */
248 public void testIsStartedAfterGet() {
249 BackgroundInitializerTestImpl init = new BackgroundInitializerTestImpl();
250 init.start();
251 checkInitialize(init);
252 assertTrue("Not started", init.isStarted());
253 }
254
255 /**
256 * A concrete implementation of BackgroundInitializer. It also overloads
257 * some methods that simplify testing.
258 */
259 private static class BackgroundInitializerTestImpl extends
260 BackgroundInitializer<Integer> {
261 /** An exception to be thrown by initialize(). */
262 Exception ex;
263
264 /** A flag whether the background task should sleep a while. */
265 boolean shouldSleep;
266
267 /** The number of invocations of initialize(). */
268 volatile int initializeCalls;
269
270 public BackgroundInitializerTestImpl() {
271 super();
272 }
273
274 public BackgroundInitializerTestImpl(ExecutorService exec) {
275 super(exec);
276 }
277
278 /**
279 * Records this invocation. Optionally throws an exception or sleeps a
280 * while.
281 */
282 @Override
283 protected Integer initialize() throws Exception {
284 if (ex != null) {
285 throw ex;
286 }
287 if (shouldSleep) {
288 Thread.sleep(60000L);
289 }
290 return ++initializeCalls;
291 }
292 }
293 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertNotSame;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertSame;
24 import static org.junit.Assert.assertTrue;
25
26 import java.util.concurrent.ThreadFactory;
27
28 import org.easymock.EasyMock;
29 import org.junit.Before;
30 import org.junit.Test;
31
32 /**
33 * Test class for {@code BasicThreadFactory}.
34 *
35 * @version $Id: BasicThreadFactoryTest.java 979392 2010-07-26 18:09:52Z mbenson $
36 */
37 public class BasicThreadFactoryTest {
38 /** Constant for the test naming pattern. */
39 private static final String PATTERN = "testThread-%d";
40
41 /** The builder for creating a thread factory. */
42 private BasicThreadFactory.Builder builder;
43
44 @Before
45 public void setUp() throws Exception {
46 builder = new BasicThreadFactory.Builder();
47 }
48
49 /**
50 * Tests the default options of a thread factory.
51 *
52 * @param factory the factory to be checked
53 */
54 private void checkFactoryDefaults(BasicThreadFactory factory) {
55 assertNull("Got a naming pattern", factory.getNamingPattern());
56 assertNull("Got an exception handler", factory
57 .getUncaughtExceptionHandler());
58 assertNull("Got a priority", factory.getPriority());
59 assertNull("Got a daemon flag", factory.getDaemonFlag());
60 assertNotNull("No wrapped factory", factory.getWrappedFactory());
61 }
62
63 /**
64 * Tests the default values used by the builder.
65 */
66 @Test
67 public void testBuildDefaults() {
68 BasicThreadFactory factory = builder.build();
69 checkFactoryDefaults(factory);
70 }
71
72 /**
73 * Tries to set a null naming pattern.
74 */
75 @Test(expected = NullPointerException.class)
76 public void testBuildNamingPatternNull() {
77 builder.namingPattern(null);
78 }
79
80 /**
81 * Tries to set a null wrapped factory.
82 */
83 @Test(expected = NullPointerException.class)
84 public void testBuildWrappedFactoryNull() {
85 builder.wrappedFactory(null);
86 }
87
88 /**
89 * Tries to set a null exception handler.
90 */
91 @Test(expected = NullPointerException.class)
92 public void testBuildUncaughtExceptionHandlerNull() {
93 builder.uncaughtExceptionHandler(null);
94 }
95
96 /**
97 * Tests the reset() method of the builder.
98 */
99 @Test
100 public void testBuilderReset() {
101 ThreadFactory wrappedFactory = EasyMock.createMock(ThreadFactory.class);
102 Thread.UncaughtExceptionHandler exHandler = EasyMock
103 .createMock(Thread.UncaughtExceptionHandler.class);
104 EasyMock.replay(wrappedFactory, exHandler);
105 builder.namingPattern(PATTERN).daemon(true).priority(
106 Thread.MAX_PRIORITY).uncaughtExceptionHandler(exHandler)
107 .wrappedFactory(wrappedFactory);
108 builder.reset();
109 BasicThreadFactory factory = builder.build();
110 checkFactoryDefaults(factory);
111 assertNotSame("Wrapped factory not reset", wrappedFactory, factory
112 .getWrappedFactory());
113 EasyMock.verify(wrappedFactory, exHandler);
114 }
115
116 /**
117 * Tests whether reset() is automatically called after build().
118 */
119 @Test
120 public void testBuilderResetAfterBuild() {
121 builder.wrappedFactory(EasyMock.createNiceMock(ThreadFactory.class))
122 .namingPattern(PATTERN).daemon(true).build();
123 checkFactoryDefaults(builder.build());
124 }
125
126 /**
127 * Tests whether the naming pattern is applied to new threads.
128 */
129 @Test
130 public void testNewThreadNamingPattern() {
131 ThreadFactory wrapped = EasyMock.createMock(ThreadFactory.class);
132 Runnable r = EasyMock.createMock(Runnable.class);
133 final int count = 12;
134 for (int i = 0; i < count; i++) {
135 EasyMock.expect(wrapped.newThread(r)).andReturn(new Thread());
136 }
137 EasyMock.replay(wrapped, r);
138 BasicThreadFactory factory = builder.wrappedFactory(wrapped)
139 .namingPattern(PATTERN).build();
140 for (int i = 0; i < count; i++) {
141 Thread t = factory.newThread(r);
142 assertEquals("Wrong thread name", String.format(PATTERN, Long
143 .valueOf(i + 1)), t.getName());
144 assertEquals("Wrong thread count", i + 1, factory.getThreadCount());
145 }
146 EasyMock.verify(wrapped, r);
147 }
148
149 /**
150 * Tests whether the thread name is not modified if no naming pattern is
151 * set.
152 */
153 @Test
154 public void testNewThreadNoNamingPattern() {
155 ThreadFactory wrapped = EasyMock.createMock(ThreadFactory.class);
156 Runnable r = EasyMock.createMock(Runnable.class);
157 final String name = "unchangedThreadName";
158 Thread t = new Thread(name);
159 EasyMock.expect(wrapped.newThread(r)).andReturn(t);
160 EasyMock.replay(wrapped, r);
161 BasicThreadFactory factory = builder.wrappedFactory(wrapped).build();
162 assertSame("Wrong thread", t, factory.newThread(r));
163 assertEquals("Name was changed", name, t.getName());
164 EasyMock.verify(wrapped, r);
165 }
166
167 /**
168 * Helper method for testing whether the daemon flag is taken into account.
169 *
170 * @param flag the value of the flag
171 */
172 private void checkDaemonFlag(boolean flag) {
173 ThreadFactory wrapped = EasyMock.createMock(ThreadFactory.class);
174 Runnable r = EasyMock.createMock(Runnable.class);
175 Thread t = new Thread();
176 EasyMock.expect(wrapped.newThread(r)).andReturn(t);
177 EasyMock.replay(wrapped, r);
178 BasicThreadFactory factory = builder.wrappedFactory(wrapped).daemon(
179 flag).build();
180 assertSame("Wrong thread", t, factory.newThread(r));
181 assertEquals("Wrong daemon flag", flag, t.isDaemon());
182 EasyMock.verify(wrapped, r);
183 }
184
185 /**
186 * Tests whether daemon threads can be created.
187 */
188 @Test
189 public void testNewThreadDaemonTrue() {
190 checkDaemonFlag(true);
191 }
192
193 /**
194 * Tests whether the daemon status of new threads can be turned off.
195 */
196 @Test
197 public void testNewThreadDaemonFalse() {
198 checkDaemonFlag(false);
199 }
200
201 /**
202 * Tests whether the daemon flag is not touched on newly created threads if
203 * it is not specified.
204 */
205 @Test
206 public void testNewThreadNoDaemonFlag() {
207 ThreadFactory wrapped = EasyMock.createMock(ThreadFactory.class);
208 Runnable r1 = EasyMock.createMock(Runnable.class);
209 Runnable r2 = EasyMock.createMock(Runnable.class);
210 Thread t1 = new Thread();
211 Thread t2 = new Thread();
212 t1.setDaemon(true);
213 EasyMock.expect(wrapped.newThread(r1)).andReturn(t1);
214 EasyMock.expect(wrapped.newThread(r2)).andReturn(t2);
215 EasyMock.replay(wrapped, r1, r2);
216 BasicThreadFactory factory = builder.wrappedFactory(wrapped).build();
217 assertSame("Wrong thread 1", t1, factory.newThread(r1));
218 assertTrue("No daemon thread", t1.isDaemon());
219 assertSame("Wrong thread 2", t2, factory.newThread(r2));
220 assertFalse("A daemon thread", t2.isDaemon());
221 EasyMock.verify(wrapped, r1, r2);
222 }
223
224 /**
225 * Tests whether the priority is set on newly created threads.
226 */
227 @Test
228 public void testNewThreadPriority() {
229 ThreadFactory wrapped = EasyMock.createMock(ThreadFactory.class);
230 Runnable r = EasyMock.createMock(Runnable.class);
231 Thread t = new Thread();
232 EasyMock.expect(wrapped.newThread(r)).andReturn(t);
233 EasyMock.replay(wrapped, r);
234 final int priority = Thread.NORM_PRIORITY + 1;
235 BasicThreadFactory factory = builder.wrappedFactory(wrapped).priority(
236 priority).build();
237 assertSame("Wrong thread", t, factory.newThread(r));
238 assertEquals("Wrong priority", priority, t.getPriority());
239 EasyMock.verify(wrapped, r);
240 }
241
242 /**
243 * Tests whether the original priority is not changed if no priority is
244 * specified.
245 */
246 @Test
247 public void testNewThreadNoPriority() {
248 ThreadFactory wrapped = EasyMock.createMock(ThreadFactory.class);
249 Runnable r = EasyMock.createMock(Runnable.class);
250 final int orgPriority = Thread.NORM_PRIORITY + 1;
251 Thread t = new Thread();
252 t.setPriority(orgPriority);
253 EasyMock.expect(wrapped.newThread(r)).andReturn(t);
254 EasyMock.replay(wrapped, r);
255 BasicThreadFactory factory = builder.wrappedFactory(wrapped).build();
256 assertSame("Wrong thread", t, factory.newThread(r));
257 assertEquals("Wrong priority", orgPriority, t.getPriority());
258 EasyMock.verify(wrapped, r);
259 }
260
261 /**
262 * Tests whether the exception handler is set if one is provided.
263 */
264 @Test
265 public void testNewThreadExHandler() {
266 ThreadFactory wrapped = EasyMock.createMock(ThreadFactory.class);
267 Runnable r = EasyMock.createMock(Runnable.class);
268 Thread.UncaughtExceptionHandler handler = EasyMock
269 .createMock(Thread.UncaughtExceptionHandler.class);
270 Thread t = new Thread();
271 EasyMock.expect(wrapped.newThread(r)).andReturn(t);
272 EasyMock.replay(wrapped, r, handler);
273 BasicThreadFactory factory = builder.wrappedFactory(wrapped)
274 .uncaughtExceptionHandler(handler).build();
275 assertSame("Wrong thread", t, factory.newThread(r));
276 assertEquals("Wrong exception handler", handler, t
277 .getUncaughtExceptionHandler());
278 EasyMock.verify(wrapped, r, handler);
279 }
280
281 /**
282 * Tests whether the original exception hander is not touched if none is
283 * specified.
284 */
285 @Test
286 public void testNewThreadNoExHandler() {
287 ThreadFactory wrapped = EasyMock.createMock(ThreadFactory.class);
288 Runnable r = EasyMock.createMock(Runnable.class);
289 Thread.UncaughtExceptionHandler handler = EasyMock
290 .createMock(Thread.UncaughtExceptionHandler.class);
291 Thread t = new Thread();
292 t.setUncaughtExceptionHandler(handler);
293 EasyMock.expect(wrapped.newThread(r)).andReturn(t);
294 EasyMock.replay(wrapped, r, handler);
295 BasicThreadFactory factory = builder.wrappedFactory(wrapped).build();
296 assertSame("Wrong thread", t, factory.newThread(r));
297 assertEquals("Wrong exception handler", handler, t
298 .getUncaughtExceptionHandler());
299 EasyMock.verify(wrapped, r, handler);
300 }
301 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ExecutorService;
20 import java.util.concurrent.Executors;
21
22 import junit.framework.TestCase;
23
24 /**
25 * Test class for {@code CallableBackgroundInitializer}
26 *
27 * @version $Id: CallableBackgroundInitializerTest.java 902960 2010-01-25 19:47:41Z sebb $
28 */
29 public class CallableBackgroundInitializerTest extends TestCase {
30 /** Constant for the result of the call() invocation. */
31 private static final Integer RESULT = Integer.valueOf(42);
32
33 /**
34 * Tries to create an instance without a Callable. This should cause an
35 * exception.
36 */
37 public void testInitNullCallable() {
38 try {
39 new CallableBackgroundInitializer<Object>(null);
40 fail("Could create instance without a Callable!");
41 } catch (IllegalArgumentException iex) {
42 // ok
43 }
44 }
45
46 /**
47 * Tests whether the executor service is correctly passed to the super
48 * class.
49 */
50 public void testInitExecutor() {
51 ExecutorService exec = Executors.newSingleThreadExecutor();
52 CallableBackgroundInitializer<Integer> init = new CallableBackgroundInitializer<Integer>(
53 new TestCallable(), exec);
54 assertEquals("Executor not set", exec, init.getExternalExecutor());
55 }
56
57 /**
58 * Tries to pass a null Callable to the constructor that takes an executor.
59 * This should cause an exception.
60 */
61 public void testInitExecutorNullCallable() {
62 ExecutorService exec = Executors.newSingleThreadExecutor();
63 try {
64 new CallableBackgroundInitializer<Integer>(null, exec);
65 fail("Could create instance without a Callable!");
66 } catch (IllegalArgumentException iex) {
67 // ok
68 }
69 }
70
71 /**
72 * Tests the implementation of initialize().
73 */
74 public void testInitialize() throws Exception {
75 TestCallable call = new TestCallable();
76 CallableBackgroundInitializer<Integer> init = new CallableBackgroundInitializer<Integer>(
77 call);
78 assertEquals("Wrong result", RESULT, init.initialize());
79 assertEquals("Wrong number of invocations", 1, call.callCount);
80 }
81
82 /**
83 * A test Callable implementation for checking the initializer's
84 * implementation of the initialize() method.
85 */
86 private static class TestCallable implements Callable<Integer> {
87 /** A counter for the number of call() invocations. */
88 int callCount;
89
90 /**
91 * Records this invocation and returns the test result.
92 */
93 public Integer call() throws Exception {
94 callCount++;
95 return RESULT;
96 }
97 }
98 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertSame;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.Future;
29 import java.util.concurrent.TimeUnit;
30
31 import org.easymock.EasyMock;
32 import org.junit.Test;
33
34 /**
35 * Test class for {@link ConcurrentUtils}.
36 *
37 * @version $Id: ConcurrentUtilsTest.java 1153484 2011-08-03 13:39:42Z ggregory $
38 */
39 public class ConcurrentUtilsTest {
40 /**
41 * Tests creating a ConcurrentException with a runtime exception as cause.
42 */
43 @Test(expected = IllegalArgumentException.class)
44 public void testConcurrentExceptionCauseUnchecked() {
45 new ConcurrentException(new RuntimeException());
46 }
47
48 /**
49 * Tests creating a ConcurrentException with an error as cause.
50 */
51 @Test(expected = IllegalArgumentException.class)
52 public void testConcurrentExceptionCauseError() {
53 new ConcurrentException("An error", new Error());
54 }
55
56 /**
57 * Tests creating a ConcurrentException with null as cause.
58 */
59 @Test(expected = IllegalArgumentException.class)
60 public void testConcurrentExceptionCauseNull() {
61 new ConcurrentException(null);
62 }
63
64 /**
65 * Tries to create a ConcurrentRuntimeException with a runtime as cause.
66 */
67 @Test(expected = IllegalArgumentException.class)
68 public void testConcurrentRuntimeExceptionCauseUnchecked() {
69 new ConcurrentRuntimeException(new RuntimeException());
70 }
71
72 /**
73 * Tries to create a ConcurrentRuntimeException with an error as cause.
74 */
75 @Test(expected = IllegalArgumentException.class)
76 public void testConcurrentRuntimeExceptionCauseError() {
77 new ConcurrentRuntimeException("An error", new Error());
78 }
79
80 /**
81 * Tries to create a ConcurrentRuntimeException with null as cause.
82 */
83 @Test(expected = IllegalArgumentException.class)
84 public void testConcurrentRuntimeExceptionCauseNull() {
85 new ConcurrentRuntimeException(null);
86 }
87
88 /**
89 * Tests extractCause() for a null exception.
90 */
91 @Test
92 public void testExtractCauseNull() {
93 assertNull("Non null result", ConcurrentUtils.extractCause(null));
94 }
95
96 /**
97 * Tests extractCause() if the cause of the passed in exception is null.
98 */
99 @Test
100 public void testExtractCauseNullCause() {
101 assertNull("Non null result", ConcurrentUtils
102 .extractCause(new ExecutionException("Test", null)));
103 }
104
105 /**
106 * Tests extractCause() if the cause is an error.
107 */
108 @Test
109 public void testExtractCauseError() {
110 Error err = new AssertionError("Test");
111 try {
112 ConcurrentUtils.extractCause(new ExecutionException(err));
113 fail("Error not thrown!");
114 } catch (Error e) {
115 assertEquals("Wrong error", err, e);
116 }
117 }
118
119 /**
120 * Tests extractCause() if the cause is an unchecked exception.
121 */
122 @Test
123 public void testExtractCauseUncheckedException() {
124 RuntimeException rex = new RuntimeException("Test");
125 try {
126 ConcurrentUtils.extractCause(new ExecutionException(rex));
127 fail("Runtime exception not thrown!");
128 } catch (RuntimeException r) {
129 assertEquals("Wrong exception", rex, r);
130 }
131 }
132
133 /**
134 * Tests extractCause() if the cause is a checked exception.
135 */
136 @Test
137 public void testExtractCauseChecked() {
138 Exception ex = new Exception("Test");
139 ConcurrentException cex = ConcurrentUtils
140 .extractCause(new ExecutionException(ex));
141 assertSame("Wrong cause", ex, cex.getCause());
142 }
143
144 /**
145 * Tests extractCauseUnchecked() for a null exception.
146 */
147 @Test
148 public void testExtractCauseUncheckedNull() {
149 assertNull("Non null result", ConcurrentUtils.extractCauseUnchecked(null));
150 }
151
152 /**
153 * Tests extractCauseUnchecked() if the cause of the passed in exception is null.
154 */
155 @Test
156 public void testExtractCauseUncheckedNullCause() {
157 assertNull("Non null result", ConcurrentUtils
158 .extractCauseUnchecked(new ExecutionException("Test", null)));
159 }
160
161 /**
162 * Tests extractCauseUnchecked() if the cause is an error.
163 */
164 @Test
165 public void testExtractCauseUncheckedError() {
166 Error err = new AssertionError("Test");
167 try {
168 ConcurrentUtils.extractCauseUnchecked(new ExecutionException(err));
169 fail("Error not thrown!");
170 } catch (Error e) {
171 assertEquals("Wrong error", err, e);
172 }
173 }
174
175 /**
176 * Tests extractCauseUnchecked() if the cause is an unchecked exception.
177 */
178 @Test
179 public void testExtractCauseUncheckedUncheckedException() {
180 RuntimeException rex = new RuntimeException("Test");
181 try {
182 ConcurrentUtils.extractCauseUnchecked(new ExecutionException(rex));
183 fail("Runtime exception not thrown!");
184 } catch (RuntimeException r) {
185 assertEquals("Wrong exception", rex, r);
186 }
187 }
188
189 /**
190 * Tests extractCauseUnchecked() if the cause is a checked exception.
191 */
192 @Test
193 public void testExtractCauseUncheckedChecked() {
194 Exception ex = new Exception("Test");
195 ConcurrentRuntimeException cex = ConcurrentUtils
196 .extractCauseUnchecked(new ExecutionException(ex));
197 assertSame("Wrong cause", ex, cex.getCause());
198 }
199
200 /**
201 * Tests handleCause() if the cause is an error.
202 */
203 @Test
204 public void testHandleCauseError() throws ConcurrentException {
205 Error err = new AssertionError("Test");
206 try {
207 ConcurrentUtils.handleCause(new ExecutionException(err));
208 fail("Error not thrown!");
209 } catch (Error e) {
210 assertEquals("Wrong error", err, e);
211 }
212 }
213
214 /**
215 * Tests handleCause() if the cause is an unchecked exception.
216 */
217 @Test
218 public void testHandleCauseUncheckedException() throws ConcurrentException {
219 RuntimeException rex = new RuntimeException("Test");
220 try {
221 ConcurrentUtils.handleCause(new ExecutionException(rex));
222 fail("Runtime exception not thrown!");
223 } catch (RuntimeException r) {
224 assertEquals("Wrong exception", rex, r);
225 }
226 }
227
228 /**
229 * Tests handleCause() if the cause is a checked exception.
230 */
231 @Test
232 public void testHandleCauseChecked() {
233 Exception ex = new Exception("Test");
234 try {
235 ConcurrentUtils.handleCause(new ExecutionException(ex));
236 fail("ConcurrentException not thrown!");
237 } catch (ConcurrentException cex) {
238 assertEquals("Wrong cause", ex, cex.getCause());
239 }
240 }
241
242 /**
243 * Tests handleCause() for a null parameter or a null cause. In this case
244 * the method should do nothing. We can only test that no exception is
245 * thrown.
246 */
247 @Test
248 public void testHandleCauseNull() throws ConcurrentException {
249 ConcurrentUtils.handleCause(null);
250 ConcurrentUtils.handleCause(new ExecutionException("Test", null));
251 }
252
253 /**
254 * Tests handleCauseUnchecked() if the cause is an error.
255 */
256 @Test
257 public void testHandleCauseUncheckedError() {
258 Error err = new AssertionError("Test");
259 try {
260 ConcurrentUtils.handleCauseUnchecked(new ExecutionException(err));
261 fail("Error not thrown!");
262 } catch (Error e) {
263 assertEquals("Wrong error", err, e);
264 }
265 }
266
267 /**
268 * Tests handleCauseUnchecked() if the cause is an unchecked exception.
269 */
270 @Test
271 public void testHandleCauseUncheckedUncheckedException() {
272 RuntimeException rex = new RuntimeException("Test");
273 try {
274 ConcurrentUtils.handleCauseUnchecked(new ExecutionException(rex));
275 fail("Runtime exception not thrown!");
276 } catch (RuntimeException r) {
277 assertEquals("Wrong exception", rex, r);
278 }
279 }
280
281 /**
282 * Tests handleCauseUnchecked() if the cause is a checked exception.
283 */
284 @Test
285 public void testHandleCauseUncheckedChecked() {
286 Exception ex = new Exception("Test");
287 try {
288 ConcurrentUtils.handleCauseUnchecked(new ExecutionException(ex));
289 fail("ConcurrentRuntimeException not thrown!");
290 } catch (ConcurrentRuntimeException crex) {
291 assertEquals("Wrong cause", ex, crex.getCause());
292 }
293 }
294
295 /**
296 * Tests handleCauseUnchecked() for a null parameter or a null cause. In
297 * this case the method should do nothing. We can only test that no
298 * exception is thrown.
299 */
300 @Test
301 public void testHandleCauseUncheckedNull() {
302 ConcurrentUtils.handleCauseUnchecked(null);
303 ConcurrentUtils.handleCauseUnchecked(new ExecutionException("Test",
304 null));
305 }
306
307 //-----------------------------------------------------------------------
308 /**
309 * Tests initialize() for a null argument.
310 */
311 @Test
312 public void testInitializeNull() throws ConcurrentException {
313 assertNull("Got a result", ConcurrentUtils.initialize(null));
314 }
315
316 /**
317 * Tests a successful initialize() operation.
318 */
319 @Test
320 public void testInitialize() throws ConcurrentException {
321 @SuppressWarnings("unchecked")
322 ConcurrentInitializer<Object> init = EasyMock
323 .createMock(ConcurrentInitializer.class);
324 final Object result = new Object();
325 EasyMock.expect(init.get()).andReturn(result);
326 EasyMock.replay(init);
327 assertSame("Wrong result object", result, ConcurrentUtils
328 .initialize(init));
329 EasyMock.verify(init);
330 }
331
332 /**
333 * Tests initializeUnchecked() for a null argument.
334 */
335 @Test
336 public void testInitializeUncheckedNull() {
337 assertNull("Got a result", ConcurrentUtils.initializeUnchecked(null));
338 }
339
340 /**
341 * Tests a successful initializeUnchecked() operation.
342 */
343 @Test
344 public void testInitializeUnchecked() throws ConcurrentException {
345 @SuppressWarnings("unchecked")
346 ConcurrentInitializer<Object> init = EasyMock
347 .createMock(ConcurrentInitializer.class);
348 final Object result = new Object();
349 EasyMock.expect(init.get()).andReturn(result);
350 EasyMock.replay(init);
351 assertSame("Wrong result object", result, ConcurrentUtils
352 .initializeUnchecked(init));
353 EasyMock.verify(init);
354 }
355
356 /**
357 * Tests whether exceptions are correctly handled by initializeUnchecked().
358 */
359 @Test
360 public void testInitializeUncheckedEx() throws ConcurrentException {
361 @SuppressWarnings("unchecked")
362 ConcurrentInitializer<Object> init = EasyMock
363 .createMock(ConcurrentInitializer.class);
364 final Exception cause = new Exception();
365 EasyMock.expect(init.get()).andThrow(new ConcurrentException(cause));
366 EasyMock.replay(init);
367 try {
368 ConcurrentUtils.initializeUnchecked(init);
369 fail("Exception not thrown!");
370 } catch (ConcurrentRuntimeException crex) {
371 assertSame("Wrong cause", cause, crex.getCause());
372 }
373 EasyMock.verify(init);
374 }
375
376 //-----------------------------------------------------------------------
377 /**
378 * Tests constant future.
379 */
380 @Test
381 public void testConstantFuture_Integer() throws Exception {
382 Integer value = Integer.valueOf(5);
383 Future<Integer> test = ConcurrentUtils.constantFuture(value);
384 assertTrue(test.isDone());
385 assertSame(value, test.get());
386 assertSame(value, test.get(1000, TimeUnit.SECONDS));
387 assertSame(value, test.get(1000, null));
388 assertFalse(test.isCancelled());
389 assertFalse(test.cancel(true));
390 assertFalse(test.cancel(false));
391 }
392
393 /**
394 * Tests constant future.
395 */
396 @Test
397 public void testConstantFuture_null() throws Exception {
398 Integer value = null;
399 Future<Integer> test = ConcurrentUtils.constantFuture(value);
400 assertTrue(test.isDone());
401 assertSame(value, test.get());
402 assertSame(value, test.get(1000, TimeUnit.SECONDS));
403 assertSame(value, test.get(1000, null));
404 assertFalse(test.isCancelled());
405 assertFalse(test.cancel(true));
406 assertFalse(test.cancel(false));
407 }
408
409 //-----------------------------------------------------------------------
410 /**
411 * Tests putIfAbsent() if the map contains the key in question.
412 */
413 @Test
414 public void testPutIfAbsentKeyPresent() {
415 final String key = "testKey";
416 final Integer value = 42;
417 ConcurrentMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
418 map.put(key, value);
419 assertEquals("Wrong result", value,
420 ConcurrentUtils.putIfAbsent(map, key, 0));
421 assertEquals("Wrong value in map", value, map.get(key));
422 }
423
424 /**
425 * Tests putIfAbsent() if the map does not contain the key in question.
426 */
427 @Test
428 public void testPutIfAbsentKeyNotPresent() {
429 final String key = "testKey";
430 final Integer value = 42;
431 ConcurrentMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
432 assertEquals("Wrong result", value,
433 ConcurrentUtils.putIfAbsent(map, key, value));
434 assertEquals("Wrong value in map", value, map.get(key));
435 }
436
437 /**
438 * Tests putIfAbsent() if a null map is passed in.
439 */
440 @Test
441 public void testPutIfAbsentNullMap() {
442 assertNull("Wrong result",
443 ConcurrentUtils.putIfAbsent(null, "test", 100));
444 }
445
446 /**
447 * Tests createIfAbsent() if the key is found in the map.
448 */
449 @Test
450 public void testCreateIfAbsentKeyPresent() throws ConcurrentException {
451 @SuppressWarnings("unchecked")
452 ConcurrentInitializer<Integer> init = EasyMock
453 .createMock(ConcurrentInitializer.class);
454 EasyMock.replay(init);
455 final String key = "testKey";
456 final Integer value = 42;
457 ConcurrentMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
458 map.put(key, value);
459 assertEquals("Wrong result", value,
460 ConcurrentUtils.createIfAbsent(map, key, init));
461 assertEquals("Wrong value in map", value, map.get(key));
462 EasyMock.verify(init);
463 }
464
465 /**
466 * Tests createIfAbsent() if the map does not contain the key in question.
467 */
468 @Test
469 public void testCreateIfAbsentKeyNotPresent() throws ConcurrentException {
470 @SuppressWarnings("unchecked")
471 ConcurrentInitializer<Integer> init = EasyMock
472 .createMock(ConcurrentInitializer.class);
473 final String key = "testKey";
474 final Integer value = 42;
475 EasyMock.expect(init.get()).andReturn(value);
476 EasyMock.replay(init);
477 ConcurrentMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
478 assertEquals("Wrong result", value,
479 ConcurrentUtils.createIfAbsent(map, key, init));
480 assertEquals("Wrong value in map", value, map.get(key));
481 EasyMock.verify(init);
482 }
483
484 /**
485 * Tests createIfAbsent() if a null map is passed in.
486 */
487 @Test
488 public void testCreateIfAbsentNullMap() throws ConcurrentException {
489 @SuppressWarnings("unchecked")
490 ConcurrentInitializer<Integer> init = EasyMock
491 .createMock(ConcurrentInitializer.class);
492 EasyMock.replay(init);
493 assertNull("Wrong result",
494 ConcurrentUtils.createIfAbsent(null, "test", init));
495 EasyMock.verify(init);
496 }
497
498 /**
499 * Tests createIfAbsent() if a null initializer is passed in.
500 */
501 @Test
502 public void testCreateIfAbsentNullInit() throws ConcurrentException {
503 ConcurrentMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
504 final String key = "testKey";
505 final Integer value = 42;
506 map.put(key, value);
507 assertNull("Wrong result",
508 ConcurrentUtils.createIfAbsent(map, key, null));
509 assertEquals("Map was changed", value, map.get(key));
510 }
511
512 /**
513 * Tests createIfAbsentUnchecked() if no exception is thrown.
514 */
515 @Test
516 public void testCreateIfAbsentUncheckedSuccess() {
517 final String key = "testKey";
518 final Integer value = 42;
519 ConcurrentMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
520 assertEquals("Wrong result", value,
521 ConcurrentUtils.createIfAbsentUnchecked(map, key,
522 new ConstantInitializer<Integer>(value)));
523 assertEquals("Wrong value in map", value, map.get(key));
524 }
525
526 /**
527 * Tests createIfAbsentUnchecked() if an exception is thrown.
528 */
529 @Test
530 public void testCreateIfAbsentUncheckedException()
531 throws ConcurrentException {
532 @SuppressWarnings("unchecked")
533 ConcurrentInitializer<Integer> init = EasyMock
534 .createMock(ConcurrentInitializer.class);
535 Exception ex = new Exception();
536 EasyMock.expect(init.get()).andThrow(new ConcurrentException(ex));
537 EasyMock.replay(init);
538 try {
539 ConcurrentUtils.createIfAbsentUnchecked(
540 new ConcurrentHashMap<String, Integer>(), "test", init);
541 fail("Exception not thrown!");
542 } catch (ConcurrentRuntimeException crex) {
543 assertEquals("Wrong cause", ex, crex.getCause());
544 }
545 EasyMock.verify(init);
546 }
547 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertTrue;
20
21 import java.util.regex.Pattern;
22
23 import org.junit.Before;
24 import org.junit.Test;
25
26 /**
27 * Test class for {@code ConstantInitializer}.
28 *
29 * @version $Id: ConstantInitializerTest.java 1153484 2011-08-03 13:39:42Z ggregory $
30 */
31 public class ConstantInitializerTest {
32 /** Constant for the object managed by the initializer. */
33 private static final Integer VALUE = 42;
34
35 /** The initializer to be tested. */
36 private ConstantInitializer<Integer> init;
37
38 @Before
39 public void setUp() throws Exception {
40 init = new ConstantInitializer<Integer>(VALUE);
41 }
42
43 /**
44 * Helper method for testing equals() and hashCode().
45 *
46 * @param obj the object to compare with the test instance
47 * @param expected the expected result
48 */
49 private void checkEquals(Object obj, boolean expected) {
50 assertEquals("Wrong result of equals", expected, init.equals(obj));
51 if (obj != null) {
52 assertEquals("Not symmetric", expected, obj.equals(init));
53 if (expected) {
54 assertEquals("Different hash codes", init.hashCode(),
55 obj.hashCode());
56 }
57 }
58 }
59
60 /**
61 * Tests whether the correct object is returned.
62 */
63 @Test
64 public void testGetObject() {
65 assertEquals("Wrong object", VALUE, init.getObject());
66 }
67
68 /**
69 * Tests whether get() returns the correct object.
70 */
71 @Test
72 public void testGet() throws ConcurrentException {
73 assertEquals("Wrong object", VALUE, init.get());
74 }
75
76 /**
77 * Tests equals() if the expected result is true.
78 */
79 @Test
80 public void testEqualsTrue() {
81 checkEquals(init, true);
82 ConstantInitializer<Integer> init2 = new ConstantInitializer<Integer>(
83 Integer.valueOf(VALUE.intValue()));
84 checkEquals(init2, true);
85 init = new ConstantInitializer<Integer>(null);
86 init2 = new ConstantInitializer<Integer>(null);
87 checkEquals(init2, true);
88 }
89
90 /**
91 * Tests equals() if the expected result is false.
92 */
93 @Test
94 public void testEqualsFalse() {
95 ConstantInitializer<Integer> init2 = new ConstantInitializer<Integer>(
96 null);
97 checkEquals(init2, false);
98 init2 = new ConstantInitializer<Integer>(VALUE + 1);
99 checkEquals(init2, false);
100 }
101
102 /**
103 * Tests equals() with objects of other classes.
104 */
105 @Test
106 public void testEqualsWithOtherObjects() {
107 checkEquals(null, false);
108 checkEquals(this, false);
109 checkEquals(new ConstantInitializer<String>("Test"), false);
110 }
111
112 /**
113 * Tests the string representation.
114 */
115 @Test
116 public void testToString() {
117 String s = init.toString();
118 Pattern pattern = Pattern
119 .compile("ConstantInitializer@\\d+ \\[ object = " + VALUE
120 + " \\]");
121 assertTrue("Wrong string: " + s, pattern.matcher(s).matches());
122 }
123
124 /**
125 * Tests the string representation if the managed object is null.
126 */
127 @Test
128 public void testToStringNull() {
129 String s = new ConstantInitializer<Object>(null).toString();
130 assertTrue("Object not found: " + s, s.indexOf("object = null") > 0);
131 }
132 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import org.junit.Before;
19
20 /**
21 * Test class for {@code LazyInitializer}.
22 *
23 * @version $Id: LazyInitializerTest.java 929189 2010-03-30 16:49:22Z oheger $
24 */
25 public class LazyInitializerTest extends AbstractConcurrentInitializerTest {
26 /** The initializer to be tested. */
27 private LazyInitializerTestImpl initializer;
28
29 @Before
30 public void setUp() throws Exception {
31 initializer = new LazyInitializerTestImpl();
32 }
33
34 /**
35 * Returns the initializer to be tested. This implementation returns the
36 * {@code LazyInitializer} created in the {@code setUp()} method.
37 *
38 * @return the initializer to be tested
39 */
40 @Override
41 protected ConcurrentInitializer<Object> createInitializer() {
42 return initializer;
43 }
44
45 /**
46 * A test implementation of LazyInitializer. This class creates a plain
47 * Object. As Object does not provide a specific equals() method, it is easy
48 * to check whether multiple instances were created.
49 */
50 private static class LazyInitializerTestImpl extends
51 LazyInitializer<Object> {
52 @Override
53 protected Object initialize() {
54 return new Object();
55 }
56 }
57 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23
24 import java.util.Iterator;
25 import java.util.NoSuchElementException;
26 import java.util.concurrent.ExecutorService;
27 import java.util.concurrent.Executors;
28
29 import org.junit.Before;
30 import org.junit.Test;
31
32 /**
33 * Test class for {@link MultiBackgroundInitializer}.
34 *
35 * @version $Id: MultiBackgroundInitializerTest.java 987621 2010-08-20 20:01:10Z oheger $
36 */
37 public class MultiBackgroundInitializerTest {
38 /** Constant for the names of the child initializers. */
39 private static final String CHILD_INIT = "childInitializer";
40
41 /** The initializer to be tested. */
42 private MultiBackgroundInitializer initializer;
43
44 @Before
45 public void setUp() throws Exception {
46 initializer = new MultiBackgroundInitializer();
47 }
48
49 /**
50 * Tests whether a child initializer has been executed. Optionally the
51 * expected executor service can be checked, too.
52 *
53 * @param child the child initializer
54 * @param expExec the expected executor service (null if the executor should
55 * not be checked)
56 * @throws ConcurrentException if an error occurs
57 */
58 private void checkChild(BackgroundInitializer<?> child,
59 ExecutorService expExec) throws ConcurrentException {
60 ChildBackgroundInitializer cinit = (ChildBackgroundInitializer) child;
61 Integer result = cinit.get();
62 assertEquals("Wrong result", 1, result.intValue());
63 assertEquals("Wrong number of executions", 1, cinit.initializeCalls);
64 if (expExec != null) {
65 assertEquals("Wrong executor service", expExec,
66 cinit.currentExecutor);
67 }
68 }
69
70 /**
71 * Tests addInitializer() if a null name is passed in. This should cause an
72 * exception.
73 */
74 @Test(expected = IllegalArgumentException.class)
75 public void testAddInitializerNullName() {
76 initializer.addInitializer(null, new ChildBackgroundInitializer());
77 }
78
79 /**
80 * Tests addInitializer() if a null initializer is passed in. This should
81 * cause an exception.
82 */
83 @Test(expected = IllegalArgumentException.class)
84 public void testAddInitializerNullInit() {
85 initializer.addInitializer(CHILD_INIT, null);
86 }
87
88 /**
89 * Tests the background processing if there are no child initializers.
90 */
91 @Test
92 public void testInitializeNoChildren() throws ConcurrentException {
93 assertTrue("Wrong result of start()", initializer.start());
94 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = initializer
95 .get();
96 assertTrue("Got child initializers", res.initializerNames().isEmpty());
97 assertTrue("Executor not shutdown", initializer.getActiveExecutor()
98 .isShutdown());
99 }
100
101 /**
102 * Helper method for testing the initialize() method. This method can
103 * operate with both an external and a temporary executor service.
104 *
105 * @return the result object produced by the initializer
106 */
107 private MultiBackgroundInitializer.MultiBackgroundInitializerResults checkInitialize()
108 throws ConcurrentException {
109 final int count = 5;
110 for (int i = 0; i < count; i++) {
111 initializer.addInitializer(CHILD_INIT + i,
112 new ChildBackgroundInitializer());
113 }
114 initializer.start();
115 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = initializer
116 .get();
117 assertEquals("Wrong number of child initializers", count, res
118 .initializerNames().size());
119 for (int i = 0; i < count; i++) {
120 String key = CHILD_INIT + i;
121 assertTrue("Name not found: " + key, res.initializerNames()
122 .contains(key));
123 assertEquals("Wrong result object", Integer.valueOf(1), res
124 .getResultObject(key));
125 assertFalse("Exception flag", res.isException(key));
126 assertNull("Got an exception", res.getException(key));
127 checkChild(res.getInitializer(key), initializer.getActiveExecutor());
128 }
129 return res;
130 }
131
132 /**
133 * Tests background processing if a temporary executor is used.
134 */
135 @Test
136 public void testInitializeTempExec() throws ConcurrentException {
137 checkInitialize();
138 assertTrue("Executor not shutdown", initializer.getActiveExecutor()
139 .isShutdown());
140 }
141
142 /**
143 * Tests background processing if an external executor service is provided.
144 */
145 @Test
146 public void testInitializeExternalExec() throws ConcurrentException {
147 ExecutorService exec = Executors.newCachedThreadPool();
148 try {
149 initializer = new MultiBackgroundInitializer(exec);
150 checkInitialize();
151 assertEquals("Wrong executor", exec, initializer
152 .getActiveExecutor());
153 assertFalse("Executor was shutdown", exec.isShutdown());
154 } finally {
155 exec.shutdown();
156 }
157 }
158
159 /**
160 * Tests the behavior of initialize() if a child initializer has a specific
161 * executor service. Then this service should not be overridden.
162 */
163 @Test
164 public void testInitializeChildWithExecutor() throws ConcurrentException {
165 final String initExec = "childInitializerWithExecutor";
166 ExecutorService exec = Executors.newSingleThreadExecutor();
167 try {
168 ChildBackgroundInitializer c1 = new ChildBackgroundInitializer();
169 ChildBackgroundInitializer c2 = new ChildBackgroundInitializer();
170 c2.setExternalExecutor(exec);
171 initializer.addInitializer(CHILD_INIT, c1);
172 initializer.addInitializer(initExec, c2);
173 initializer.start();
174 initializer.get();
175 checkChild(c1, initializer.getActiveExecutor());
176 checkChild(c2, exec);
177 } finally {
178 exec.shutdown();
179 }
180 }
181
182 /**
183 * Tries to add another child initializer after the start() method has been
184 * called. This should not be allowed.
185 */
186 @Test
187 public void testAddInitializerAfterStart() throws ConcurrentException {
188 initializer.start();
189 try {
190 initializer.addInitializer(CHILD_INIT,
191 new ChildBackgroundInitializer());
192 fail("Could add initializer after start()!");
193 } catch (IllegalStateException istex) {
194 initializer.get();
195 }
196 }
197
198 /**
199 * Tries to query an unknown child initializer from the results object. This
200 * should cause an exception.
201 */
202 @Test(expected = NoSuchElementException.class)
203 public void testResultGetInitializerUnknown() throws ConcurrentException {
204 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = checkInitialize();
205 res.getInitializer("unknown");
206 }
207
208 /**
209 * Tries to query the results of an unknown child initializer from the
210 * results object. This should cause an exception.
211 */
212 @Test(expected = NoSuchElementException.class)
213 public void testResultGetResultObjectUnknown() throws ConcurrentException {
214 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = checkInitialize();
215 res.getResultObject("unknown");
216 }
217
218 /**
219 * Tries to query the exception of an unknown child initializer from the
220 * results object. This should cause an exception.
221 */
222 @Test(expected = NoSuchElementException.class)
223 public void testResultGetExceptionUnknown() throws ConcurrentException {
224 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = checkInitialize();
225 res.getException("unknown");
226 }
227
228 /**
229 * Tries to query the exception flag of an unknown child initializer from
230 * the results object. This should cause an exception.
231 */
232 @Test(expected = NoSuchElementException.class)
233 public void testResultIsExceptionUnknown() throws ConcurrentException {
234 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = checkInitialize();
235 res.isException("unknown");
236 }
237
238 /**
239 * Tests that the set with the names of the initializers cannot be modified.
240 */
241 @Test(expected = UnsupportedOperationException.class)
242 public void testResultInitializerNamesModify() throws ConcurrentException {
243 checkInitialize();
244 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = initializer
245 .get();
246 Iterator<String> it = res.initializerNames().iterator();
247 it.next();
248 it.remove();
249 }
250
251 /**
252 * Tests the behavior of the initializer if one of the child initializers
253 * throws a runtime exception.
254 */
255 @Test
256 public void testInitializeRuntimeEx() {
257 ChildBackgroundInitializer child = new ChildBackgroundInitializer();
258 child.ex = new RuntimeException();
259 initializer.addInitializer(CHILD_INIT, child);
260 initializer.start();
261 try {
262 initializer.get();
263 fail("Runtime exception not thrown!");
264 } catch (Exception ex) {
265 assertEquals("Wrong exception", child.ex, ex);
266 }
267 }
268
269 /**
270 * Tests the behavior of the initializer if one of the child initializers
271 * throws a checked exception.
272 */
273 @Test
274 public void testInitializeEx() throws ConcurrentException {
275 ChildBackgroundInitializer child = new ChildBackgroundInitializer();
276 child.ex = new Exception();
277 initializer.addInitializer(CHILD_INIT, child);
278 initializer.start();
279 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = initializer
280 .get();
281 assertTrue("No exception flag", res.isException(CHILD_INIT));
282 assertNull("Got a results object", res.getResultObject(CHILD_INIT));
283 ConcurrentException cex = res.getException(CHILD_INIT);
284 assertEquals("Wrong cause", child.ex, cex.getCause());
285 }
286
287 /**
288 * Tests the isSuccessful() method of the result object if no child
289 * initializer has thrown an exception.
290 */
291 @Test
292 public void testInitializeResultsIsSuccessfulTrue()
293 throws ConcurrentException {
294 ChildBackgroundInitializer child = new ChildBackgroundInitializer();
295 initializer.addInitializer(CHILD_INIT, child);
296 initializer.start();
297 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = initializer
298 .get();
299 assertTrue("Wrong success flag", res.isSuccessful());
300 }
301
302 /**
303 * Tests the isSuccessful() method of the result object if at least one
304 * child initializer has thrown an exception.
305 */
306 @Test
307 public void testInitializeResultsIsSuccessfulFalse()
308 throws ConcurrentException {
309 ChildBackgroundInitializer child = new ChildBackgroundInitializer();
310 child.ex = new Exception();
311 initializer.addInitializer(CHILD_INIT, child);
312 initializer.start();
313 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = initializer
314 .get();
315 assertFalse("Wrong success flag", res.isSuccessful());
316 }
317
318 /**
319 * Tests whether MultiBackgroundInitializers can be combined in a nested
320 * way.
321 */
322 @Test
323 public void testInitializeNested() throws ConcurrentException {
324 final String nameMulti = "multiChildInitializer";
325 initializer
326 .addInitializer(CHILD_INIT, new ChildBackgroundInitializer());
327 MultiBackgroundInitializer mi2 = new MultiBackgroundInitializer();
328 final int count = 3;
329 for (int i = 0; i < count; i++) {
330 mi2
331 .addInitializer(CHILD_INIT + i,
332 new ChildBackgroundInitializer());
333 }
334 initializer.addInitializer(nameMulti, mi2);
335 initializer.start();
336 MultiBackgroundInitializer.MultiBackgroundInitializerResults res = initializer
337 .get();
338 ExecutorService exec = initializer.getActiveExecutor();
339 checkChild(res.getInitializer(CHILD_INIT), exec);
340 MultiBackgroundInitializer.MultiBackgroundInitializerResults res2 = (MultiBackgroundInitializer.MultiBackgroundInitializerResults) res
341 .getResultObject(nameMulti);
342 assertEquals("Wrong number of initializers", count, res2
343 .initializerNames().size());
344 for (int i = 0; i < count; i++) {
345 checkChild(res2.getInitializer(CHILD_INIT + i), exec);
346 }
347 assertTrue("Executor not shutdown", exec.isShutdown());
348 }
349
350 /**
351 * A concrete implementation of {@code BackgroundInitializer} used for
352 * defining background tasks for {@code MultiBackgroundInitializer}.
353 */
354 private static class ChildBackgroundInitializer extends
355 BackgroundInitializer<Integer> {
356 /** Stores the current executor service. */
357 volatile ExecutorService currentExecutor;
358
359 /** A counter for the invocations of initialize(). */
360 volatile int initializeCalls;
361
362 /** An exception to be thrown by initialize(). */
363 Exception ex;
364
365 /**
366 * Records this invocation. Optionally throws an exception.
367 */
368 @Override
369 protected Integer initialize() throws Exception {
370 currentExecutor = getActiveExecutor();
371 initializeCalls++;
372
373 if (ex != null) {
374 throw ex;
375 }
376
377 return initializeCalls;
378 }
379 }
380 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.concurrent;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23
24 import java.util.concurrent.CountDownLatch;
25 import java.util.concurrent.ScheduledExecutorService;
26 import java.util.concurrent.ScheduledFuture;
27 import java.util.concurrent.ScheduledThreadPoolExecutor;
28 import java.util.concurrent.TimeUnit;
29
30 import org.easymock.EasyMock;
31 import org.junit.Test;
32
33 /**
34 * Test class for TimedSemaphore.
35 *
36 * @version $Id: TimedSemaphoreTest.java 1022749 2010-10-14 22:49:55Z ggregory $
37 */
38 public class TimedSemaphoreTest {
39 /** Constant for the time period. */
40 private static final long PERIOD = 500;
41
42 /** Constant for the time unit. */
43 private static final TimeUnit UNIT = TimeUnit.MILLISECONDS;
44
45 /** Constant for the default limit. */
46 private static final int LIMIT = 10;
47
48 /**
49 * Tests creating a new instance.
50 */
51 @Test
52 public void testInit() {
53 ScheduledExecutorService service = EasyMock
54 .createMock(ScheduledExecutorService.class);
55 EasyMock.replay(service);
56 TimedSemaphore semaphore = new TimedSemaphore(service, PERIOD, UNIT,
57 LIMIT);
58 EasyMock.verify(service);
59 assertEquals("Wrong service", service, semaphore.getExecutorService());
60 assertEquals("Wrong period", PERIOD, semaphore.getPeriod());
61 assertEquals("Wrong unit", UNIT, semaphore.getUnit());
62 assertEquals("Statistic available", 0, semaphore
63 .getLastAcquiresPerPeriod());
64 assertEquals("Average available", 0.0, semaphore
65 .getAverageCallsPerPeriod(), .05);
66 assertFalse("Already shutdown", semaphore.isShutdown());
67 assertEquals("Wrong limit", LIMIT, semaphore.getLimit());
68 }
69
70 /**
71 * Tries to create an instance with a negative period. This should cause an
72 * exception.
73 */
74 @Test(expected = IllegalArgumentException.class)
75 public void testInitInvalidPeriod() {
76 new TimedSemaphore(0L, UNIT, LIMIT);
77 }
78
79 /**
80 * Tests whether a default executor service is created if no service is
81 * provided.
82 */
83 @Test
84 public void testInitDefaultService() {
85 TimedSemaphore semaphore = new TimedSemaphore(PERIOD, UNIT, LIMIT);
86 ScheduledThreadPoolExecutor exec = (ScheduledThreadPoolExecutor) semaphore
87 .getExecutorService();
88 assertFalse("Wrong periodic task policy", exec
89 .getContinueExistingPeriodicTasksAfterShutdownPolicy());
90 assertFalse("Wrong delayed task policy", exec
91 .getExecuteExistingDelayedTasksAfterShutdownPolicy());
92 assertFalse("Already shutdown", exec.isShutdown());
93 semaphore.shutdown();
94 }
95
96 /**
97 * Tests starting the timer.
98 */
99 @Test
100 public void testStartTimer() throws InterruptedException {
101 TimedSemaphoreTestImpl semaphore = new TimedSemaphoreTestImpl(PERIOD,
102 UNIT, LIMIT);
103 ScheduledFuture<?> future = semaphore.startTimer();
104 assertNotNull("No future returned", future);
105 Thread.sleep(PERIOD);
106 final int trials = 10;
107 int count = 0;
108 do {
109 Thread.sleep(PERIOD);
110 if (count++ > trials) {
111 fail("endOfPeriod() not called!");
112 }
113 } while (semaphore.getPeriodEnds() <= 0);
114 semaphore.shutdown();
115 }
116
117 /**
118 * Tests the shutdown() method if the executor belongs to the semaphore. In
119 * this case it has to be shut down.
120 */
121 @Test
122 public void testShutdownOwnExecutor() {
123 TimedSemaphore semaphore = new TimedSemaphore(PERIOD, UNIT, LIMIT);
124 semaphore.shutdown();
125 assertTrue("Not shutdown", semaphore.isShutdown());
126 assertTrue("Executor not shutdown", semaphore.getExecutorService()
127 .isShutdown());
128 }
129
130 /**
131 * Tests the shutdown() method for a shared executor service before a task
132 * was started. This should do pretty much nothing.
133 */
134 @Test
135 public void testShutdownSharedExecutorNoTask() {
136 ScheduledExecutorService service = EasyMock
137 .createMock(ScheduledExecutorService.class);
138 EasyMock.replay(service);
139 TimedSemaphore semaphore = new TimedSemaphore(service, PERIOD, UNIT,
140 LIMIT);
141 semaphore.shutdown();
142 assertTrue("Not shutdown", semaphore.isShutdown());
143 EasyMock.verify(service);
144 }
145
146 /**
147 * Prepares an executor service mock to expect the start of the timer.
148 *
149 * @param service the mock
150 * @param future the future
151 */
152 private void prepareStartTimer(ScheduledExecutorService service,
153 ScheduledFuture<?> future) {
154 service.scheduleAtFixedRate((Runnable) EasyMock.anyObject(), EasyMock
155 .eq(PERIOD), EasyMock.eq(PERIOD), EasyMock.eq(UNIT));
156 EasyMock.expectLastCall().andReturn(future);
157 }
158
159 /**
160 * Tests the shutdown() method for a shared executor after the task was
161 * started. In this case the task must be canceled.
162 */
163 @Test
164 public void testShutdownSharedExecutorTask() throws InterruptedException {
165 ScheduledExecutorService service = EasyMock
166 .createMock(ScheduledExecutorService.class);
167 ScheduledFuture<?> future = EasyMock.createMock(ScheduledFuture.class);
168 prepareStartTimer(service, future);
169 EasyMock.expect(Boolean.valueOf(future.cancel(false))).andReturn(Boolean.TRUE);
170 EasyMock.replay(service, future);
171 TimedSemaphoreTestImpl semaphore = new TimedSemaphoreTestImpl(service,
172 PERIOD, UNIT, LIMIT);
173 semaphore.acquire();
174 semaphore.shutdown();
175 assertTrue("Not shutdown", semaphore.isShutdown());
176 EasyMock.verify(service, future);
177 }
178
179 /**
180 * Tests multiple invocations of the shutdown() method.
181 */
182 @Test
183 public void testShutdownMultipleTimes() throws InterruptedException {
184 ScheduledExecutorService service = EasyMock
185 .createMock(ScheduledExecutorService.class);
186 ScheduledFuture<?> future = EasyMock.createMock(ScheduledFuture.class);
187 prepareStartTimer(service, future);
188 EasyMock.expect(Boolean.valueOf(future.cancel(false))).andReturn(Boolean.TRUE);
189 EasyMock.replay(service, future);
190 TimedSemaphoreTestImpl semaphore = new TimedSemaphoreTestImpl(service,
191 PERIOD, UNIT, LIMIT);
192 semaphore.acquire();
193 for (int i = 0; i < 10; i++) {
194 semaphore.shutdown();
195 }
196 EasyMock.verify(service, future);
197 }
198
199 /**
200 * Tests the acquire() method if a limit is set.
201 */
202 @Test
203 public void testAcquireLimit() throws InterruptedException {
204 ScheduledExecutorService service = EasyMock
205 .createMock(ScheduledExecutorService.class);
206 ScheduledFuture<?> future = EasyMock.createMock(ScheduledFuture.class);
207 prepareStartTimer(service, future);
208 EasyMock.replay(service, future);
209 final int count = 10;
210 CountDownLatch latch = new CountDownLatch(count - 1);
211 TimedSemaphore semaphore = new TimedSemaphore(service, PERIOD, UNIT, 1);
212 SemaphoreThread t = new SemaphoreThread(semaphore, latch, count,
213 count - 1);
214 semaphore.setLimit(count - 1);
215
216 // start a thread that calls the semaphore count times
217 t.start();
218 latch.await();
219 // now the semaphore's limit should be reached and the thread blocked
220 assertEquals("Wrong semaphore count", count - 1, semaphore
221 .getAcquireCount());
222
223 // this wakes up the thread, it should call the semaphore once more
224 semaphore.endOfPeriod();
225 t.join();
226 assertEquals("Wrong semaphore count (2)", 1, semaphore
227 .getAcquireCount());
228 assertEquals("Wrong acquire() count", count - 1, semaphore
229 .getLastAcquiresPerPeriod());
230 EasyMock.verify(service, future);
231 }
232
233 /**
234 * Tests the acquire() method if more threads are involved than the limit.
235 * This method starts a number of threads that all invoke the semaphore. The
236 * semaphore's limit is set to 1, so in each period only a single thread can
237 * acquire the semaphore.
238 */
239 @Test
240 public void testAcquireMultipleThreads() throws InterruptedException {
241 ScheduledExecutorService service = EasyMock
242 .createMock(ScheduledExecutorService.class);
243 ScheduledFuture<?> future = EasyMock.createMock(ScheduledFuture.class);
244 prepareStartTimer(service, future);
245 EasyMock.replay(service, future);
246 TimedSemaphoreTestImpl semaphore = new TimedSemaphoreTestImpl(service,
247 PERIOD, UNIT, 1);
248 semaphore.latch = new CountDownLatch(1);
249 final int count = 10;
250 SemaphoreThread[] threads = new SemaphoreThread[count];
251 for (int i = 0; i < count; i++) {
252 threads[i] = new SemaphoreThread(semaphore, null, 1, 0);
253 threads[i].start();
254 }
255 for (int i = 0; i < count; i++) {
256 semaphore.latch.await();
257 assertEquals("Wrong count", 1, semaphore.getAcquireCount());
258 semaphore.latch = new CountDownLatch(1);
259 semaphore.endOfPeriod();
260 assertEquals("Wrong acquire count", 1, semaphore
261 .getLastAcquiresPerPeriod());
262 }
263 for (int i = 0; i < count; i++) {
264 threads[i].join();
265 }
266 EasyMock.verify(service, future);
267 }
268
269 /**
270 * Tests the acquire() method if no limit is set. A test thread is started
271 * that calls the semaphore a large number of times. Even if the semaphore's
272 * period does not end, the thread should never block.
273 */
274 @Test
275 public void testAcquireNoLimit() throws InterruptedException {
276 ScheduledExecutorService service = EasyMock
277 .createMock(ScheduledExecutorService.class);
278 ScheduledFuture<?> future = EasyMock.createMock(ScheduledFuture.class);
279 prepareStartTimer(service, future);
280 EasyMock.replay(service, future);
281 TimedSemaphoreTestImpl semaphore = new TimedSemaphoreTestImpl(service,
282 PERIOD, UNIT, TimedSemaphore.NO_LIMIT);
283 final int count = 1000;
284 CountDownLatch latch = new CountDownLatch(count);
285 SemaphoreThread t = new SemaphoreThread(semaphore, latch, count, count);
286 t.start();
287 latch.await();
288 EasyMock.verify(service, future);
289 }
290
291 /**
292 * Tries to call acquire() after shutdown(). This should cause an exception.
293 */
294 @Test(expected = IllegalStateException.class)
295 public void testPassAfterShutdown() throws InterruptedException {
296 TimedSemaphore semaphore = new TimedSemaphore(PERIOD, UNIT, LIMIT);
297 semaphore.shutdown();
298 semaphore.acquire();
299 }
300
301 /**
302 * Tests a bigger number of invocations that span multiple periods. The
303 * period is set to a very short time. A background thread calls the
304 * semaphore a large number of times. While it runs at last one end of a
305 * period should be reached.
306 */
307 @Test
308 public void testAcquireMultiplePeriods() throws InterruptedException {
309 final int count = 1000;
310 TimedSemaphoreTestImpl semaphore = new TimedSemaphoreTestImpl(
311 PERIOD / 10, TimeUnit.MILLISECONDS, 1);
312 semaphore.setLimit(count / 4);
313 CountDownLatch latch = new CountDownLatch(count);
314 SemaphoreThread t = new SemaphoreThread(semaphore, latch, count, count);
315 t.start();
316 latch.await();
317 semaphore.shutdown();
318 assertTrue("End of period not reached", semaphore.getPeriodEnds() > 0);
319 }
320
321 /**
322 * Tests the methods for statistics.
323 */
324 @Test
325 public void testGetAverageCallsPerPeriod() throws InterruptedException {
326 ScheduledExecutorService service = EasyMock
327 .createMock(ScheduledExecutorService.class);
328 ScheduledFuture<?> future = EasyMock.createMock(ScheduledFuture.class);
329 prepareStartTimer(service, future);
330 EasyMock.replay(service, future);
331 TimedSemaphore semaphore = new TimedSemaphore(service, PERIOD, UNIT,
332 LIMIT);
333 semaphore.acquire();
334 semaphore.endOfPeriod();
335 assertEquals("Wrong average (1)", 1.0, semaphore
336 .getAverageCallsPerPeriod(), .005);
337 semaphore.acquire();
338 semaphore.acquire();
339 semaphore.endOfPeriod();
340 assertEquals("Wrong average (2)", 1.5, semaphore
341 .getAverageCallsPerPeriod(), .005);
342 EasyMock.verify(service, future);
343 }
344
345 /**
346 * Tests whether the available non-blocking calls can be queried.
347 */
348 @Test
349 public void testGetAvailablePermits() throws InterruptedException {
350 ScheduledExecutorService service = EasyMock
351 .createMock(ScheduledExecutorService.class);
352 ScheduledFuture<?> future = EasyMock.createMock(ScheduledFuture.class);
353 prepareStartTimer(service, future);
354 EasyMock.replay(service, future);
355 TimedSemaphore semaphore = new TimedSemaphore(service, PERIOD, UNIT,
356 LIMIT);
357 for (int i = 0; i < LIMIT; i++) {
358 assertEquals("Wrong available count at " + i, LIMIT - i, semaphore
359 .getAvailablePermits());
360 semaphore.acquire();
361 }
362 semaphore.endOfPeriod();
363 assertEquals("Wrong available count in new period", LIMIT, semaphore
364 .getAvailablePermits());
365 EasyMock.verify(service, future);
366 }
367
368 /**
369 * A specialized implementation of {@code TimedSemaphore} that is easier to
370 * test.
371 */
372 private static class TimedSemaphoreTestImpl extends TimedSemaphore {
373 /** A mock scheduled future. */
374 ScheduledFuture<?> schedFuture;
375
376 /** A latch for synchronizing with the main thread. */
377 volatile CountDownLatch latch;
378
379 /** Counter for the endOfPeriod() invocations. */
380 private int periodEnds;
381
382 public TimedSemaphoreTestImpl(long timePeriod, TimeUnit timeUnit,
383 int limit) {
384 super(timePeriod, timeUnit, limit);
385 }
386
387 public TimedSemaphoreTestImpl(ScheduledExecutorService service,
388 long timePeriod, TimeUnit timeUnit, int limit) {
389 super(service, timePeriod, timeUnit, limit);
390 }
391
392 /**
393 * Returns the number of invocations of the endOfPeriod() method.
394 *
395 * @return the endOfPeriod() invocations
396 */
397 public int getPeriodEnds() {
398 synchronized (this) {
399 return periodEnds;
400 }
401 }
402
403 /**
404 * Invokes the latch if one is set.
405 */
406 @Override
407 public void acquire() throws InterruptedException {
408 super.acquire();
409 if (latch != null) {
410 latch.countDown();
411 }
412 }
413
414 /**
415 * Counts the number of invocations.
416 */
417 @Override
418 protected void endOfPeriod() {
419 super.endOfPeriod();
420 synchronized (this) {
421 periodEnds++;
422 }
423 }
424
425 /**
426 * Either returns the mock future or calls the super method.
427 */
428 @Override
429 protected ScheduledFuture<?> startTimer() {
430 return (schedFuture != null) ? schedFuture : super.startTimer();
431 }
432 }
433
434 /**
435 * A test thread class that will be used by tests for triggering the
436 * semaphore. The thread calls the semaphore a configurable number of times.
437 * When this is done, it can notify the main thread.
438 */
439 private static class SemaphoreThread extends Thread {
440 /** The semaphore. */
441 private final TimedSemaphore semaphore;
442
443 /** A latch for communication with the main thread. */
444 private final CountDownLatch latch;
445
446 /** The number of acquire() calls. */
447 private final int count;
448
449 /** The number of invocations of the latch. */
450 private final int latchCount;
451
452 public SemaphoreThread(TimedSemaphore b, CountDownLatch l, int c, int lc) {
453 semaphore = b;
454 latch = l;
455 count = c;
456 latchCount = lc;
457 }
458
459 /**
460 * Calls acquire() on the semaphore for the specified number of times.
461 * Optionally the latch will also be triggered to synchronize with the
462 * main test thread.
463 */
464 @Override
465 public void run() {
466 try {
467 for (int i = 0; i < count; i++) {
468 semaphore.acquire();
469
470 if (i < latchCount) {
471 latch.countDown();
472 }
473 }
474 } catch (InterruptedException iex) {
475 Thread.currentThread().interrupt();
476 }
477 }
478 }
479 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.event;
18
19 import java.beans.PropertyChangeEvent;
20 import java.beans.PropertyVetoException;
21 import java.beans.VetoableChangeListener;
22 import java.io.ByteArrayInputStream;
23 import java.io.ByteArrayOutputStream;
24 import java.io.IOException;
25 import java.io.ObjectInputStream;
26 import java.io.ObjectOutputStream;
27 import java.lang.reflect.Method;
28 import java.util.ArrayList;
29 import java.util.Date;
30 import java.util.List;
31
32 import junit.framework.TestCase;
33
34 import org.easymock.EasyMock;
35
36 /**
37 * @since 3.0
38 * @version $Id: EventListenerSupportTest.java 1144929 2011-07-10 18:26:16Z ggregory $
39 */
40 public class EventListenerSupportTest extends TestCase
41 {
42 public void testAddNullListener()
43 {
44 EventListenerSupport<VetoableChangeListener> listenerSupport = EventListenerSupport.create(VetoableChangeListener.class);
45 try
46 {
47 listenerSupport.addListener(null);
48 fail("Should not be able to add a null listener.");
49 }
50 catch (NullPointerException e)
51 {
52
53 }
54 }
55
56 public void testRemoveNullListener()
57 {
58 EventListenerSupport<VetoableChangeListener> listenerSupport = EventListenerSupport.create(VetoableChangeListener.class);
59 try
60 {
61 listenerSupport.removeListener(null);
62 fail("Should not be able to remove a null listener.");
63 }
64 catch (NullPointerException e)
65 {
66
67 }
68 }
69
70 public void testEventDispatchOrder() throws PropertyVetoException
71 {
72 EventListenerSupport<VetoableChangeListener> listenerSupport = EventListenerSupport.create(VetoableChangeListener.class);
73 final List<VetoableChangeListener> calledListeners = new ArrayList<VetoableChangeListener>();
74
75 final VetoableChangeListener listener1 = createListener(calledListeners);
76 final VetoableChangeListener listener2 = createListener(calledListeners);
77 listenerSupport.addListener(listener1);
78 listenerSupport.addListener(listener2);
79 listenerSupport.fire().vetoableChange(new PropertyChangeEvent(new Date(), "Day", 4, 5));
80 assertEquals(calledListeners.size(), 2);
81 assertSame(calledListeners.get(0), listener1);
82 assertSame(calledListeners.get(1), listener2);
83 }
84
85 public void testCreateWithNonInterfaceParameter()
86 {
87 try
88 {
89 EventListenerSupport.create(String.class);
90 fail("Should not be able to create using non-interface class.");
91 }
92 catch (IllegalArgumentException e)
93 {
94
95 }
96 }
97
98 public void testCreateWithNullParameter()
99 {
100 try
101 {
102 EventListenerSupport.create(null);
103 fail("Should not be able to create using null class.");
104 }
105 catch (NullPointerException e)
106 {
107
108 }
109 }
110
111 public void testRemoveListenerDuringEvent() throws PropertyVetoException
112 {
113 final EventListenerSupport<VetoableChangeListener> listenerSupport = EventListenerSupport.create(VetoableChangeListener.class);
114 for (int i = 0; i < 10; ++i)
115 {
116 addDeregisterListener(listenerSupport);
117 }
118 assertEquals(listenerSupport.getListenerCount(), 10);
119 listenerSupport.fire().vetoableChange(new PropertyChangeEvent(new Date(), "Day", 4, 5));
120 assertEquals(listenerSupport.getListenerCount(), 0);
121 }
122
123 public void testGetListeners() {
124 final EventListenerSupport<VetoableChangeListener> listenerSupport = EventListenerSupport.create(VetoableChangeListener.class);
125
126 VetoableChangeListener[] listeners = listenerSupport.getListeners();
127 assertEquals(0, listeners.length);
128 assertEquals(VetoableChangeListener.class, listeners.getClass().getComponentType());
129 VetoableChangeListener[] empty = listeners;
130 //for fun, show that the same empty instance is used
131 assertSame(empty, listenerSupport.getListeners());
132
133 VetoableChangeListener listener1 = EasyMock.createNiceMock(VetoableChangeListener.class);
134 listenerSupport.addListener(listener1);
135 assertEquals(1, listenerSupport.getListeners().length);
136 VetoableChangeListener listener2 = EasyMock.createNiceMock(VetoableChangeListener.class);
137 listenerSupport.addListener(listener2);
138 assertEquals(2, listenerSupport.getListeners().length);
139 listenerSupport.removeListener(listener1);
140 assertEquals(1, listenerSupport.getListeners().length);
141 listenerSupport.removeListener(listener2);
142 assertSame(empty, listenerSupport.getListeners());
143 }
144
145 public void testSerialization() throws IOException, ClassNotFoundException, PropertyVetoException {
146 EventListenerSupport<VetoableChangeListener> listenerSupport = EventListenerSupport.create(VetoableChangeListener.class);
147 listenerSupport.addListener(new VetoableChangeListener() {
148
149 public void vetoableChange(PropertyChangeEvent e) {
150 }
151 });
152 listenerSupport.addListener(EasyMock.createNiceMock(VetoableChangeListener.class));
153
154 //serialize:
155 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
156 ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
157
158 objectOutputStream.writeObject(listenerSupport);
159 objectOutputStream.close();
160
161 //deserialize:
162 @SuppressWarnings("unchecked")
163 EventListenerSupport<VetoableChangeListener> deserializedListenerSupport = (EventListenerSupport<VetoableChangeListener>) new ObjectInputStream(
164 new ByteArrayInputStream(outputStream.toByteArray())).readObject();
165
166 //make sure we get a listener array back, of the correct component type, and that it contains only the serializable mock
167 VetoableChangeListener[] listeners = deserializedListenerSupport.getListeners();
168 assertEquals(VetoableChangeListener.class, listeners.getClass().getComponentType());
169 assertEquals(1, listeners.length);
170
171 //now verify that the mock still receives events; we can infer that the proxy was correctly reconstituted
172 VetoableChangeListener listener = listeners[0];
173 PropertyChangeEvent evt = new PropertyChangeEvent(new Date(), "Day", 7, 9);
174 listener.vetoableChange(evt);
175 EasyMock.replay(listener);
176 deserializedListenerSupport.fire().vetoableChange(evt);
177 EasyMock.verify(listener);
178
179 //remove listener and verify we get an empty array of listeners
180 deserializedListenerSupport.removeListener(listener);
181 assertEquals(0, deserializedListenerSupport.getListeners().length);
182 }
183
184 public void testSubclassInvocationHandling() throws PropertyVetoException {
185
186 @SuppressWarnings("serial")
187 EventListenerSupport<VetoableChangeListener> eventListenerSupport = new EventListenerSupport<VetoableChangeListener>(
188 VetoableChangeListener.class) {
189 @Override
190 protected java.lang.reflect.InvocationHandler createInvocationHandler() {
191 return new ProxyInvocationHandler() {
192 /**
193 * {@inheritDoc}
194 */
195 @Override
196 public Object invoke(Object proxy, Method method, Object[] args)
197 throws Throwable {
198 return "vetoableChange".equals(method.getName())
199 && "Hour".equals(((PropertyChangeEvent) args[0]).getPropertyName()) ? null
200 : super.invoke(proxy, method, args);
201 }
202 };
203 }
204 };
205
206 VetoableChangeListener listener = EasyMock.createNiceMock(VetoableChangeListener.class);
207 eventListenerSupport.addListener(listener);
208 Object source = new Date();
209 PropertyChangeEvent ignore = new PropertyChangeEvent(source, "Hour", 5, 6);
210 PropertyChangeEvent respond = new PropertyChangeEvent(source, "Day", 6, 7);
211 listener.vetoableChange(respond);
212 EasyMock.replay(listener);
213 eventListenerSupport.fire().vetoableChange(ignore);
214 eventListenerSupport.fire().vetoableChange(respond);
215 EasyMock.verify(listener);
216 }
217
218 private void addDeregisterListener(final EventListenerSupport<VetoableChangeListener> listenerSupport)
219 {
220 listenerSupport.addListener(new VetoableChangeListener()
221 {
222 public void vetoableChange(PropertyChangeEvent e)
223 {
224 listenerSupport.removeListener(this);
225 }
226 });
227 }
228
229 private VetoableChangeListener createListener(final List<VetoableChangeListener> calledListeners)
230 {
231 return new VetoableChangeListener()
232 {
233 public void vetoableChange(PropertyChangeEvent e)
234 {
235 calledListeners.add(this);
236 }
237 };
238 }
239 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.event;
17
18 import java.beans.PropertyChangeEvent;
19 import java.beans.PropertyChangeListener;
20 import java.beans.VetoableChangeListener;
21 import java.lang.reflect.Constructor;
22 import java.lang.reflect.InvocationHandler;
23 import java.lang.reflect.Method;
24 import java.lang.reflect.Modifier;
25 import java.lang.reflect.Proxy;
26 import java.util.Date;
27 import java.util.Map;
28 import java.util.TreeMap;
29
30 import javax.naming.event.ObjectChangeListener;
31
32 import junit.framework.TestCase;
33
34 /**
35 * @since 3.0
36 * @version $Id: EventUtilsTest.java 1144929 2011-07-10 18:26:16Z ggregory $
37 */
38 public class EventUtilsTest extends TestCase
39 {
40
41 public void testConstructor() {
42 assertNotNull(new EventUtils());
43 Constructor<?>[] cons = EventUtils.class.getDeclaredConstructors();
44 assertEquals(1, cons.length);
45 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
46 assertEquals(true, Modifier.isPublic(EventUtils.class.getModifiers()));
47 assertEquals(false, Modifier.isFinal(EventUtils.class.getModifiers()));
48 }
49
50 public void testAddEventListener()
51 {
52 final PropertyChangeSource src = new PropertyChangeSource();
53 EventCountingInvociationHandler handler = new EventCountingInvociationHandler();
54 PropertyChangeListener listener = handler.createListener(PropertyChangeListener.class);
55 assertEquals(0, handler.getEventCount("propertyChange"));
56 EventUtils.addEventListener(src, PropertyChangeListener.class, listener);
57 assertEquals(0, handler.getEventCount("propertyChange"));
58 src.setProperty("newValue");
59 assertEquals(1, handler.getEventCount("propertyChange"));
60 }
61
62 public void testAddEventListenerWithNoAddMethod()
63 {
64 final PropertyChangeSource src = new PropertyChangeSource();
65 EventCountingInvociationHandler handler = new EventCountingInvociationHandler();
66 ObjectChangeListener listener = handler.createListener(ObjectChangeListener.class);
67 try
68 {
69 EventUtils.addEventListener(src, ObjectChangeListener.class, listener);
70 fail("Should not be allowed to add a listener to an object that doesn't support it.");
71 }
72 catch (IllegalArgumentException e)
73 {
74 assertEquals("Class " + src.getClass().getName() + " does not have a public add" + ObjectChangeListener.class.getSimpleName() + " method which takes a parameter of type " + ObjectChangeListener.class.getName() + ".", e.getMessage());
75 }
76 }
77
78 public void testAddEventListenerThrowsException()
79 {
80 final ExceptionEventSource src = new ExceptionEventSource();
81 try
82 {
83 EventUtils.addEventListener(src, PropertyChangeListener.class, new PropertyChangeListener()
84 {
85 public void propertyChange(PropertyChangeEvent e)
86 {
87 // Do nothing!
88 }
89 });
90 fail("Add method should have thrown an exception, so method should fail.");
91 }
92 catch (RuntimeException e)
93 {
94
95 }
96 }
97
98 public void testAddEventListenerWithPrivateAddMethod()
99 {
100 final PropertyChangeSource src = new PropertyChangeSource();
101 EventCountingInvociationHandler handler = new EventCountingInvociationHandler();
102 VetoableChangeListener listener = handler.createListener(VetoableChangeListener.class);
103 try
104 {
105 EventUtils.addEventListener(src, VetoableChangeListener.class, listener);
106 fail("Should not be allowed to add a listener to an object that doesn't support it.");
107 }
108 catch (IllegalArgumentException e)
109 {
110 assertEquals("Class " + src.getClass().getName() + " does not have a public add" + VetoableChangeListener.class.getSimpleName() + " method which takes a parameter of type " + VetoableChangeListener.class.getName() + ".", e.getMessage());
111 }
112 }
113
114 public void testBindEventsToMethod()
115 {
116 final PropertyChangeSource src = new PropertyChangeSource();
117 final EventCounter counter = new EventCounter();
118 EventUtils.bindEventsToMethod(counter, "eventOccurred", src, PropertyChangeListener.class);
119 assertEquals(0, counter.getCount());
120 src.setProperty("newValue");
121 assertEquals(1, counter.getCount());
122 }
123
124
125 public void testBindEventsToMethodWithEvent()
126 {
127 final PropertyChangeSource src = new PropertyChangeSource();
128 final EventCounterWithEvent counter = new EventCounterWithEvent();
129 EventUtils.bindEventsToMethod(counter, "eventOccurred", src, PropertyChangeListener.class);
130 assertEquals(0, counter.getCount());
131 src.setProperty("newValue");
132 assertEquals(1, counter.getCount());
133 }
134
135
136 public void testBindFilteredEventsToMethod()
137 {
138 final MultipleEventSource src = new MultipleEventSource();
139 final EventCounter counter = new EventCounter();
140 EventUtils.bindEventsToMethod(counter, "eventOccurred", src, MultipleEventListener.class, "event1");
141 assertEquals(0, counter.getCount());
142 src.listeners.fire().event1(new PropertyChangeEvent(new Date(), "Day", Integer.valueOf(0), Integer.valueOf(1)));
143 assertEquals(1, counter.getCount());
144 src.listeners.fire().event2(new PropertyChangeEvent(new Date(), "Day", Integer.valueOf(1), Integer.valueOf(2)));
145 assertEquals(1, counter.getCount());
146 }
147
148 public static interface MultipleEventListener
149 {
150 public void event1(PropertyChangeEvent e);
151
152 public void event2(PropertyChangeEvent e);
153 }
154
155 public static class EventCounter
156 {
157 private int count;
158
159 public void eventOccurred()
160 {
161 count++;
162 }
163
164 public int getCount()
165 {
166 return count;
167 }
168 }
169
170 public static class EventCounterWithEvent
171 {
172 private int count;
173
174 public void eventOccurred(PropertyChangeEvent e)
175 {
176 count++;
177 }
178
179 public int getCount()
180 {
181 return count;
182 }
183 }
184
185
186 private static class EventCountingInvociationHandler implements InvocationHandler
187 {
188 private Map<String, Integer> eventCounts = new TreeMap<String, Integer>();
189
190 public <L> L createListener(Class<L> listenerType)
191 {
192 return listenerType.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
193 new Class[]{listenerType},
194 this));
195 }
196
197 public int getEventCount(String eventName)
198 {
199 Integer count = eventCounts.get(eventName);
200 return count == null ? 0 : count.intValue();
201 }
202
203 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
204 {
205 Integer count = eventCounts.get(method.getName());
206 if (count == null)
207 {
208 eventCounts.put(method.getName(), Integer.valueOf(1));
209 }
210 else
211 {
212 eventCounts.put(method.getName(), Integer.valueOf(count.intValue() + 1));
213 }
214 return null;
215 }
216 }
217
218 public static class MultipleEventSource
219 {
220 private EventListenerSupport<MultipleEventListener> listeners = EventListenerSupport.create(MultipleEventListener.class);
221
222 public void addMultipleEventListener(MultipleEventListener listener)
223 {
224 listeners.addListener(listener);
225 }
226 }
227
228 public static class ExceptionEventSource
229 {
230 public void addPropertyChangeListener(PropertyChangeListener listener)
231 {
232 throw new RuntimeException();
233 }
234 }
235
236 public static class PropertyChangeSource
237 {
238 private EventListenerSupport<PropertyChangeListener> listeners = EventListenerSupport.create(PropertyChangeListener.class);
239
240 private String property;
241
242 public void setProperty(String property)
243 {
244 String oldValue = this.property;
245 this.property = property;
246 listeners.fire().propertyChange(new PropertyChangeEvent(this, "property", oldValue, property));
247 }
248
249 protected void addVetoableChangeListener(VetoableChangeListener listener)
250 {
251 // Do nothing!
252 }
253
254 public void addPropertyChangeListener(PropertyChangeListener listener)
255 {
256 listeners.addListener(listener);
257 }
258
259 public void removePropertyChangeListener(PropertyChangeListener listener)
260 {
261 listeners.removeListener(listener);
262 }
263 }
264 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 import java.io.Serializable;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.Date;
22 import java.util.List;
23 import java.util.Set;
24
25 import junit.framework.TestCase;
26
27 import org.apache.commons.lang3.SerializationUtils;
28 import org.apache.commons.lang3.tuple.Pair;
29
30
31 /**
32 * Abstract test of an ExceptionContext implementation.
33 */
34 public abstract class AbstractExceptionContextTest<T extends ExceptionContext & Serializable> extends TestCase {
35
36 protected static final String TEST_MESSAGE_2 = "This is monotonous";
37 protected static final String TEST_MESSAGE = "Test Message";
38 protected T exceptionContext;
39
40 protected static class ObjectWithFaultyToString {
41 @Override
42 public String toString() {
43 throw new RuntimeException("Crap");
44 }
45 }
46
47 @Override
48 protected void setUp() throws Exception {
49 exceptionContext
50 .addContextValue("test1", null)
51 .addContextValue("test2", "some value")
52 .addContextValue("test Date", new Date())
53 .addContextValue("test Nbr", Integer.valueOf(5))
54 .addContextValue("test Poorly written obj", new ObjectWithFaultyToString());
55 }
56
57 public void testAddContextValue() {
58 String message = exceptionContext.getFormattedExceptionMessage(TEST_MESSAGE);
59 assertTrue(message.indexOf(TEST_MESSAGE) >= 0);
60 assertTrue(message.indexOf("test1") >= 0);
61 assertTrue(message.indexOf("test2") >= 0);
62 assertTrue(message.indexOf("test Date") >= 0);
63 assertTrue(message.indexOf("test Nbr") >= 0);
64 assertTrue(message.indexOf("some value") >= 0);
65 assertTrue(message.indexOf("5") >= 0);
66
67 assertTrue(exceptionContext.getFirstContextValue("test1") == null);
68 assertTrue(exceptionContext.getFirstContextValue("test2").equals("some value"));
69
70 assertEquals(5, exceptionContext.getContextLabels().size());
71 assertTrue(exceptionContext.getContextLabels().contains("test1"));
72 assertTrue(exceptionContext.getContextLabels().contains("test2"));
73 assertTrue(exceptionContext.getContextLabels().contains("test Date"));
74 assertTrue(exceptionContext.getContextLabels().contains("test Nbr"));
75
76 exceptionContext.addContextValue("test2", "different value");
77 assertEquals(5, exceptionContext.getContextLabels().size());
78 assertTrue(exceptionContext.getContextLabels().contains("test2"));
79
80 String contextMessage = exceptionContext.getFormattedExceptionMessage(null);
81 assertTrue(contextMessage.indexOf(TEST_MESSAGE) == -1);
82 }
83
84 public void testSetContextValue() {
85 exceptionContext.addContextValue("test2", "different value");
86 exceptionContext.setContextValue("test3", "3");
87
88 String message = exceptionContext.getFormattedExceptionMessage(TEST_MESSAGE);
89 assertTrue(message.indexOf(TEST_MESSAGE) >= 0);
90 assertTrue(message.indexOf("test Poorly written obj") >= 0);
91 assertTrue(message.indexOf("Crap") >= 0);
92
93 assertTrue(exceptionContext.getFirstContextValue("crap") == null);
94 assertTrue(exceptionContext.getFirstContextValue("test Poorly written obj") instanceof ObjectWithFaultyToString);
95
96 assertEquals(7, exceptionContext.getContextEntries().size());
97 assertEquals(6, exceptionContext.getContextLabels().size());
98
99 assertTrue(exceptionContext.getContextLabels().contains("test Poorly written obj"));
100 assertTrue(!exceptionContext.getContextLabels().contains("crap"));
101
102 exceptionContext.setContextValue("test Poorly written obj", "replacement");
103
104 assertEquals(7, exceptionContext.getContextEntries().size());
105 assertEquals(6, exceptionContext.getContextLabels().size());
106
107 exceptionContext.setContextValue("test2", "another");
108
109 assertEquals(6, exceptionContext.getContextEntries().size());
110 assertEquals(6, exceptionContext.getContextLabels().size());
111
112 String contextMessage = exceptionContext.getFormattedExceptionMessage(null);
113 assertTrue(contextMessage.indexOf(TEST_MESSAGE) == -1);
114 }
115
116 public void testGetFirstContextValue() {
117 exceptionContext.addContextValue("test2", "different value");
118
119 assertTrue(exceptionContext.getFirstContextValue("test1") == null);
120 assertTrue(exceptionContext.getFirstContextValue("test2").equals("some value"));
121 assertTrue(exceptionContext.getFirstContextValue("crap") == null);
122
123 exceptionContext.setContextValue("test2", "another");
124
125 assertTrue(exceptionContext.getFirstContextValue("test2").equals("another"));
126 }
127
128 public void testGetContextValues() {
129 exceptionContext.addContextValue("test2", "different value");
130
131 assertEquals(exceptionContext.getContextValues("test1"), Collections.singletonList(null));
132 assertEquals(exceptionContext.getContextValues("test2"), Arrays.asList("some value", "different value"));
133
134 exceptionContext.setContextValue("test2", "another");
135
136 assertTrue(exceptionContext.getFirstContextValue("test2").equals("another"));
137 }
138
139 public void testGetContextLabels() {
140 assertEquals(5, exceptionContext.getContextEntries().size());
141
142 exceptionContext.addContextValue("test2", "different value");
143
144 Set<String> labels = exceptionContext.getContextLabels();
145 assertEquals(6, exceptionContext.getContextEntries().size());
146 assertEquals(5, labels.size());
147 assertTrue(labels.contains("test1"));
148 assertTrue(labels.contains("test2"));
149 assertTrue(labels.contains("test Date"));
150 assertTrue(labels.contains("test Nbr"));
151 }
152
153 public void testGetContextEntries() {
154 assertEquals(5, exceptionContext.getContextEntries().size());
155
156 exceptionContext.addContextValue("test2", "different value");
157
158 List<Pair<String, Object>> entries = exceptionContext.getContextEntries();
159 assertEquals(6, entries.size());
160 assertEquals("test1", entries.get(0).getKey());
161 assertEquals("test2", entries.get(1).getKey());
162 assertEquals("test Date", entries.get(2).getKey());
163 assertEquals("test Nbr", entries.get(3).getKey());
164 assertEquals("test Poorly written obj", entries.get(4).getKey());
165 assertEquals("test2", entries.get(5).getKey());
166 }
167
168 public void testJavaSerialization() {
169 exceptionContext.setContextValue("test Poorly written obj", "serializable replacement");
170
171 @SuppressWarnings("unchecked")
172 T clone = (T)SerializationUtils.deserialize(SerializationUtils.serialize(exceptionContext));
173 assertEquals(exceptionContext.getFormattedExceptionMessage(null), clone.getFormattedExceptionMessage(null));
174 }
175 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 import java.util.Date;
19
20 import org.apache.commons.lang3.StringUtils;
21
22 /**
23 * JUnit tests for ContextedException.
24 */
25 public class ContextedExceptionTest extends AbstractExceptionContextTest<ContextedException> {
26
27 @Override
28 public void setUp() throws Exception {
29 exceptionContext = new ContextedException(new Exception(TEST_MESSAGE));
30 super.setUp();
31 }
32
33 public void testContextedException() {
34 exceptionContext = new ContextedException();
35 String message = exceptionContext.getMessage();
36 String trace = ExceptionUtils.getStackTrace(exceptionContext);
37 assertTrue(trace.indexOf("ContextedException")>=0);
38 assertTrue(StringUtils.isEmpty(message));
39 }
40
41 public void testContextedExceptionString() {
42 exceptionContext = new ContextedException(TEST_MESSAGE);
43 assertEquals(TEST_MESSAGE, exceptionContext.getMessage());
44
45 String trace = ExceptionUtils.getStackTrace(exceptionContext);
46 assertTrue(trace.indexOf(TEST_MESSAGE)>=0);
47 }
48
49 public void testContextedExceptionThrowable() {
50 exceptionContext = new ContextedException(new Exception(TEST_MESSAGE));
51 String message = exceptionContext.getMessage();
52 String trace = ExceptionUtils.getStackTrace(exceptionContext);
53 assertTrue(trace.indexOf("ContextedException")>=0);
54 assertTrue(trace.indexOf(TEST_MESSAGE)>=0);
55 assertTrue(message.indexOf(TEST_MESSAGE)>=0);
56 }
57
58 public void testContextedExceptionStringThrowable() {
59 exceptionContext = new ContextedException(TEST_MESSAGE_2, new Exception(TEST_MESSAGE));
60 String message = exceptionContext.getMessage();
61 String trace = ExceptionUtils.getStackTrace(exceptionContext);
62 assertTrue(trace.indexOf("ContextedException")>=0);
63 assertTrue(trace.indexOf(TEST_MESSAGE)>=0);
64 assertTrue(trace.indexOf(TEST_MESSAGE_2)>=0);
65 assertTrue(message.indexOf(TEST_MESSAGE_2)>=0);
66 }
67
68 public void testContextedExceptionStringThrowableContext() {
69 exceptionContext = new ContextedException(TEST_MESSAGE_2, new Exception(TEST_MESSAGE), new DefaultExceptionContext());
70 String message = exceptionContext.getMessage();
71 String trace = ExceptionUtils.getStackTrace(exceptionContext);
72 assertTrue(trace.indexOf("ContextedException")>=0);
73 assertTrue(trace.indexOf(TEST_MESSAGE)>=0);
74 assertTrue(trace.indexOf(TEST_MESSAGE_2)>=0);
75 assertTrue(message.indexOf(TEST_MESSAGE_2)>=0);
76 }
77
78 public void testNullExceptionPassing() {
79 exceptionContext = new ContextedException(TEST_MESSAGE_2, new Exception(TEST_MESSAGE), null)
80 .addContextValue("test1", null)
81 .addContextValue("test2", "some value")
82 .addContextValue("test Date", new Date())
83 .addContextValue("test Nbr", Integer.valueOf(5))
84 .addContextValue("test Poorly written obj", new ObjectWithFaultyToString());
85
86 String message = exceptionContext.getMessage();
87 assertTrue(message != null);
88 }
89
90 public void testRawMessage() {
91 assertEquals(Exception.class.getName() + ": " + TEST_MESSAGE, exceptionContext.getRawMessage());
92 exceptionContext = new ContextedException(TEST_MESSAGE_2, new Exception(TEST_MESSAGE), new DefaultExceptionContext());
93 assertEquals(TEST_MESSAGE_2, exceptionContext.getRawMessage());
94 exceptionContext = new ContextedException(null, new Exception(TEST_MESSAGE), new DefaultExceptionContext());
95 assertNull(exceptionContext.getRawMessage());
96 }
97 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 import java.util.Date;
19
20 import org.apache.commons.lang3.StringUtils;
21
22 /**
23 * JUnit tests for ContextedRuntimeException.
24 */
25 public class ContextedRuntimeExceptionTest extends AbstractExceptionContextTest<ContextedRuntimeException> {
26
27 @Override
28 protected void setUp() throws Exception {
29 exceptionContext = new ContextedRuntimeException(new Exception(TEST_MESSAGE));
30 super.setUp();
31 }
32
33 public void testContextedException() {
34 exceptionContext = new ContextedRuntimeException();
35 String message = exceptionContext.getMessage();
36 String trace = ExceptionUtils.getStackTrace(exceptionContext);
37 assertTrue(trace.indexOf("ContextedException")>=0);
38 assertTrue(StringUtils.isEmpty(message));
39 }
40
41 public void testContextedExceptionString() {
42 exceptionContext = new ContextedRuntimeException(TEST_MESSAGE);
43 assertEquals(TEST_MESSAGE, exceptionContext.getMessage());
44
45 String trace = ExceptionUtils.getStackTrace(exceptionContext);
46 assertTrue(trace.indexOf(TEST_MESSAGE)>=0);
47 }
48
49 public void testContextedExceptionThrowable() {
50 exceptionContext = new ContextedRuntimeException(new Exception(TEST_MESSAGE));
51 String message = exceptionContext.getMessage();
52 String trace = ExceptionUtils.getStackTrace(exceptionContext);
53 assertTrue(trace.indexOf("ContextedException")>=0);
54 assertTrue(trace.indexOf(TEST_MESSAGE)>=0);
55 assertTrue(message.indexOf(TEST_MESSAGE)>=0);
56 }
57
58 public void testContextedExceptionStringThrowable() {
59 exceptionContext = new ContextedRuntimeException(TEST_MESSAGE_2, new Exception(TEST_MESSAGE));
60 String message = exceptionContext.getMessage();
61 String trace = ExceptionUtils.getStackTrace(exceptionContext);
62 assertTrue(trace.indexOf("ContextedException")>=0);
63 assertTrue(trace.indexOf(TEST_MESSAGE)>=0);
64 assertTrue(trace.indexOf(TEST_MESSAGE_2)>=0);
65 assertTrue(message.indexOf(TEST_MESSAGE_2)>=0);
66 }
67
68 public void testContextedExceptionStringThrowableContext() {
69 exceptionContext = new ContextedRuntimeException(TEST_MESSAGE_2, new Exception(TEST_MESSAGE), new DefaultExceptionContext() {});
70 String message = exceptionContext.getMessage();
71 String trace = ExceptionUtils.getStackTrace(exceptionContext);
72 assertTrue(trace.indexOf("ContextedException")>=0);
73 assertTrue(trace.indexOf(TEST_MESSAGE)>=0);
74 assertTrue(trace.indexOf(TEST_MESSAGE_2)>=0);
75 assertTrue(message.indexOf(TEST_MESSAGE_2)>=0);
76 }
77
78 public void testNullExceptionPassing() {
79 exceptionContext = new ContextedRuntimeException(TEST_MESSAGE_2, new Exception(TEST_MESSAGE), null)
80 .addContextValue("test1", null)
81 .addContextValue("test2", "some value")
82 .addContextValue("test Date", new Date())
83 .addContextValue("test Nbr", Integer.valueOf(5))
84 .addContextValue("test Poorly written obj", new ObjectWithFaultyToString());
85
86 String message = exceptionContext.getMessage();
87 assertTrue(message != null);
88 }
89
90 public void testRawMessage() {
91 assertEquals(Exception.class.getName() + ": " + TEST_MESSAGE, exceptionContext.getRawMessage());
92 exceptionContext = new ContextedRuntimeException(TEST_MESSAGE_2, new Exception(TEST_MESSAGE), new DefaultExceptionContext());
93 assertEquals(TEST_MESSAGE_2, exceptionContext.getRawMessage());
94 exceptionContext = new ContextedRuntimeException(null, new Exception(TEST_MESSAGE), new DefaultExceptionContext());
95 assertNull(exceptionContext.getRawMessage());
96 }
97 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 /**
19 * JUnit tests for DefaultExceptionContext.
20 *
21 */
22 public class DefaultExceptionContextTest extends AbstractExceptionContextTest<DefaultExceptionContext> {
23
24 @Override
25 public void setUp() throws Exception {
26 exceptionContext = new DefaultExceptionContext();
27 super.setUp();
28 }
29
30 public void testFormattedExceptionMessageNull() {
31 exceptionContext = new DefaultExceptionContext();
32 exceptionContext.getFormattedExceptionMessage(null);
33 }
34
35 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.exception;
17
18 import java.io.ByteArrayOutputStream;
19 import java.io.PrintStream;
20 import java.io.PrintWriter;
21 import java.io.StringWriter;
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.Modifier;
24 import java.util.List;
25
26 import junit.framework.TestCase;
27
28 /**
29 * Tests {@link org.apache.commons.lang3.exception.ExceptionUtils}.
30 *
31 * <h3>Notes</h3>
32 * <p>
33 * Make sure this exception code does not depend on Java 1.4 nested exceptions. SVN revision 38990 does not compile with
34 * Java 1.3.1.
35 * </p>
36 * <ul>
37 * <li>Compiled with Sun Java 1.3.1_15</li>
38 * <li>Tested with Sun Java 1.3.1_15</li>
39 * <li>Tested with Sun Java 1.4.2_12</li>
40 * <li>Tested with Sun Java 1.5.0_08</li>
41 * <li>All of the above on Windows XP SP2 + patches.</li>
42 * </ul>
43 * <p>
44 * Gary Gregory; August 16, 2006.
45 * </p>
46 *
47 * @since 1.0
48 */
49 public class ExceptionUtilsTest extends TestCase {
50
51 private NestableException nested;
52 private Throwable withCause;
53 private Throwable withoutCause;
54 private Throwable jdkNoCause;
55 private ExceptionWithCause cyclicCause;
56
57 public ExceptionUtilsTest(String name) {
58 super(name);
59 }
60
61 @Override
62 public void setUp() {
63 withoutCause = createExceptionWithoutCause();
64 nested = new NestableException(withoutCause);
65 withCause = new ExceptionWithCause(nested);
66 jdkNoCause = new NullPointerException();
67 ExceptionWithCause a = new ExceptionWithCause(null);
68 ExceptionWithCause b = new ExceptionWithCause(a);
69 a.setCause(b);
70 cyclicCause = new ExceptionWithCause(a);
71 }
72
73 @Override
74 protected void tearDown() throws Exception {
75 withoutCause = null;
76 nested = null;
77 withCause = null;
78 jdkNoCause = null;
79 cyclicCause = null;
80 }
81
82 //-----------------------------------------------------------------------
83 private Throwable createExceptionWithoutCause() {
84 try {
85 throw new ExceptionWithoutCause();
86 } catch (Throwable t) {
87 return t;
88 }
89 }
90
91 private Throwable createExceptionWithCause() {
92 try {
93 try {
94 throw new ExceptionWithCause(createExceptionWithoutCause());
95 } catch (Throwable t) {
96 throw new ExceptionWithCause(t);
97 }
98 } catch (Throwable t) {
99 return t;
100 }
101 }
102
103 //-----------------------------------------------------------------------
104
105 public void testConstructor() {
106 assertNotNull(new ExceptionUtils());
107 Constructor<?>[] cons = ExceptionUtils.class.getDeclaredConstructors();
108 assertEquals(1, cons.length);
109 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
110 assertEquals(true, Modifier.isPublic(ExceptionUtils.class.getModifiers()));
111 assertEquals(false, Modifier.isFinal(ExceptionUtils.class.getModifiers()));
112 }
113
114 //-----------------------------------------------------------------------
115 @SuppressWarnings("deprecation") // Specifically tests the deprecated methods
116 public void testGetCause_Throwable() {
117 assertSame(null, ExceptionUtils.getCause(null));
118 assertSame(null, ExceptionUtils.getCause(withoutCause));
119 assertSame(withoutCause, ExceptionUtils.getCause(nested));
120 assertSame(nested, ExceptionUtils.getCause(withCause));
121 assertSame(null, ExceptionUtils.getCause(jdkNoCause));
122 assertSame(cyclicCause.getCause(), ExceptionUtils.getCause(cyclicCause));
123 assertSame(((ExceptionWithCause) cyclicCause.getCause()).getCause(), ExceptionUtils.getCause(cyclicCause.getCause()));
124 assertSame(cyclicCause.getCause(), ExceptionUtils.getCause(((ExceptionWithCause) cyclicCause.getCause()).getCause()));
125 }
126
127 @SuppressWarnings("deprecation") // Specifically tests the deprecated methods
128 public void testGetCause_ThrowableArray() {
129 assertSame(null, ExceptionUtils.getCause(null, null));
130 assertSame(null, ExceptionUtils.getCause(null, new String[0]));
131
132 // not known type, so match on supplied method names
133 assertSame(nested, ExceptionUtils.getCause(withCause, null)); // default names
134 assertSame(null, ExceptionUtils.getCause(withCause, new String[0]));
135 assertSame(null, ExceptionUtils.getCause(withCause, new String[] {null}));
136 assertSame(nested, ExceptionUtils.getCause(withCause, new String[] {"getCause"}));
137
138 // not known type, so match on supplied method names
139 assertSame(null, ExceptionUtils.getCause(withoutCause, null));
140 assertSame(null, ExceptionUtils.getCause(withoutCause, new String[0]));
141 assertSame(null, ExceptionUtils.getCause(withoutCause, new String[] {null}));
142 assertSame(null, ExceptionUtils.getCause(withoutCause, new String[] {"getCause"}));
143 assertSame(null, ExceptionUtils.getCause(withoutCause, new String[] {"getTargetException"}));
144 }
145
146 public void testGetRootCause_Throwable() {
147 assertSame(null, ExceptionUtils.getRootCause(null));
148 assertSame(null, ExceptionUtils.getRootCause(withoutCause));
149 assertSame(withoutCause, ExceptionUtils.getRootCause(nested));
150 assertSame(withoutCause, ExceptionUtils.getRootCause(withCause));
151 assertSame(null, ExceptionUtils.getRootCause(jdkNoCause));
152 assertSame(((ExceptionWithCause) cyclicCause.getCause()).getCause(), ExceptionUtils.getRootCause(cyclicCause));
153 }
154
155 //-----------------------------------------------------------------------
156 public void testGetThrowableCount_Throwable() {
157 assertEquals(0, ExceptionUtils.getThrowableCount(null));
158 assertEquals(1, ExceptionUtils.getThrowableCount(withoutCause));
159 assertEquals(2, ExceptionUtils.getThrowableCount(nested));
160 assertEquals(3, ExceptionUtils.getThrowableCount(withCause));
161 assertEquals(1, ExceptionUtils.getThrowableCount(jdkNoCause));
162 assertEquals(3, ExceptionUtils.getThrowableCount(cyclicCause));
163 }
164
165 //-----------------------------------------------------------------------
166 public void testGetThrowables_Throwable_null() {
167 assertEquals(0, ExceptionUtils.getThrowables(null).length);
168 }
169
170 public void testGetThrowables_Throwable_withoutCause() {
171 Throwable[] throwables = ExceptionUtils.getThrowables(withoutCause);
172 assertEquals(1, throwables.length);
173 assertSame(withoutCause, throwables[0]);
174 }
175
176 public void testGetThrowables_Throwable_nested() {
177 Throwable[] throwables = ExceptionUtils.getThrowables(nested);
178 assertEquals(2, throwables.length);
179 assertSame(nested, throwables[0]);
180 assertSame(withoutCause, throwables[1]);
181 }
182
183 public void testGetThrowables_Throwable_withCause() {
184 Throwable[] throwables = ExceptionUtils.getThrowables(withCause);
185 assertEquals(3, throwables.length);
186 assertSame(withCause, throwables[0]);
187 assertSame(nested, throwables[1]);
188 assertSame(withoutCause, throwables[2]);
189 }
190
191 public void testGetThrowables_Throwable_jdkNoCause() {
192 Throwable[] throwables = ExceptionUtils.getThrowables(jdkNoCause);
193 assertEquals(1, throwables.length);
194 assertSame(jdkNoCause, throwables[0]);
195 }
196
197 public void testGetThrowables_Throwable_recursiveCause() {
198 Throwable[] throwables = ExceptionUtils.getThrowables(cyclicCause);
199 assertEquals(3, throwables.length);
200 assertSame(cyclicCause, throwables[0]);
201 assertSame(cyclicCause.getCause(), throwables[1]);
202 assertSame(((ExceptionWithCause) cyclicCause.getCause()).getCause(), throwables[2]);
203 }
204
205 //-----------------------------------------------------------------------
206 public void testGetThrowableList_Throwable_null() {
207 List<?> throwables = ExceptionUtils.getThrowableList(null);
208 assertEquals(0, throwables.size());
209 }
210
211 public void testGetThrowableList_Throwable_withoutCause() {
212 List<?> throwables = ExceptionUtils.getThrowableList(withoutCause);
213 assertEquals(1, throwables.size());
214 assertSame(withoutCause, throwables.get(0));
215 }
216
217 public void testGetThrowableList_Throwable_nested() {
218 List<?> throwables = ExceptionUtils.getThrowableList(nested);
219 assertEquals(2, throwables.size());
220 assertSame(nested, throwables.get(0));
221 assertSame(withoutCause, throwables.get(1));
222 }
223
224 public void testGetThrowableList_Throwable_withCause() {
225 List<?> throwables = ExceptionUtils.getThrowableList(withCause);
226 assertEquals(3, throwables.size());
227 assertSame(withCause, throwables.get(0));
228 assertSame(nested, throwables.get(1));
229 assertSame(withoutCause, throwables.get(2));
230 }
231
232 public void testGetThrowableList_Throwable_jdkNoCause() {
233 List<?> throwables = ExceptionUtils.getThrowableList(jdkNoCause);
234 assertEquals(1, throwables.size());
235 assertSame(jdkNoCause, throwables.get(0));
236 }
237
238 public void testGetThrowableList_Throwable_recursiveCause() {
239 List<?> throwables = ExceptionUtils.getThrowableList(cyclicCause);
240 assertEquals(3, throwables.size());
241 assertSame(cyclicCause, throwables.get(0));
242 assertSame(cyclicCause.getCause(), throwables.get(1));
243 assertSame(((ExceptionWithCause) cyclicCause.getCause()).getCause(), throwables.get(2));
244 }
245
246 //-----------------------------------------------------------------------
247 public void testIndexOf_ThrowableClass() {
248 assertEquals(-1, ExceptionUtils.indexOfThrowable(null, null));
249 assertEquals(-1, ExceptionUtils.indexOfThrowable(null, NestableException.class));
250
251 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, null));
252 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithCause.class));
253 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, NestableException.class));
254 assertEquals(0, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithoutCause.class));
255
256 assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, null));
257 assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithCause.class));
258 assertEquals(0, ExceptionUtils.indexOfThrowable(nested, NestableException.class));
259 assertEquals(1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithoutCause.class));
260
261 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, null));
262 assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class));
263 assertEquals(1, ExceptionUtils.indexOfThrowable(withCause, NestableException.class));
264 assertEquals(2, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithoutCause.class));
265
266 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Exception.class));
267 }
268
269 public void testIndexOf_ThrowableClassInt() {
270 assertEquals(-1, ExceptionUtils.indexOfThrowable(null, null, 0));
271 assertEquals(-1, ExceptionUtils.indexOfThrowable(null, NestableException.class, 0));
272
273 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, null));
274 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithCause.class, 0));
275 assertEquals(-1, ExceptionUtils.indexOfThrowable(withoutCause, NestableException.class, 0));
276 assertEquals(0, ExceptionUtils.indexOfThrowable(withoutCause, ExceptionWithoutCause.class, 0));
277
278 assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, null, 0));
279 assertEquals(-1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithCause.class, 0));
280 assertEquals(0, ExceptionUtils.indexOfThrowable(nested, NestableException.class, 0));
281 assertEquals(1, ExceptionUtils.indexOfThrowable(nested, ExceptionWithoutCause.class, 0));
282
283 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, null));
284 assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 0));
285 assertEquals(1, ExceptionUtils.indexOfThrowable(withCause, NestableException.class, 0));
286 assertEquals(2, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithoutCause.class, 0));
287
288 assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, -1));
289 assertEquals(0, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 0));
290 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 1));
291 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, ExceptionWithCause.class, 9));
292
293 assertEquals(-1, ExceptionUtils.indexOfThrowable(withCause, Exception.class, 0));
294 }
295
296 //-----------------------------------------------------------------------
297 public void testIndexOfType_ThrowableClass() {
298 assertEquals(-1, ExceptionUtils.indexOfType(null, null));
299 assertEquals(-1, ExceptionUtils.indexOfType(null, NestableException.class));
300
301 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, null));
302 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, ExceptionWithCause.class));
303 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, NestableException.class));
304 assertEquals(0, ExceptionUtils.indexOfType(withoutCause, ExceptionWithoutCause.class));
305
306 assertEquals(-1, ExceptionUtils.indexOfType(nested, null));
307 assertEquals(-1, ExceptionUtils.indexOfType(nested, ExceptionWithCause.class));
308 assertEquals(0, ExceptionUtils.indexOfType(nested, NestableException.class));
309 assertEquals(1, ExceptionUtils.indexOfType(nested, ExceptionWithoutCause.class));
310
311 assertEquals(-1, ExceptionUtils.indexOfType(withCause, null));
312 assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class));
313 assertEquals(1, ExceptionUtils.indexOfType(withCause, NestableException.class));
314 assertEquals(2, ExceptionUtils.indexOfType(withCause, ExceptionWithoutCause.class));
315
316 assertEquals(0, ExceptionUtils.indexOfType(withCause, Exception.class));
317 }
318
319 public void testIndexOfType_ThrowableClassInt() {
320 assertEquals(-1, ExceptionUtils.indexOfType(null, null, 0));
321 assertEquals(-1, ExceptionUtils.indexOfType(null, NestableException.class, 0));
322
323 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, null));
324 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, ExceptionWithCause.class, 0));
325 assertEquals(-1, ExceptionUtils.indexOfType(withoutCause, NestableException.class, 0));
326 assertEquals(0, ExceptionUtils.indexOfType(withoutCause, ExceptionWithoutCause.class, 0));
327
328 assertEquals(-1, ExceptionUtils.indexOfType(nested, null, 0));
329 assertEquals(-1, ExceptionUtils.indexOfType(nested, ExceptionWithCause.class, 0));
330 assertEquals(0, ExceptionUtils.indexOfType(nested, NestableException.class, 0));
331 assertEquals(1, ExceptionUtils.indexOfType(nested, ExceptionWithoutCause.class, 0));
332
333 assertEquals(-1, ExceptionUtils.indexOfType(withCause, null));
334 assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 0));
335 assertEquals(1, ExceptionUtils.indexOfType(withCause, NestableException.class, 0));
336 assertEquals(2, ExceptionUtils.indexOfType(withCause, ExceptionWithoutCause.class, 0));
337
338 assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, -1));
339 assertEquals(0, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 0));
340 assertEquals(-1, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 1));
341 assertEquals(-1, ExceptionUtils.indexOfType(withCause, ExceptionWithCause.class, 9));
342
343 assertEquals(0, ExceptionUtils.indexOfType(withCause, Exception.class, 0));
344 }
345
346 //-----------------------------------------------------------------------
347 public void testPrintRootCauseStackTrace_Throwable() throws Exception {
348 ExceptionUtils.printRootCauseStackTrace(null);
349 // could pipe system.err to a known stream, but not much point as
350 // internally this method calls stram method anyway
351 }
352
353 public void testPrintRootCauseStackTrace_ThrowableStream() throws Exception {
354 ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
355 ExceptionUtils.printRootCauseStackTrace(null, (PrintStream) null);
356 ExceptionUtils.printRootCauseStackTrace(null, new PrintStream(out));
357 assertEquals(0, out.toString().length());
358
359 out = new ByteArrayOutputStream(1024);
360 try {
361 ExceptionUtils.printRootCauseStackTrace(withCause, (PrintStream) null);
362 fail();
363 } catch (IllegalArgumentException ex) {
364 }
365
366 out = new ByteArrayOutputStream(1024);
367 Throwable withCause = createExceptionWithCause();
368 ExceptionUtils.printRootCauseStackTrace(withCause, new PrintStream(out));
369 String stackTrace = out.toString();
370 assertTrue(stackTrace.indexOf(ExceptionUtils.WRAPPED_MARKER) != -1);
371
372 out = new ByteArrayOutputStream(1024);
373 ExceptionUtils.printRootCauseStackTrace(withoutCause, new PrintStream(out));
374 stackTrace = out.toString();
375 assertTrue(stackTrace.indexOf(ExceptionUtils.WRAPPED_MARKER) == -1);
376 }
377
378 public void testPrintRootCauseStackTrace_ThrowableWriter() throws Exception {
379 StringWriter writer = new StringWriter(1024);
380 ExceptionUtils.printRootCauseStackTrace(null, (PrintWriter) null);
381 ExceptionUtils.printRootCauseStackTrace(null, new PrintWriter(writer));
382 assertEquals(0, writer.getBuffer().length());
383
384 writer = new StringWriter(1024);
385 try {
386 ExceptionUtils.printRootCauseStackTrace(withCause, (PrintWriter) null);
387 fail();
388 } catch (IllegalArgumentException ex) {
389 }
390
391 writer = new StringWriter(1024);
392 Throwable withCause = createExceptionWithCause();
393 ExceptionUtils.printRootCauseStackTrace(withCause, new PrintWriter(writer));
394 String stackTrace = writer.toString();
395 assertTrue(stackTrace.indexOf(ExceptionUtils.WRAPPED_MARKER) != -1);
396
397 writer = new StringWriter(1024);
398 ExceptionUtils.printRootCauseStackTrace(withoutCause, new PrintWriter(writer));
399 stackTrace = writer.toString();
400 assertTrue(stackTrace.indexOf(ExceptionUtils.WRAPPED_MARKER) == -1);
401 }
402
403 //-----------------------------------------------------------------------
404 public void testGetRootCauseStackTrace_Throwable() throws Exception {
405 assertEquals(0, ExceptionUtils.getRootCauseStackTrace(null).length);
406
407 Throwable withCause = createExceptionWithCause();
408 String[] stackTrace = ExceptionUtils.getRootCauseStackTrace(withCause);
409 boolean match = false;
410 for (String element : stackTrace) {
411 if (element.startsWith(ExceptionUtils.WRAPPED_MARKER)) {
412 match = true;
413 break;
414 }
415 }
416 assertEquals(true, match);
417
418 stackTrace = ExceptionUtils.getRootCauseStackTrace(withoutCause);
419 match = false;
420 for (String element : stackTrace) {
421 if (element.startsWith(ExceptionUtils.WRAPPED_MARKER)) {
422 match = true;
423 break;
424 }
425 }
426 assertEquals(false, match);
427 }
428
429 public void testRemoveCommonFrames_ListList() throws Exception {
430 try {
431 ExceptionUtils.removeCommonFrames(null, null);
432 fail();
433 } catch (IllegalArgumentException ex) {
434 }
435 }
436
437 public void test_getMessage_Throwable() {
438 Throwable th = null;
439 assertEquals("", ExceptionUtils.getMessage(th));
440
441 th = new IllegalArgumentException("Base");
442 assertEquals("IllegalArgumentException: Base", ExceptionUtils.getMessage(th));
443
444 th = new ExceptionWithCause("Wrapper", th);
445 assertEquals("ExceptionUtilsTest.ExceptionWithCause: Wrapper", ExceptionUtils.getMessage(th));
446 }
447
448 public void test_getRootCauseMessage_Throwable() {
449 Throwable th = null;
450 assertEquals("", ExceptionUtils.getRootCauseMessage(th));
451
452 th = new IllegalArgumentException("Base");
453 assertEquals("IllegalArgumentException: Base", ExceptionUtils.getRootCauseMessage(th));
454
455 th = new ExceptionWithCause("Wrapper", th);
456 assertEquals("IllegalArgumentException: Base", ExceptionUtils.getRootCauseMessage(th));
457 }
458
459 //-----------------------------------------------------------------------
460 /**
461 * Provides a method with a well known chained/nested exception
462 * name which matches the full signature (e.g. has a return value
463 * of <code>Throwable</code>.
464 */
465 private static class ExceptionWithCause extends Exception {
466 private Throwable cause;
467
468 public ExceptionWithCause(String str, Throwable cause) {
469 super(str);
470 setCause(cause);
471 }
472
473 public ExceptionWithCause(Throwable cause) {
474 super();
475 setCause(cause);
476 }
477
478 @Override
479 public Throwable getCause() {
480 return cause;
481 }
482
483 public void setCause(Throwable cause) {
484 this.cause = cause;
485 }
486 }
487
488 /**
489 * Provides a method with a well known chained/nested exception
490 * name which does not match the full signature (e.g. lacks a
491 * return value of <code>Throwable</code>.
492 */
493 private static class ExceptionWithoutCause extends Exception {
494 @SuppressWarnings("unused")
495 public void getTargetException() {
496 }
497 }
498
499 // Temporary classes to allow the nested exception code to be removed
500 // prior to a rewrite of this test class.
501 private static class NestableException extends Exception {
502 @SuppressWarnings("unused")
503 public NestableException() { super(); }
504 public NestableException(Throwable t) { super(t); }
505 }
506
507 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one
2 * or more contributor license agreements. See the NOTICE file
3 * distributed with this work for additional information
4 * regarding copyright ownership. The ASF licenses this file
5 * to you under the Apache License, Version 2.0 (the
6 * "License"); you may not use this file except in compliance
7 * with the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 package org.apache.commons.lang3.math;
19
20 import junit.framework.TestCase;
21
22 /**
23 * Test cases for the {@link Fraction} class
24 *
25 * @version $Id: FractionTest.java 1153484 2011-08-03 13:39:42Z ggregory $
26 */
27 public class FractionTest extends TestCase {
28
29 private static final int SKIP = 500; //53
30
31 public FractionTest(String name) {
32 super(name);
33 }
34
35 //--------------------------------------------------------------------------
36
37 public void testConstants() {
38 assertEquals(0, Fraction.ZERO.getNumerator());
39 assertEquals(1, Fraction.ZERO.getDenominator());
40
41 assertEquals(1, Fraction.ONE.getNumerator());
42 assertEquals(1, Fraction.ONE.getDenominator());
43
44 assertEquals(1, Fraction.ONE_HALF.getNumerator());
45 assertEquals(2, Fraction.ONE_HALF.getDenominator());
46
47 assertEquals(1, Fraction.ONE_THIRD.getNumerator());
48 assertEquals(3, Fraction.ONE_THIRD.getDenominator());
49
50 assertEquals(2, Fraction.TWO_THIRDS.getNumerator());
51 assertEquals(3, Fraction.TWO_THIRDS.getDenominator());
52
53 assertEquals(1, Fraction.ONE_QUARTER.getNumerator());
54 assertEquals(4, Fraction.ONE_QUARTER.getDenominator());
55
56 assertEquals(2, Fraction.TWO_QUARTERS.getNumerator());
57 assertEquals(4, Fraction.TWO_QUARTERS.getDenominator());
58
59 assertEquals(3, Fraction.THREE_QUARTERS.getNumerator());
60 assertEquals(4, Fraction.THREE_QUARTERS.getDenominator());
61
62 assertEquals(1, Fraction.ONE_FIFTH.getNumerator());
63 assertEquals(5, Fraction.ONE_FIFTH.getDenominator());
64
65 assertEquals(2, Fraction.TWO_FIFTHS.getNumerator());
66 assertEquals(5, Fraction.TWO_FIFTHS.getDenominator());
67
68 assertEquals(3, Fraction.THREE_FIFTHS.getNumerator());
69 assertEquals(5, Fraction.THREE_FIFTHS.getDenominator());
70
71 assertEquals(4, Fraction.FOUR_FIFTHS.getNumerator());
72 assertEquals(5, Fraction.FOUR_FIFTHS.getDenominator());
73 }
74
75 public void testFactory_int_int() {
76 Fraction f = null;
77
78 // zero
79 f = Fraction.getFraction(0, 1);
80 assertEquals(0, f.getNumerator());
81 assertEquals(1, f.getDenominator());
82
83 f = Fraction.getFraction(0, 2);
84 assertEquals(0, f.getNumerator());
85 assertEquals(2, f.getDenominator());
86
87 // normal
88 f = Fraction.getFraction(1, 1);
89 assertEquals(1, f.getNumerator());
90 assertEquals(1, f.getDenominator());
91
92 f = Fraction.getFraction(2, 1);
93 assertEquals(2, f.getNumerator());
94 assertEquals(1, f.getDenominator());
95
96 f = Fraction.getFraction(23, 345);
97 assertEquals(23, f.getNumerator());
98 assertEquals(345, f.getDenominator());
99
100 // improper
101 f = Fraction.getFraction(22, 7);
102 assertEquals(22, f.getNumerator());
103 assertEquals(7, f.getDenominator());
104
105 // negatives
106 f = Fraction.getFraction(-6, 10);
107 assertEquals(-6, f.getNumerator());
108 assertEquals(10, f.getDenominator());
109
110 f = Fraction.getFraction(6, -10);
111 assertEquals(-6, f.getNumerator());
112 assertEquals(10, f.getDenominator());
113
114 f = Fraction.getFraction(-6, -10);
115 assertEquals(6, f.getNumerator());
116 assertEquals(10, f.getDenominator());
117
118 // zero denominator
119 try {
120 f = Fraction.getFraction(1, 0);
121 fail("expecting ArithmeticException");
122 } catch (ArithmeticException ex) {}
123
124 try {
125 f = Fraction.getFraction(2, 0);
126 fail("expecting ArithmeticException");
127 } catch (ArithmeticException ex) {}
128
129 try {
130 f = Fraction.getFraction(-3, 0);
131 fail("expecting ArithmeticException");
132 } catch (ArithmeticException ex) {}
133
134 // very large: can't represent as unsimplified fraction, although
135 try {
136 f = Fraction.getFraction(4, Integer.MIN_VALUE);
137 fail("expecting ArithmeticException");
138 } catch (ArithmeticException ex) {}
139 try {
140 f = Fraction.getFraction(1, Integer.MIN_VALUE);
141 fail("expecting ArithmeticException");
142 } catch (ArithmeticException ex) {}
143 }
144
145 public void testFactory_int_int_int() {
146 Fraction f = null;
147
148 // zero
149 f = Fraction.getFraction(0, 0, 2);
150 assertEquals(0, f.getNumerator());
151 assertEquals(2, f.getDenominator());
152
153 f = Fraction.getFraction(2, 0, 2);
154 assertEquals(4, f.getNumerator());
155 assertEquals(2, f.getDenominator());
156
157 f = Fraction.getFraction(0, 1, 2);
158 assertEquals(1, f.getNumerator());
159 assertEquals(2, f.getDenominator());
160
161 // normal
162 f = Fraction.getFraction(1, 1, 2);
163 assertEquals(3, f.getNumerator());
164 assertEquals(2, f.getDenominator());
165
166 // negatives
167 try {
168 f = Fraction.getFraction(1, -6, -10);
169 fail("expecting ArithmeticException");
170 } catch (ArithmeticException ex) {}
171
172 try {
173 f = Fraction.getFraction(1, -6, -10);
174 fail("expecting ArithmeticException");
175 } catch (ArithmeticException ex) {}
176
177 try {
178 f = Fraction.getFraction(1, -6, -10);
179 fail("expecting ArithmeticException");
180 } catch (ArithmeticException ex) {}
181
182 // negative whole
183 f = Fraction.getFraction(-1, 6, 10);
184 assertEquals(-16, f.getNumerator());
185 assertEquals(10, f.getDenominator());
186
187 try {
188 f = Fraction.getFraction(-1, -6, 10);
189 fail("expecting ArithmeticException");
190 } catch (ArithmeticException ex) {}
191
192 try {
193 f = Fraction.getFraction(-1, 6, -10);
194 fail("expecting ArithmeticException");
195 } catch (ArithmeticException ex) {}
196
197 try {
198 f = Fraction.getFraction(-1, -6, -10);
199 fail("expecting ArithmeticException");
200 } catch (ArithmeticException ex) {}
201
202 // zero denominator
203 try {
204 f = Fraction.getFraction(0, 1, 0);
205 fail("expecting ArithmeticException");
206 } catch (ArithmeticException ex) {}
207
208 try {
209 f = Fraction.getFraction(1, 2, 0);
210 fail("expecting ArithmeticException");
211 } catch (ArithmeticException ex) {}
212
213 try {
214 f = Fraction.getFraction(-1, -3, 0);
215 fail("expecting ArithmeticException");
216 } catch (ArithmeticException ex) {}
217
218 try {
219 f = Fraction.getFraction(Integer.MAX_VALUE, 1, 2);
220 fail("expecting ArithmeticException");
221 } catch (ArithmeticException ex) {}
222
223 try {
224 f = Fraction.getFraction(-Integer.MAX_VALUE, 1, 2);
225 fail("expecting ArithmeticException");
226 } catch (ArithmeticException ex) {}
227
228 // very large
229 f = Fraction.getFraction(-1, 0, Integer.MAX_VALUE);
230 assertEquals(-Integer.MAX_VALUE, f.getNumerator());
231 assertEquals(Integer.MAX_VALUE, f.getDenominator());
232
233 try {
234 // negative denominators not allowed in this constructor.
235 f = Fraction.getFraction(0, 4, Integer.MIN_VALUE);
236 fail("expecting ArithmeticException");
237 } catch (ArithmeticException ex) {}
238 try {
239 f = Fraction.getFraction(1, 1, Integer.MAX_VALUE);
240 fail("expecting ArithmeticException");
241 } catch (ArithmeticException ex) {}
242 try {
243 f = Fraction.getFraction(-1, 2, Integer.MAX_VALUE);
244 fail("expecting ArithmeticException");
245 } catch (ArithmeticException ex) {}
246 }
247 public void testReducedFactory_int_int() {
248 Fraction f = null;
249
250 // zero
251 f = Fraction.getReducedFraction(0, 1);
252 assertEquals(0, f.getNumerator());
253 assertEquals(1, f.getDenominator());
254
255 // normal
256 f = Fraction.getReducedFraction(1, 1);
257 assertEquals(1, f.getNumerator());
258 assertEquals(1, f.getDenominator());
259
260 f = Fraction.getReducedFraction(2, 1);
261 assertEquals(2, f.getNumerator());
262 assertEquals(1, f.getDenominator());
263
264 // improper
265 f = Fraction.getReducedFraction(22, 7);
266 assertEquals(22, f.getNumerator());
267 assertEquals(7, f.getDenominator());
268
269 // negatives
270 f = Fraction.getReducedFraction(-6, 10);
271 assertEquals(-3, f.getNumerator());
272 assertEquals(5, f.getDenominator());
273
274 f = Fraction.getReducedFraction(6, -10);
275 assertEquals(-3, f.getNumerator());
276 assertEquals(5, f.getDenominator());
277
278 f = Fraction.getReducedFraction(-6, -10);
279 assertEquals(3, f.getNumerator());
280 assertEquals(5, f.getDenominator());
281
282 // zero denominator
283 try {
284 f = Fraction.getReducedFraction(1, 0);
285 fail("expecting ArithmeticException");
286 } catch (ArithmeticException ex) {}
287
288 try {
289 f = Fraction.getReducedFraction(2, 0);
290 fail("expecting ArithmeticException");
291 } catch (ArithmeticException ex) {}
292
293 try {
294 f = Fraction.getReducedFraction(-3, 0);
295 fail("expecting ArithmeticException");
296 } catch (ArithmeticException ex) {}
297
298 // reduced
299 f = Fraction.getReducedFraction(0, 2);
300 assertEquals(0, f.getNumerator());
301 assertEquals(1, f.getDenominator());
302
303 f = Fraction.getReducedFraction(2, 2);
304 assertEquals(1, f.getNumerator());
305 assertEquals(1, f.getDenominator());
306
307 f = Fraction.getReducedFraction(2, 4);
308 assertEquals(1, f.getNumerator());
309 assertEquals(2, f.getDenominator());
310
311 f = Fraction.getReducedFraction(15, 10);
312 assertEquals(3, f.getNumerator());
313 assertEquals(2, f.getDenominator());
314
315 f = Fraction.getReducedFraction(121, 22);
316 assertEquals(11, f.getNumerator());
317 assertEquals(2, f.getDenominator());
318
319 // Extreme values
320 // OK, can reduce before negating
321 f = Fraction.getReducedFraction(-2, Integer.MIN_VALUE);
322 assertEquals(1, f.getNumerator());
323 assertEquals(-(Integer.MIN_VALUE / 2), f.getDenominator());
324
325 // Can't reduce, negation will throw
326 try {
327 f = Fraction.getReducedFraction(-7, Integer.MIN_VALUE);
328 fail("Expecting ArithmeticException");
329 } catch (ArithmeticException ex) {}
330
331 // LANG-662
332 f = Fraction.getReducedFraction(Integer.MIN_VALUE, 2);
333 assertEquals(Integer.MIN_VALUE / 2, f.getNumerator());
334 assertEquals(1, f.getDenominator());
335 }
336
337 public void testFactory_double() {
338 Fraction f = null;
339
340 try {
341 f = Fraction.getFraction(Double.NaN);
342 fail("expecting ArithmeticException");
343 } catch (ArithmeticException ex) {}
344
345 try {
346 f = Fraction.getFraction(Double.POSITIVE_INFINITY);
347 fail("expecting ArithmeticException");
348 } catch (ArithmeticException ex) {}
349
350 try {
351 f = Fraction.getFraction(Double.NEGATIVE_INFINITY);
352 fail("expecting ArithmeticException");
353 } catch (ArithmeticException ex) {}
354
355 try {
356 f = Fraction.getFraction((double) Integer.MAX_VALUE + 1);
357 fail("expecting ArithmeticException");
358 } catch (ArithmeticException ex) {}
359
360 // zero
361 f = Fraction.getFraction(0.0d);
362 assertEquals(0, f.getNumerator());
363 assertEquals(1, f.getDenominator());
364
365 // one
366 f = Fraction.getFraction(1.0d);
367 assertEquals(1, f.getNumerator());
368 assertEquals(1, f.getDenominator());
369
370 // one half
371 f = Fraction.getFraction(0.5d);
372 assertEquals(1, f.getNumerator());
373 assertEquals(2, f.getDenominator());
374
375 // negative
376 f = Fraction.getFraction(-0.875d);
377 assertEquals(-7, f.getNumerator());
378 assertEquals(8, f.getDenominator());
379
380 // over 1
381 f = Fraction.getFraction(1.25d);
382 assertEquals(5, f.getNumerator());
383 assertEquals(4, f.getDenominator());
384
385 // two thirds
386 f = Fraction.getFraction(0.66666d);
387 assertEquals(2, f.getNumerator());
388 assertEquals(3, f.getDenominator());
389
390 // small
391 f = Fraction.getFraction(1.0d/10001d);
392 assertEquals(0, f.getNumerator());
393 assertEquals(1, f.getDenominator());
394
395 // normal
396 Fraction f2 = null;
397 for (int i = 1; i <= 100; i++) { // denominator
398 for (int j = 1; j <= i; j++) { // numerator
399 try {
400 f = Fraction.getFraction((double) j / (double) i);
401 } catch (ArithmeticException ex) {
402 System.err.println(j + " " + i);
403 throw ex;
404 }
405 f2 = Fraction.getReducedFraction(j, i);
406 assertEquals(f2.getNumerator(), f.getNumerator());
407 assertEquals(f2.getDenominator(), f.getDenominator());
408 }
409 }
410 // save time by skipping some tests! (
411 for (int i = 1001; i <= 10000; i+=SKIP) { // denominator
412 for (int j = 1; j <= i; j++) { // numerator
413 try {
414 f = Fraction.getFraction((double) j / (double) i);
415 } catch (ArithmeticException ex) {
416 System.err.println(j + " " + i);
417 throw ex;
418 }
419 f2 = Fraction.getReducedFraction(j, i);
420 assertEquals(f2.getNumerator(), f.getNumerator());
421 assertEquals(f2.getDenominator(), f.getDenominator());
422 }
423 }
424 }
425
426 public void testFactory_String() {
427 try {
428 Fraction.getFraction(null);
429 fail("expecting IllegalArgumentException");
430 } catch (IllegalArgumentException ex) {}
431 }
432
433
434 public void testFactory_String_double() {
435 Fraction f = null;
436
437 f = Fraction.getFraction("0.0");
438 assertEquals(0, f.getNumerator());
439 assertEquals(1, f.getDenominator());
440
441 f = Fraction.getFraction("0.2");
442 assertEquals(1, f.getNumerator());
443 assertEquals(5, f.getDenominator());
444
445 f = Fraction.getFraction("0.5");
446 assertEquals(1, f.getNumerator());
447 assertEquals(2, f.getDenominator());
448
449 f = Fraction.getFraction("0.66666");
450 assertEquals(2, f.getNumerator());
451 assertEquals(3, f.getDenominator());
452
453 try {
454 f = Fraction.getFraction("2.3R");
455 fail("Expecting NumberFormatException");
456 } catch (NumberFormatException ex) {}
457
458 try {
459 f = Fraction.getFraction("2147483648"); // too big
460 fail("Expecting NumberFormatException");
461 } catch (NumberFormatException ex) {}
462
463 try {
464 f = Fraction.getFraction(".");
465 fail("Expecting NumberFormatException");
466 } catch (NumberFormatException ex) {}
467 }
468
469 public void testFactory_String_proper() {
470 Fraction f = null;
471
472 f = Fraction.getFraction("0 0/1");
473 assertEquals(0, f.getNumerator());
474 assertEquals(1, f.getDenominator());
475
476 f = Fraction.getFraction("1 1/5");
477 assertEquals(6, f.getNumerator());
478 assertEquals(5, f.getDenominator());
479
480 f = Fraction.getFraction("7 1/2");
481 assertEquals(15, f.getNumerator());
482 assertEquals(2, f.getDenominator());
483
484 f = Fraction.getFraction("1 2/4");
485 assertEquals(6, f.getNumerator());
486 assertEquals(4, f.getDenominator());
487
488 f = Fraction.getFraction("-7 1/2");
489 assertEquals(-15, f.getNumerator());
490 assertEquals(2, f.getDenominator());
491
492 f = Fraction.getFraction("-1 2/4");
493 assertEquals(-6, f.getNumerator());
494 assertEquals(4, f.getDenominator());
495
496 try {
497 f = Fraction.getFraction("2 3");
498 fail("expecting NumberFormatException");
499 } catch (NumberFormatException ex) {}
500
501 try {
502 f = Fraction.getFraction("a 3");
503 fail("expecting NumberFormatException");
504 } catch (NumberFormatException ex) {}
505
506 try {
507 f = Fraction.getFraction("2 b/4");
508 fail("expecting NumberFormatException");
509 } catch (NumberFormatException ex) {}
510
511 try {
512 f = Fraction.getFraction("2 ");
513 fail("expecting NumberFormatException");
514 } catch (NumberFormatException ex) {}
515
516 try {
517 f = Fraction.getFraction(" 3");
518 fail("expecting NumberFormatException");
519 } catch (NumberFormatException ex) {}
520
521 try {
522 f = Fraction.getFraction(" ");
523 fail("expecting NumberFormatException");
524 } catch (NumberFormatException ex) {}
525 }
526
527 public void testFactory_String_improper() {
528 Fraction f = null;
529
530 f = Fraction.getFraction("0/1");
531 assertEquals(0, f.getNumerator());
532 assertEquals(1, f.getDenominator());
533
534 f = Fraction.getFraction("1/5");
535 assertEquals(1, f.getNumerator());
536 assertEquals(5, f.getDenominator());
537
538 f = Fraction.getFraction("1/2");
539 assertEquals(1, f.getNumerator());
540 assertEquals(2, f.getDenominator());
541
542 f = Fraction.getFraction("2/3");
543 assertEquals(2, f.getNumerator());
544 assertEquals(3, f.getDenominator());
545
546 f = Fraction.getFraction("7/3");
547 assertEquals(7, f.getNumerator());
548 assertEquals(3, f.getDenominator());
549
550 f = Fraction.getFraction("2/4");
551 assertEquals(2, f.getNumerator());
552 assertEquals(4, f.getDenominator());
553
554 try {
555 f = Fraction.getFraction("2/d");
556 fail("expecting NumberFormatException");
557 } catch (NumberFormatException ex) {}
558
559 try {
560 f = Fraction.getFraction("2e/3");
561 fail("expecting NumberFormatException");
562 } catch (NumberFormatException ex) {}
563
564 try {
565 f = Fraction.getFraction("2/");
566 fail("expecting NumberFormatException");
567 } catch (NumberFormatException ex) {}
568
569 try {
570 f = Fraction.getFraction("/");
571 fail("expecting NumberFormatException");
572 } catch (NumberFormatException ex) {}
573 }
574
575 public void testGets() {
576 Fraction f = null;
577
578 f = Fraction.getFraction(3, 5, 6);
579 assertEquals(23, f.getNumerator());
580 assertEquals(3, f.getProperWhole());
581 assertEquals(5, f.getProperNumerator());
582 assertEquals(6, f.getDenominator());
583
584 f = Fraction.getFraction(-3, 5, 6);
585 assertEquals(-23, f.getNumerator());
586 assertEquals(-3, f.getProperWhole());
587 assertEquals(5, f.getProperNumerator());
588 assertEquals(6, f.getDenominator());
589
590 f = Fraction.getFraction(Integer.MIN_VALUE, 0, 1);
591 assertEquals(Integer.MIN_VALUE, f.getNumerator());
592 assertEquals(Integer.MIN_VALUE, f.getProperWhole());
593 assertEquals(0, f.getProperNumerator());
594 assertEquals(1, f.getDenominator());
595 }
596
597 public void testConversions() {
598 Fraction f = null;
599
600 f = Fraction.getFraction(3, 7, 8);
601 assertEquals(3, f.intValue());
602 assertEquals(3L, f.longValue());
603 assertEquals(3.875f, f.floatValue(), 0.00001f);
604 assertEquals(3.875d, f.doubleValue(), 0.00001d);
605 }
606
607 public void testReduce() {
608 Fraction f = null;
609
610 f = Fraction.getFraction(50, 75);
611 Fraction result = f.reduce();
612 assertEquals(2, result.getNumerator());
613 assertEquals(3, result.getDenominator());
614
615 f = Fraction.getFraction(-2, -3);
616 result = f.reduce();
617 assertEquals(2, result.getNumerator());
618 assertEquals(3, result.getDenominator());
619
620 f = Fraction.getFraction(2, -3);
621 result = f.reduce();
622 assertEquals(-2, result.getNumerator());
623 assertEquals(3, result.getDenominator());
624
625 f = Fraction.getFraction(-2, 3);
626 result = f.reduce();
627 assertEquals(-2, result.getNumerator());
628 assertEquals(3, result.getDenominator());
629 assertSame(f, result);
630
631 f = Fraction.getFraction(2, 3);
632 result = f.reduce();
633 assertEquals(2, result.getNumerator());
634 assertEquals(3, result.getDenominator());
635 assertSame(f, result);
636
637 f = Fraction.getFraction(0, 1);
638 result = f.reduce();
639 assertEquals(0, result.getNumerator());
640 assertEquals(1, result.getDenominator());
641 assertSame(f, result);
642
643 f = Fraction.getFraction(0, 100);
644 result = f.reduce();
645 assertEquals(0, result.getNumerator());
646 assertEquals(1, result.getDenominator());
647 assertSame(result, Fraction.ZERO);
648
649 f = Fraction.getFraction(Integer.MIN_VALUE, 2);
650 result = f.reduce();
651 assertEquals(Integer.MIN_VALUE / 2, result.getNumerator());
652 assertEquals(1, result.getDenominator());
653 }
654
655 public void testInvert() {
656 Fraction f = null;
657
658 f = Fraction.getFraction(50, 75);
659 f = f.invert();
660 assertEquals(75, f.getNumerator());
661 assertEquals(50, f.getDenominator());
662
663 f = Fraction.getFraction(4, 3);
664 f = f.invert();
665 assertEquals(3, f.getNumerator());
666 assertEquals(4, f.getDenominator());
667
668 f = Fraction.getFraction(-15, 47);
669 f = f.invert();
670 assertEquals(-47, f.getNumerator());
671 assertEquals(15, f.getDenominator());
672
673 f = Fraction.getFraction(0, 3);
674 try {
675 f = f.invert();
676 fail("expecting ArithmeticException");
677 } catch (ArithmeticException ex) {}
678
679 // large values
680 f = Fraction.getFraction(Integer.MIN_VALUE, 1);
681 try {
682 f = f.invert();
683 fail("expecting ArithmeticException");
684 } catch (ArithmeticException ex) {}
685
686 f = Fraction.getFraction(Integer.MAX_VALUE, 1);
687 f = f.invert();
688 assertEquals(1, f.getNumerator());
689 assertEquals(Integer.MAX_VALUE, f.getDenominator());
690 }
691
692 public void testNegate() {
693 Fraction f = null;
694
695 f = Fraction.getFraction(50, 75);
696 f = f.negate();
697 assertEquals(-50, f.getNumerator());
698 assertEquals(75, f.getDenominator());
699
700 f = Fraction.getFraction(-50, 75);
701 f = f.negate();
702 assertEquals(50, f.getNumerator());
703 assertEquals(75, f.getDenominator());
704
705 // large values
706 f = Fraction.getFraction(Integer.MAX_VALUE-1, Integer.MAX_VALUE);
707 f = f.negate();
708 assertEquals(Integer.MIN_VALUE+2, f.getNumerator());
709 assertEquals(Integer.MAX_VALUE, f.getDenominator());
710
711 f = Fraction.getFraction(Integer.MIN_VALUE, 1);
712 try {
713 f = f.negate();
714 fail("expecting ArithmeticException");
715 } catch (ArithmeticException ex) {}
716 }
717
718 public void testAbs() {
719 Fraction f = null;
720
721 f = Fraction.getFraction(50, 75);
722 f = f.abs();
723 assertEquals(50, f.getNumerator());
724 assertEquals(75, f.getDenominator());
725
726 f = Fraction.getFraction(-50, 75);
727 f = f.abs();
728 assertEquals(50, f.getNumerator());
729 assertEquals(75, f.getDenominator());
730
731 f = Fraction.getFraction(Integer.MAX_VALUE, 1);
732 f = f.abs();
733 assertEquals(Integer.MAX_VALUE, f.getNumerator());
734 assertEquals(1, f.getDenominator());
735
736 f = Fraction.getFraction(Integer.MAX_VALUE, -1);
737 f = f.abs();
738 assertEquals(Integer.MAX_VALUE, f.getNumerator());
739 assertEquals(1, f.getDenominator());
740
741 f = Fraction.getFraction(Integer.MIN_VALUE, 1);
742 try {
743 f = f.abs();
744 fail("expecting ArithmeticException");
745 } catch (ArithmeticException ex) {}
746 }
747
748 public void testPow() {
749 Fraction f = null;
750
751 f = Fraction.getFraction(3, 5);
752 assertEquals(Fraction.ONE, f.pow(0));
753
754 f = Fraction.getFraction(3, 5);
755 assertSame(f, f.pow(1));
756 assertEquals(f, f.pow(1));
757
758 f = Fraction.getFraction(3, 5);
759 f = f.pow(2);
760 assertEquals(9, f.getNumerator());
761 assertEquals(25, f.getDenominator());
762
763 f = Fraction.getFraction(3, 5);
764 f = f.pow(3);
765 assertEquals(27, f.getNumerator());
766 assertEquals(125, f.getDenominator());
767
768 f = Fraction.getFraction(3, 5);
769 f = f.pow(-1);
770 assertEquals(5, f.getNumerator());
771 assertEquals(3, f.getDenominator());
772
773 f = Fraction.getFraction(3, 5);
774 f = f.pow(-2);
775 assertEquals(25, f.getNumerator());
776 assertEquals(9, f.getDenominator());
777
778 // check unreduced fractions stay that way.
779 f = Fraction.getFraction(6, 10);
780 assertEquals(Fraction.ONE, f.pow(0));
781
782 f = Fraction.getFraction(6, 10);
783 assertEquals(f, f.pow(1));
784 assertFalse(f.pow(1).equals(Fraction.getFraction(3,5)));
785
786 f = Fraction.getFraction(6, 10);
787 f = f.pow(2);
788 assertEquals(9, f.getNumerator());
789 assertEquals(25, f.getDenominator());
790
791 f = Fraction.getFraction(6, 10);
792 f = f.pow(3);
793 assertEquals(27, f.getNumerator());
794 assertEquals(125, f.getDenominator());
795
796 f = Fraction.getFraction(6, 10);
797 f = f.pow(-1);
798 assertEquals(10, f.getNumerator());
799 assertEquals(6, f.getDenominator());
800
801 f = Fraction.getFraction(6, 10);
802 f = f.pow(-2);
803 assertEquals(25, f.getNumerator());
804 assertEquals(9, f.getDenominator());
805
806 // zero to any positive power is still zero.
807 f = Fraction.getFraction(0, 1231);
808 f = f.pow(1);
809 assertTrue(0==f.compareTo(Fraction.ZERO));
810 assertEquals(0, f.getNumerator());
811 assertEquals(1231, f.getDenominator());
812 f = f.pow(2);
813 assertTrue(0==f.compareTo(Fraction.ZERO));
814 assertEquals(0, f.getNumerator());
815 assertEquals(1, f.getDenominator());
816
817 // zero to negative powers should throw an exception
818 try {
819 f = f.pow(-1);
820 fail("expecting ArithmeticException");
821 } catch (ArithmeticException ex) {}
822 try {
823 f = f.pow(Integer.MIN_VALUE);
824 fail("expecting ArithmeticException");
825 } catch (ArithmeticException ex) {}
826
827 // one to any power is still one.
828 f = Fraction.getFraction(1, 1);
829 f = f.pow(0);
830 assertEquals(f, Fraction.ONE);
831 f = f.pow(1);
832 assertEquals(f, Fraction.ONE);
833 f = f.pow(-1);
834 assertEquals(f, Fraction.ONE);
835 f = f.pow(Integer.MAX_VALUE);
836 assertEquals(f, Fraction.ONE);
837 f = f.pow(Integer.MIN_VALUE);
838 assertEquals(f, Fraction.ONE);
839
840 f = Fraction.getFraction(Integer.MAX_VALUE, 1);
841 try {
842 f = f.pow(2);
843 fail("expecting ArithmeticException");
844 } catch (ArithmeticException ex) {}
845
846 // Numerator growing too negative during the pow operation.
847 f = Fraction.getFraction(Integer.MIN_VALUE, 1);
848 try {
849 f = f.pow(3);
850 fail("expecting ArithmeticException");
851 } catch (ArithmeticException ex) {}
852
853 f = Fraction.getFraction(65536, 1);
854 try {
855 f = f.pow(2);
856 fail("expecting ArithmeticException");
857 } catch (ArithmeticException ex) {}
858 }
859
860 public void testAdd() {
861 Fraction f = null;
862 Fraction f1 = null;
863 Fraction f2 = null;
864
865 f1 = Fraction.getFraction(3, 5);
866 f2 = Fraction.getFraction(1, 5);
867 f = f1.add(f2);
868 assertEquals(4, f.getNumerator());
869 assertEquals(5, f.getDenominator());
870
871 f1 = Fraction.getFraction(3, 5);
872 f2 = Fraction.getFraction(2, 5);
873 f = f1.add(f2);
874 assertEquals(1, f.getNumerator());
875 assertEquals(1, f.getDenominator());
876
877 f1 = Fraction.getFraction(3, 5);
878 f2 = Fraction.getFraction(3, 5);
879 f = f1.add(f2);
880 assertEquals(6, f.getNumerator());
881 assertEquals(5, f.getDenominator());
882
883 f1 = Fraction.getFraction(3, 5);
884 f2 = Fraction.getFraction(-4, 5);
885 f = f1.add(f2);
886 assertEquals(-1, f.getNumerator());
887 assertEquals(5, f.getDenominator());
888
889 f1 = Fraction.getFraction(Integer.MAX_VALUE - 1, 1);
890 f2 = Fraction.ONE;
891 f = f1.add(f2);
892 assertEquals(Integer.MAX_VALUE, f.getNumerator());
893 assertEquals(1, f.getDenominator());
894
895 f1 = Fraction.getFraction(3, 5);
896 f2 = Fraction.getFraction(1, 2);
897 f = f1.add(f2);
898 assertEquals(11, f.getNumerator());
899 assertEquals(10, f.getDenominator());
900
901 f1 = Fraction.getFraction(3, 8);
902 f2 = Fraction.getFraction(1, 6);
903 f = f1.add(f2);
904 assertEquals(13, f.getNumerator());
905 assertEquals(24, f.getDenominator());
906
907 f1 = Fraction.getFraction(0, 5);
908 f2 = Fraction.getFraction(1, 5);
909 f = f1.add(f2);
910 assertSame(f2, f);
911 f = f2.add(f1);
912 assertSame(f2, f);
913
914 f1 = Fraction.getFraction(-1, 13*13*2*2);
915 f2 = Fraction.getFraction(-2, 13*17*2);
916 f = f1.add(f2);
917 assertEquals(13*13*17*2*2, f.getDenominator());
918 assertEquals(-17 - 2*13*2, f.getNumerator());
919
920 try {
921 f.add(null);
922 fail("expecting IllegalArgumentException");
923 } catch (IllegalArgumentException ex) {}
924
925 // if this fraction is added naively, it will overflow.
926 // check that it doesn't.
927 f1 = Fraction.getFraction(1,32768*3);
928 f2 = Fraction.getFraction(1,59049);
929 f = f1.add(f2);
930 assertEquals(52451, f.getNumerator());
931 assertEquals(1934917632, f.getDenominator());
932
933 f1 = Fraction.getFraction(Integer.MIN_VALUE, 3);
934 f2 = Fraction.ONE_THIRD;
935 f = f1.add(f2);
936 assertEquals(Integer.MIN_VALUE+1, f.getNumerator());
937 assertEquals(3, f.getDenominator());
938
939 f1 = Fraction.getFraction(Integer.MAX_VALUE - 1, 1);
940 f2 = Fraction.ONE;
941 f = f1.add(f2);
942 assertEquals(Integer.MAX_VALUE, f.getNumerator());
943 assertEquals(1, f.getDenominator());
944
945 try {
946 f = f.add(Fraction.ONE); // should overflow
947 fail("expecting ArithmeticException but got: " + f.toString());
948 } catch (ArithmeticException ex) {}
949
950 // denominator should not be a multiple of 2 or 3 to trigger overflow
951 f1 = Fraction.getFraction(Integer.MIN_VALUE, 5);
952 f2 = Fraction.getFraction(-1,5);
953 try {
954 f = f1.add(f2); // should overflow
955 fail("expecting ArithmeticException but got: " + f.toString());
956 } catch (ArithmeticException ex) {}
957
958 try {
959 f= Fraction.getFraction(-Integer.MAX_VALUE, 1);
960 f = f.add(f);
961 fail("expecting ArithmeticException");
962 } catch (ArithmeticException ex) {}
963
964 try {
965 f= Fraction.getFraction(-Integer.MAX_VALUE, 1);
966 f = f.add(f);
967 fail("expecting ArithmeticException");
968 } catch (ArithmeticException ex) {}
969
970 f1 = Fraction.getFraction(3,327680);
971 f2 = Fraction.getFraction(2,59049);
972 try {
973 f = f1.add(f2); // should overflow
974 fail("expecting ArithmeticException but got: " + f.toString());
975 } catch (ArithmeticException ex) {}
976 }
977
978 public void testSubtract() {
979 Fraction f = null;
980 Fraction f1 = null;
981 Fraction f2 = null;
982
983 f1 = Fraction.getFraction(3, 5);
984 f2 = Fraction.getFraction(1, 5);
985 f = f1.subtract(f2);
986 assertEquals(2, f.getNumerator());
987 assertEquals(5, f.getDenominator());
988
989 f1 = Fraction.getFraction(7, 5);
990 f2 = Fraction.getFraction(2, 5);
991 f = f1.subtract(f2);
992 assertEquals(1, f.getNumerator());
993 assertEquals(1, f.getDenominator());
994
995 f1 = Fraction.getFraction(3, 5);
996 f2 = Fraction.getFraction(3, 5);
997 f = f1.subtract(f2);
998 assertEquals(0, f.getNumerator());
999 assertEquals(1, f.getDenominator());
1000
1001 f1 = Fraction.getFraction(3, 5);
1002 f2 = Fraction.getFraction(-4, 5);
1003 f = f1.subtract(f2);
1004 assertEquals(7, f.getNumerator());
1005 assertEquals(5, f.getDenominator());
1006
1007 f1 = Fraction.getFraction(0, 5);
1008 f2 = Fraction.getFraction(4, 5);
1009 f = f1.subtract(f2);
1010 assertEquals(-4, f.getNumerator());
1011 assertEquals(5, f.getDenominator());
1012
1013 f1 = Fraction.getFraction(0, 5);
1014 f2 = Fraction.getFraction(-4, 5);
1015 f = f1.subtract(f2);
1016 assertEquals(4, f.getNumerator());
1017 assertEquals(5, f.getDenominator());
1018
1019 f1 = Fraction.getFraction(3, 5);
1020 f2 = Fraction.getFraction(1, 2);
1021 f = f1.subtract(f2);
1022 assertEquals(1, f.getNumerator());
1023 assertEquals(10, f.getDenominator());
1024
1025 f1 = Fraction.getFraction(0, 5);
1026 f2 = Fraction.getFraction(1, 5);
1027 f = f2.subtract(f1);
1028 assertSame(f2, f);
1029
1030 try {
1031 f.subtract(null);
1032 fail("expecting IllegalArgumentException");
1033 } catch (IllegalArgumentException ex) {}
1034
1035 // if this fraction is subtracted naively, it will overflow.
1036 // check that it doesn't.
1037 f1 = Fraction.getFraction(1,32768*3);
1038 f2 = Fraction.getFraction(1,59049);
1039 f = f1.subtract(f2);
1040 assertEquals(-13085, f.getNumerator());
1041 assertEquals(1934917632, f.getDenominator());
1042
1043 f1 = Fraction.getFraction(Integer.MIN_VALUE, 3);
1044 f2 = Fraction.ONE_THIRD.negate();
1045 f = f1.subtract(f2);
1046 assertEquals(Integer.MIN_VALUE+1, f.getNumerator());
1047 assertEquals(3, f.getDenominator());
1048
1049 f1 = Fraction.getFraction(Integer.MAX_VALUE, 1);
1050 f2 = Fraction.ONE;
1051 f = f1.subtract(f2);
1052 assertEquals(Integer.MAX_VALUE-1, f.getNumerator());
1053 assertEquals(1, f.getDenominator());
1054
1055 try {
1056 f1 = Fraction.getFraction(1, Integer.MAX_VALUE);
1057 f2 = Fraction.getFraction(1, Integer.MAX_VALUE - 1);
1058 f = f1.subtract(f2);
1059 fail("expecting ArithmeticException"); //should overflow
1060 } catch (ArithmeticException ex) {}
1061
1062 // denominator should not be a multiple of 2 or 3 to trigger overflow
1063 f1 = Fraction.getFraction(Integer.MIN_VALUE, 5);
1064 f2 = Fraction.getFraction(1,5);
1065 try {
1066 f = f1.subtract(f2); // should overflow
1067 fail("expecting ArithmeticException but got: " + f.toString());
1068 } catch (ArithmeticException ex) {}
1069
1070 try {
1071 f= Fraction.getFraction(Integer.MIN_VALUE, 1);
1072 f = f.subtract(Fraction.ONE);
1073 fail("expecting ArithmeticException");
1074 } catch (ArithmeticException ex) {}
1075
1076 try {
1077 f= Fraction.getFraction(Integer.MAX_VALUE, 1);
1078 f = f.subtract(Fraction.ONE.negate());
1079 fail("expecting ArithmeticException");
1080 } catch (ArithmeticException ex) {}
1081
1082 f1 = Fraction.getFraction(3,327680);
1083 f2 = Fraction.getFraction(2,59049);
1084 try {
1085 f = f1.subtract(f2); // should overflow
1086 fail("expecting ArithmeticException but got: " + f.toString());
1087 } catch (ArithmeticException ex) {}
1088 }
1089
1090 public void testMultiply() {
1091 Fraction f = null;
1092 Fraction f1 = null;
1093 Fraction f2 = null;
1094
1095 f1 = Fraction.getFraction(3, 5);
1096 f2 = Fraction.getFraction(2, 5);
1097 f = f1.multiplyBy(f2);
1098 assertEquals(6, f.getNumerator());
1099 assertEquals(25, f.getDenominator());
1100
1101 f1 = Fraction.getFraction(6, 10);
1102 f2 = Fraction.getFraction(6, 10);
1103 f = f1.multiplyBy(f2);
1104 assertEquals(9, f.getNumerator());
1105 assertEquals(25, f.getDenominator());
1106 f = f.multiplyBy(f2);
1107 assertEquals(27, f.getNumerator());
1108 assertEquals(125, f.getDenominator());
1109
1110 f1 = Fraction.getFraction(3, 5);
1111 f2 = Fraction.getFraction(-2, 5);
1112 f = f1.multiplyBy(f2);
1113 assertEquals(-6, f.getNumerator());
1114 assertEquals(25, f.getDenominator());
1115
1116 f1 = Fraction.getFraction(-3, 5);
1117 f2 = Fraction.getFraction(-2, 5);
1118 f = f1.multiplyBy(f2);
1119 assertEquals(6, f.getNumerator());
1120 assertEquals(25, f.getDenominator());
1121
1122
1123 f1 = Fraction.getFraction(0, 5);
1124 f2 = Fraction.getFraction(2, 7);
1125 f = f1.multiplyBy(f2);
1126 assertSame(Fraction.ZERO, f);
1127
1128 f1 = Fraction.getFraction(2, 7);
1129 f2 = Fraction.ONE;
1130 f = f1.multiplyBy(f2);
1131 assertEquals(2, f.getNumerator());
1132 assertEquals(7, f.getDenominator());
1133
1134 f1 = Fraction.getFraction(Integer.MAX_VALUE, 1);
1135 f2 = Fraction.getFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
1136 f = f1.multiplyBy(f2);
1137 assertEquals(Integer.MIN_VALUE, f.getNumerator());
1138 assertEquals(1, f.getDenominator());
1139
1140 try {
1141 f.multiplyBy(null);
1142 fail("expecting IllegalArgumentException");
1143 } catch (IllegalArgumentException ex) {}
1144
1145 try {
1146 f1 = Fraction.getFraction(1, Integer.MAX_VALUE);
1147 f = f1.multiplyBy(f1); // should overflow
1148 fail("expecting ArithmeticException");
1149 } catch (ArithmeticException ex) {}
1150
1151 try {
1152 f1 = Fraction.getFraction(1, -Integer.MAX_VALUE);
1153 f = f1.multiplyBy(f1); // should overflow
1154 fail("expecting ArithmeticException");
1155 } catch (ArithmeticException ex) {}
1156 }
1157
1158 public void testDivide() {
1159 Fraction f = null;
1160 Fraction f1 = null;
1161 Fraction f2 = null;
1162
1163 f1 = Fraction.getFraction(3, 5);
1164 f2 = Fraction.getFraction(2, 5);
1165 f = f1.divideBy(f2);
1166 assertEquals(3, f.getNumerator());
1167 assertEquals(2, f.getDenominator());
1168
1169 f1 = Fraction.getFraction(3, 5);
1170 f2 = Fraction.ZERO;
1171 try {
1172 f = f1.divideBy(f2);
1173 fail("expecting ArithmeticException");
1174 } catch (ArithmeticException ex) {}
1175
1176 f1 = Fraction.getFraction(0, 5);
1177 f2 = Fraction.getFraction(2, 7);
1178 f = f1.divideBy(f2);
1179 assertSame(Fraction.ZERO, f);
1180
1181 f1 = Fraction.getFraction(2, 7);
1182 f2 = Fraction.ONE;
1183 f = f1.divideBy(f2);
1184 assertEquals(2, f.getNumerator());
1185 assertEquals(7, f.getDenominator());
1186
1187 f1 = Fraction.getFraction(1, Integer.MAX_VALUE);
1188 f = f1.divideBy(f1);
1189 assertEquals(1, f.getNumerator());
1190 assertEquals(1, f.getDenominator());
1191
1192 f1 = Fraction.getFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
1193 f2 = Fraction.getFraction(1, Integer.MAX_VALUE);
1194 f = f1.divideBy(f2);
1195 assertEquals(Integer.MIN_VALUE, f.getNumerator());
1196 assertEquals(1, f.getDenominator());
1197
1198 try {
1199 f.divideBy(null);
1200 fail("IllegalArgumentException");
1201 } catch (IllegalArgumentException ex) {}
1202
1203 try {
1204 f1 = Fraction.getFraction(1, Integer.MAX_VALUE);
1205 f = f1.divideBy(f1.invert()); // should overflow
1206 fail("expecting ArithmeticException");
1207 } catch (ArithmeticException ex) {}
1208 try {
1209 f1 = Fraction.getFraction(1, -Integer.MAX_VALUE);
1210 f = f1.divideBy(f1.invert()); // should overflow
1211 fail("expecting ArithmeticException");
1212 } catch (ArithmeticException ex) {}
1213 }
1214
1215 public void testEquals() {
1216 Fraction f1 = null;
1217 Fraction f2 = null;
1218
1219 f1 = Fraction.getFraction(3, 5);
1220 assertEquals(false, f1.equals(null));
1221 assertEquals(false, f1.equals(new Object()));
1222 assertEquals(false, f1.equals(Integer.valueOf(6)));
1223
1224 f1 = Fraction.getFraction(3, 5);
1225 f2 = Fraction.getFraction(2, 5);
1226 assertEquals(false, f1.equals(f2));
1227 assertEquals(true, f1.equals(f1));
1228 assertEquals(true, f2.equals(f2));
1229
1230 f2 = Fraction.getFraction(3, 5);
1231 assertEquals(true, f1.equals(f2));
1232
1233 f2 = Fraction.getFraction(6, 10);
1234 assertEquals(false, f1.equals(f2));
1235 }
1236
1237 public void testHashCode() {
1238 Fraction f1 = Fraction.getFraction(3, 5);
1239 Fraction f2 = Fraction.getFraction(3, 5);
1240
1241 assertTrue(f1.hashCode() == f2.hashCode());
1242
1243 f2 = Fraction.getFraction(2, 5);
1244 assertTrue(f1.hashCode() != f2.hashCode());
1245
1246 f2 = Fraction.getFraction(6, 10);
1247 assertTrue(f1.hashCode() != f2.hashCode());
1248 }
1249
1250 public void testCompareTo() {
1251 Fraction f1 = null;
1252 Fraction f2 = null;
1253
1254 f1 = Fraction.getFraction(3, 5);
1255 assertTrue(f1.compareTo(f1) == 0);
1256
1257 try {
1258 f1.compareTo(null);
1259 fail("expecting NullPointerException");
1260 } catch (NullPointerException ex) {}
1261
1262 f2 = Fraction.getFraction(2, 5);
1263 assertTrue(f1.compareTo(f2) > 0);
1264 assertTrue(f2.compareTo(f2) == 0);
1265
1266 f2 = Fraction.getFraction(4, 5);
1267 assertTrue(f1.compareTo(f2) < 0);
1268 assertTrue(f2.compareTo(f2) == 0);
1269
1270 f2 = Fraction.getFraction(3, 5);
1271 assertTrue(f1.compareTo(f2) == 0);
1272 assertTrue(f2.compareTo(f2) == 0);
1273
1274 f2 = Fraction.getFraction(6, 10);
1275 assertTrue(f1.compareTo(f2) == 0);
1276 assertTrue(f2.compareTo(f2) == 0);
1277
1278 f2 = Fraction.getFraction(-1, 1, Integer.MAX_VALUE);
1279 assertTrue(f1.compareTo(f2) > 0);
1280 assertTrue(f2.compareTo(f2) == 0);
1281
1282 }
1283
1284 public void testToString() {
1285 Fraction f = null;
1286
1287 f = Fraction.getFraction(3, 5);
1288 String str = f.toString();
1289 assertEquals("3/5", str);
1290 assertSame(str, f.toString());
1291
1292 f = Fraction.getFraction(7, 5);
1293 assertEquals("7/5", f.toString());
1294
1295 f = Fraction.getFraction(4, 2);
1296 assertEquals("4/2", f.toString());
1297
1298 f = Fraction.getFraction(0, 2);
1299 assertEquals("0/2", f.toString());
1300
1301 f = Fraction.getFraction(2, 2);
1302 assertEquals("2/2", f.toString());
1303
1304 f = Fraction.getFraction(Integer.MIN_VALUE, 0, 1);
1305 assertEquals("-2147483648/1", f.toString());
1306
1307 f = Fraction.getFraction(-1, 1, Integer.MAX_VALUE);
1308 assertEquals("-2147483648/2147483647", f.toString());
1309 }
1310
1311 public void testToProperString() {
1312 Fraction f = null;
1313
1314 f = Fraction.getFraction(3, 5);
1315 String str = f.toProperString();
1316 assertEquals("3/5", str);
1317 assertSame(str, f.toProperString());
1318
1319 f = Fraction.getFraction(7, 5);
1320 assertEquals("1 2/5", f.toProperString());
1321
1322 f = Fraction.getFraction(14, 10);
1323 assertEquals("1 4/10", f.toProperString());
1324
1325 f = Fraction.getFraction(4, 2);
1326 assertEquals("2", f.toProperString());
1327
1328 f = Fraction.getFraction(0, 2);
1329 assertEquals("0", f.toProperString());
1330
1331 f = Fraction.getFraction(2, 2);
1332 assertEquals("1", f.toProperString());
1333
1334 f = Fraction.getFraction(-7, 5);
1335 assertEquals("-1 2/5", f.toProperString());
1336
1337 f = Fraction.getFraction(Integer.MIN_VALUE, 0, 1);
1338 assertEquals("-2147483648", f.toProperString());
1339
1340 f = Fraction.getFraction(-1, 1, Integer.MAX_VALUE);
1341 assertEquals("-1 1/2147483647", f.toProperString());
1342
1343 assertEquals("-1", Fraction.getFraction(-1).toProperString());
1344 }
1345 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.math;
17
18 import junit.framework.TestCase;
19
20 /**
21 * Unit tests {@link org.apache.commons.lang3.math.IEEE754rUtils}.
22 *
23 * @version $Id: IEEE754rUtilsTest.java 889219 2009-12-10 12:02:50Z bayard $
24 */
25 public class IEEE754rUtilsTest extends TestCase {
26
27 public void testLang381() {
28 assertEquals(1.2, IEEE754rUtils.min(1.2, 2.5, Double.NaN), 0.01);
29 assertEquals(2.5, IEEE754rUtils.max(1.2, 2.5, Double.NaN), 0.01);
30 assertTrue(Double.isNaN(IEEE754rUtils.max(Double.NaN, Double.NaN, Double.NaN)));
31 assertEquals(1.2f, IEEE754rUtils.min(1.2f, 2.5f, Float.NaN), 0.01);
32 assertEquals(2.5f, IEEE754rUtils.max(1.2f, 2.5f, Float.NaN), 0.01);
33 assertTrue(Float.isNaN(IEEE754rUtils.max(Float.NaN, Float.NaN, Float.NaN)));
34
35 double[] a = new double[] { 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
36 assertEquals(42.0, IEEE754rUtils.max(a), 0.01);
37 assertEquals(1.2, IEEE754rUtils.min(a), 0.01);
38
39 double[] b = new double[] { Double.NaN, 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
40 assertEquals(42.0, IEEE754rUtils.max(b), 0.01);
41 assertEquals(1.2, IEEE754rUtils.min(b), 0.01);
42
43 float[] aF = new float[] { 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
44 assertEquals(1.2f, IEEE754rUtils.min(aF), 0.01);
45 assertEquals(42.0f, IEEE754rUtils.max(aF), 0.01);
46
47 float[] bF = new float[] { Float.NaN, 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
48 assertEquals(1.2f, IEEE754rUtils.min(bF), 0.01);
49 assertEquals(42.0f, IEEE754rUtils.max(bF), 0.01);
50 }
51
52 public void testEnforceExceptions() {
53 try {
54 IEEE754rUtils.min( (float[]) null);
55 fail("IllegalArgumentException expected for null input");
56 } catch(IllegalArgumentException iae) { /* expected */ }
57
58 try {
59 IEEE754rUtils.min(new float[0]);
60 fail("IllegalArgumentException expected for empty input");
61 } catch(IllegalArgumentException iae) { /* expected */ }
62
63 try {
64 IEEE754rUtils.max( (float[]) null);
65 fail("IllegalArgumentException expected for null input");
66 } catch(IllegalArgumentException iae) { /* expected */ }
67
68 try {
69 IEEE754rUtils.max(new float[0]);
70 fail("IllegalArgumentException expected for empty input");
71 } catch(IllegalArgumentException iae) { /* expected */ }
72
73 try {
74 IEEE754rUtils.min( (double[]) null);
75 fail("IllegalArgumentException expected for null input");
76 } catch(IllegalArgumentException iae) { /* expected */ }
77
78 try {
79 IEEE754rUtils.min(new double[0]);
80 fail("IllegalArgumentException expected for empty input");
81 } catch(IllegalArgumentException iae) { /* expected */ }
82
83 try {
84 IEEE754rUtils.max( (double[]) null);
85 fail("IllegalArgumentException expected for null input");
86 } catch(IllegalArgumentException iae) { /* expected */ }
87
88 try {
89 IEEE754rUtils.max(new double[0]);
90 fail("IllegalArgumentException expected for empty input");
91 } catch(IllegalArgumentException iae) { /* expected */ }
92
93 }
94
95 public void testConstructorExists() {
96 new IEEE754rUtils();
97 }
98
99 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.math;
17
18 import static org.apache.commons.lang3.JavaVersion.JAVA_1_3;
19 import static org.junit.Assert.*;
20
21 import java.lang.reflect.Constructor;
22 import java.lang.reflect.Modifier;
23 import java.math.BigDecimal;
24 import java.math.BigInteger;
25
26 import org.apache.commons.lang3.SystemUtils;
27
28 import org.junit.Test;
29
30 /**
31 * Unit tests {@link org.apache.commons.lang3.math.NumberUtils}.
32 *
33 * @version $Id: NumberUtilsTest.java 1153490 2011-08-03 13:53:35Z ggregory $
34 */
35 public class NumberUtilsTest {
36
37 //-----------------------------------------------------------------------
38 @Test
39 public void testConstructor() {
40 assertNotNull(new NumberUtils());
41 Constructor<?>[] cons = NumberUtils.class.getDeclaredConstructors();
42 assertEquals(1, cons.length);
43 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
44 assertEquals(true, Modifier.isPublic(NumberUtils.class.getModifiers()));
45 assertEquals(false, Modifier.isFinal(NumberUtils.class.getModifiers()));
46 }
47
48 //---------------------------------------------------------------------
49
50 /**
51 * Test for {@link NumberUtils#toInt(String)}.
52 */
53 @Test
54 public void testToIntString() {
55 assertTrue("toInt(String) 1 failed", NumberUtils.toInt("12345") == 12345);
56 assertTrue("toInt(String) 2 failed", NumberUtils.toInt("abc") == 0);
57 assertTrue("toInt(empty) failed", NumberUtils.toInt("") == 0);
58 assertTrue("toInt(null) failed", NumberUtils.toInt(null) == 0);
59 }
60
61 /**
62 * Test for {@link NumberUtils#toInt(String, int)}.
63 */
64 @Test
65 public void testToIntStringI() {
66 assertTrue("toInt(String,int) 1 failed", NumberUtils.toInt("12345", 5) == 12345);
67 assertTrue("toInt(String,int) 2 failed", NumberUtils.toInt("1234.5", 5) == 5);
68 }
69
70 /**
71 * Test for {@link NumberUtils#toLong(String)}.
72 */
73 @Test
74 public void testToLongString() {
75 assertTrue("toLong(String) 1 failed", NumberUtils.toLong("12345") == 12345l);
76 assertTrue("toLong(String) 2 failed", NumberUtils.toLong("abc") == 0l);
77 assertTrue("toLong(String) 3 failed", NumberUtils.toLong("1L") == 0l);
78 assertTrue("toLong(String) 4 failed", NumberUtils.toLong("1l") == 0l);
79 assertTrue("toLong(Long.MAX_VALUE) failed", NumberUtils.toLong(Long.MAX_VALUE+"") == Long.MAX_VALUE);
80 assertTrue("toLong(Long.MIN_VALUE) failed", NumberUtils.toLong(Long.MIN_VALUE+"") == Long.MIN_VALUE);
81 assertTrue("toLong(empty) failed", NumberUtils.toLong("") == 0l);
82 assertTrue("toLong(null) failed", NumberUtils.toLong(null) == 0l);
83 }
84
85 /**
86 * Test for {@link NumberUtils#toLong(String, long)}.
87 */
88 @Test
89 public void testToLongStringL() {
90 assertTrue("toLong(String,long) 1 failed", NumberUtils.toLong("12345", 5l) == 12345l);
91 assertTrue("toLong(String,long) 2 failed", NumberUtils.toLong("1234.5", 5l) == 5l);
92 }
93
94 /**
95 * Test for {@link NumberUtils#toFloat(String)}.
96 */
97 @Test
98 public void testToFloatString() {
99 assertTrue("toFloat(String) 1 failed", NumberUtils.toFloat("-1.2345") == -1.2345f);
100 assertTrue("toFloat(String) 2 failed", NumberUtils.toFloat("1.2345") == 1.2345f);
101 assertTrue("toFloat(String) 3 failed", NumberUtils.toFloat("abc") == 0.0f);
102 assertTrue("toFloat(Float.MAX_VALUE) failed", NumberUtils.toFloat(Float.MAX_VALUE+"") == Float.MAX_VALUE);
103 assertTrue("toFloat(Float.MIN_VALUE) failed", NumberUtils.toFloat(Float.MIN_VALUE+"") == Float.MIN_VALUE);
104 assertTrue("toFloat(empty) failed", NumberUtils.toFloat("") == 0.0f);
105 assertTrue("toFloat(null) failed", NumberUtils.toFloat(null) == 0.0f);
106 }
107
108 /**
109 * Test for {@link NumberUtils#toFloat(String, float)}.
110 */
111 @Test
112 public void testToFloatStringF() {
113 assertTrue("toFloat(String,int) 1 failed", NumberUtils.toFloat("1.2345", 5.1f) == 1.2345f);
114 assertTrue("toFloat(String,int) 2 failed", NumberUtils.toFloat("a", 5.0f) == 5.0f);
115 }
116
117 /**
118 * Test for {@link NumberUtils#toDouble(String)}.
119 */
120 @Test
121 public void testStringToDoubleString() {
122 assertTrue("toDouble(String) 1 failed", NumberUtils.toDouble("-1.2345") == -1.2345d);
123 assertTrue("toDouble(String) 2 failed", NumberUtils.toDouble("1.2345") == 1.2345d);
124 assertTrue("toDouble(String) 3 failed", NumberUtils.toDouble("abc") == 0.0d);
125 assertTrue("toDouble(Double.MAX_VALUE) failed", NumberUtils.toDouble(Double.MAX_VALUE+"") == Double.MAX_VALUE);
126 assertTrue("toDouble(Double.MIN_VALUE) failed", NumberUtils.toDouble(Double.MIN_VALUE+"") == Double.MIN_VALUE);
127 assertTrue("toDouble(empty) failed", NumberUtils.toDouble("") == 0.0d);
128 assertTrue("toDouble(null) failed", NumberUtils.toDouble(null) == 0.0d);
129 }
130
131 /**
132 * Test for {@link NumberUtils#toDouble(String, double)}.
133 */
134 @Test
135 public void testStringToDoubleStringD() {
136 assertTrue("toDouble(String,int) 1 failed", NumberUtils.toDouble("1.2345", 5.1d) == 1.2345d);
137 assertTrue("toDouble(String,int) 2 failed", NumberUtils.toDouble("a", 5.0d) == 5.0d);
138 }
139
140 /**
141 * Test for {@link NumberUtils#toByte(String)}.
142 */
143 @Test
144 public void testToByteString() {
145 assertTrue("toByte(String) 1 failed", NumberUtils.toByte("123") == 123);
146 assertTrue("toByte(String) 2 failed", NumberUtils.toByte("abc") == 0);
147 assertTrue("toByte(empty) failed", NumberUtils.toByte("") == 0);
148 assertTrue("toByte(null) failed", NumberUtils.toByte(null) == 0);
149 }
150
151 /**
152 * Test for {@link NumberUtils#toByte(String, byte)}.
153 */
154 @Test
155 public void testToByteStringI() {
156 assertTrue("toByte(String,byte) 1 failed", NumberUtils.toByte("123", (byte) 5) == 123);
157 assertTrue("toByte(String,byte) 2 failed", NumberUtils.toByte("12.3", (byte) 5) == 5);
158 }
159
160 /**
161 * Test for {@link NumberUtils#toShort(String)}.
162 */
163 @Test
164 public void testToShortString() {
165 assertTrue("toShort(String) 1 failed", NumberUtils.toShort("12345") == 12345);
166 assertTrue("toShort(String) 2 failed", NumberUtils.toShort("abc") == 0);
167 assertTrue("toShort(empty) failed", NumberUtils.toShort("") == 0);
168 assertTrue("toShort(null) failed", NumberUtils.toShort(null) == 0);
169 }
170
171 /**
172 * Test for {@link NumberUtils#toShort(String, short)}.
173 */
174 @Test
175 public void testToShortStringI() {
176 assertTrue("toShort(String,short) 1 failed", NumberUtils.toShort("12345", (short) 5) == 12345);
177 assertTrue("toShort(String,short) 2 failed", NumberUtils.toShort("1234.5", (short) 5) == 5);
178 }
179
180 @Test
181 public void testCreateNumber() {
182 // a lot of things can go wrong
183 assertEquals("createNumber(String) 1 failed", Float.valueOf("1234.5"), NumberUtils.createNumber("1234.5"));
184 assertEquals("createNumber(String) 2 failed", Integer.valueOf("12345"), NumberUtils.createNumber("12345"));
185 assertEquals("createNumber(String) 3 failed", Double.valueOf("1234.5"), NumberUtils.createNumber("1234.5D"));
186 assertEquals("createNumber(String) 3 failed", Double.valueOf("1234.5"), NumberUtils.createNumber("1234.5d"));
187 assertEquals("createNumber(String) 4 failed", Float.valueOf("1234.5"), NumberUtils.createNumber("1234.5F"));
188 assertEquals("createNumber(String) 4 failed", Float.valueOf("1234.5"), NumberUtils.createNumber("1234.5f"));
189 assertEquals("createNumber(String) 5 failed", Long.valueOf(Integer.MAX_VALUE + 1L), NumberUtils.createNumber(""
190 + (Integer.MAX_VALUE + 1L)));
191 assertEquals("createNumber(String) 6 failed", Long.valueOf(12345), NumberUtils.createNumber("12345L"));
192 assertEquals("createNumber(String) 6 failed", Long.valueOf(12345), NumberUtils.createNumber("12345l"));
193 assertEquals("createNumber(String) 7 failed", Float.valueOf("-1234.5"), NumberUtils.createNumber("-1234.5"));
194 assertEquals("createNumber(String) 8 failed", Integer.valueOf("-12345"), NumberUtils.createNumber("-12345"));
195 assertTrue("createNumber(String) 9 failed", 0xFADE == NumberUtils.createNumber("0xFADE").intValue());
196 assertTrue("createNumber(String) 10 failed", -0xFADE == NumberUtils.createNumber("-0xFADE").intValue());
197 assertEquals("createNumber(String) 11 failed", Double.valueOf("1.1E200"), NumberUtils.createNumber("1.1E200"));
198 assertEquals("createNumber(String) 12 failed", Float.valueOf("1.1E20"), NumberUtils.createNumber("1.1E20"));
199 assertEquals("createNumber(String) 13 failed", Double.valueOf("-1.1E200"), NumberUtils.createNumber("-1.1E200"));
200 assertEquals("createNumber(String) 14 failed", Double.valueOf("1.1E-200"), NumberUtils.createNumber("1.1E-200"));
201 assertEquals("createNumber(null) failed", null, NumberUtils.createNumber(null));
202 assertEquals("createNumber(String) failed", new BigInteger("12345678901234567890"), NumberUtils
203 .createNumber("12345678901234567890L"));
204
205 // jdk 1.2 doesn't support this. unsure about jdk 1.2.2
206 if (SystemUtils.isJavaVersionAtLeast(JAVA_1_3)) {
207 assertEquals("createNumber(String) 15 failed", new BigDecimal("1.1E-700"), NumberUtils
208 .createNumber("1.1E-700F"));
209 }
210 assertEquals("createNumber(String) 16 failed", Long.valueOf("10" + Integer.MAX_VALUE), NumberUtils
211 .createNumber("10" + Integer.MAX_VALUE + "L"));
212 assertEquals("createNumber(String) 17 failed", Long.valueOf("10" + Integer.MAX_VALUE), NumberUtils
213 .createNumber("10" + Integer.MAX_VALUE));
214 assertEquals("createNumber(String) 18 failed", new BigInteger("10" + Long.MAX_VALUE), NumberUtils
215 .createNumber("10" + Long.MAX_VALUE));
216
217 // LANG-521
218 assertEquals("createNumber(String) LANG-521 failed", Float.valueOf("2."), NumberUtils.createNumber("2."));
219
220 // LANG-638
221 assertFalse("createNumber(String) succeeded", checkCreateNumber("1eE"));
222
223 // LANG-693
224 assertEquals("createNumber(String) LANG-693 failed", Double.valueOf(Double.MAX_VALUE), NumberUtils
225 .createNumber("" + Double.MAX_VALUE));
226 }
227
228 @Test
229 public void testCreateFloat() {
230 assertEquals("createFloat(String) failed", Float.valueOf("1234.5"), NumberUtils.createFloat("1234.5"));
231 assertEquals("createFloat(null) failed", null, NumberUtils.createFloat(null));
232 this.testCreateFloatFailure("");
233 this.testCreateFloatFailure(" ");
234 this.testCreateFloatFailure("\b\t\n\f\r");
235 // Funky whitespaces
236 this.testCreateFloatFailure("\u00A0\uFEFF\u000B\u000C\u001C\u001D\u001E\u001F");
237 }
238
239 protected void testCreateFloatFailure(String str) {
240 try {
241 Float value = NumberUtils.createFloat(str);
242 fail("createFloat(blank) failed: " + value);
243 } catch (NumberFormatException ex) {
244 // empty
245 }
246 }
247
248 @Test
249 public void testCreateDouble() {
250 assertEquals("createDouble(String) failed", Double.valueOf("1234.5"), NumberUtils.createDouble("1234.5"));
251 assertEquals("createDouble(null) failed", null, NumberUtils.createDouble(null));
252 this.testCreateDoubleFailure("");
253 this.testCreateDoubleFailure(" ");
254 this.testCreateDoubleFailure("\b\t\n\f\r");
255 // Funky whitespaces
256 this.testCreateDoubleFailure("\u00A0\uFEFF\u000B\u000C\u001C\u001D\u001E\u001F");
257 }
258
259 protected void testCreateDoubleFailure(String str) {
260 try {
261 Double value = NumberUtils.createDouble(str);
262 fail("createDouble(blank) failed: " + value);
263 } catch (NumberFormatException ex) {
264 // empty
265 }
266 }
267
268 @Test
269 public void testCreateInteger() {
270 assertEquals("createInteger(String) failed", Integer.valueOf("12345"), NumberUtils.createInteger("12345"));
271 assertEquals("createInteger(null) failed", null, NumberUtils.createInteger(null));
272 this.testCreateIntegerFailure("");
273 this.testCreateIntegerFailure(" ");
274 this.testCreateIntegerFailure("\b\t\n\f\r");
275 // Funky whitespaces
276 this.testCreateIntegerFailure("\u00A0\uFEFF\u000B\u000C\u001C\u001D\u001E\u001F");
277 }
278
279 protected void testCreateIntegerFailure(String str) {
280 try {
281 Integer value = NumberUtils.createInteger(str);
282 fail("createInteger(blank) failed: " + value);
283 } catch (NumberFormatException ex) {
284 // empty
285 }
286 }
287
288 @Test
289 public void testCreateLong() {
290 assertEquals("createLong(String) failed", Long.valueOf("12345"), NumberUtils.createLong("12345"));
291 assertEquals("createLong(null) failed", null, NumberUtils.createLong(null));
292 this.testCreateLongFailure("");
293 this.testCreateLongFailure(" ");
294 this.testCreateLongFailure("\b\t\n\f\r");
295 // Funky whitespaces
296 this.testCreateLongFailure("\u00A0\uFEFF\u000B\u000C\u001C\u001D\u001E\u001F");
297 }
298
299 protected void testCreateLongFailure(String str) {
300 try {
301 Long value = NumberUtils.createLong(str);
302 fail("createLong(blank) failed: " + value);
303 } catch (NumberFormatException ex) {
304 // empty
305 }
306 }
307
308 @Test
309 public void testCreateBigInteger() {
310 assertEquals("createBigInteger(String) failed", new BigInteger("12345"), NumberUtils.createBigInteger("12345"));
311 assertEquals("createBigInteger(null) failed", null, NumberUtils.createBigInteger(null));
312 this.testCreateBigIntegerFailure("");
313 this.testCreateBigIntegerFailure(" ");
314 this.testCreateBigIntegerFailure("\b\t\n\f\r");
315 // Funky whitespaces
316 this.testCreateBigIntegerFailure("\u00A0\uFEFF\u000B\u000C\u001C\u001D\u001E\u001F");
317 }
318
319 protected void testCreateBigIntegerFailure(String str) {
320 try {
321 BigInteger value = NumberUtils.createBigInteger(str);
322 fail("createBigInteger(blank) failed: " + value);
323 } catch (NumberFormatException ex) {
324 // empty
325 }
326 }
327
328 @Test
329 public void testCreateBigDecimal() {
330 assertEquals("createBigDecimal(String) failed", new BigDecimal("1234.5"), NumberUtils.createBigDecimal("1234.5"));
331 assertEquals("createBigDecimal(null) failed", null, NumberUtils.createBigDecimal(null));
332 this.testCreateBigDecimalFailure("");
333 this.testCreateBigDecimalFailure(" ");
334 this.testCreateBigDecimalFailure("\b\t\n\f\r");
335 // Funky whitespaces
336 this.testCreateBigDecimalFailure("\u00A0\uFEFF\u000B\u000C\u001C\u001D\u001E\u001F");
337 }
338
339 protected void testCreateBigDecimalFailure(String str) {
340 try {
341 BigDecimal value = NumberUtils.createBigDecimal(str);
342 fail("createBigDecimal(blank) failed: " + value);
343 } catch (NumberFormatException ex) {
344 // empty
345 }
346 }
347
348 // min/max tests
349 // ----------------------------------------------------------------------
350 @Test(expected = IllegalArgumentException.class)
351 public void testMinLong_nullArray() {
352 NumberUtils.min((long[]) null);
353 }
354
355 @Test(expected = IllegalArgumentException.class)
356 public void testMinLong_emptyArray() {
357 NumberUtils.min(new long[0]);
358 }
359
360 @Test
361 public void testMinLong() {
362 assertEquals(
363 "min(long[]) failed for array length 1",
364 5,
365 NumberUtils.min(new long[] { 5 }));
366
367 assertEquals(
368 "min(long[]) failed for array length 2",
369 6,
370 NumberUtils.min(new long[] { 6, 9 }));
371
372 assertEquals(-10, NumberUtils.min(new long[] { -10, -5, 0, 5, 10 }));
373 assertEquals(-10, NumberUtils.min(new long[] { -5, 0, -10, 5, 10 }));
374 }
375
376 @Test(expected = IllegalArgumentException.class)
377 public void testMinInt_nullArray() {
378 NumberUtils.min((int[]) null);
379 }
380
381 @Test(expected = IllegalArgumentException.class)
382 public void testMinInt_emptyArray() {
383 NumberUtils.min(new int[0]);
384 }
385
386 @Test
387 public void testMinInt() {
388 assertEquals(
389 "min(int[]) failed for array length 1",
390 5,
391 NumberUtils.min(new int[] { 5 }));
392
393 assertEquals(
394 "min(int[]) failed for array length 2",
395 6,
396 NumberUtils.min(new int[] { 6, 9 }));
397
398 assertEquals(-10, NumberUtils.min(new int[] { -10, -5, 0, 5, 10 }));
399 assertEquals(-10, NumberUtils.min(new int[] { -5, 0, -10, 5, 10 }));
400 }
401
402 @Test(expected = IllegalArgumentException.class)
403 public void testMinShort_nullArray() {
404 NumberUtils.min((short[]) null);
405 }
406
407 @Test(expected = IllegalArgumentException.class)
408 public void testMinShort_emptyArray() {
409 NumberUtils.min(new short[0]);
410 }
411
412 @Test
413 public void testMinShort() {
414 assertEquals(
415 "min(short[]) failed for array length 1",
416 5,
417 NumberUtils.min(new short[] { 5 }));
418
419 assertEquals(
420 "min(short[]) failed for array length 2",
421 6,
422 NumberUtils.min(new short[] { 6, 9 }));
423
424 assertEquals(-10, NumberUtils.min(new short[] { -10, -5, 0, 5, 10 }));
425 assertEquals(-10, NumberUtils.min(new short[] { -5, 0, -10, 5, 10 }));
426 }
427
428 @Test(expected = IllegalArgumentException.class)
429 public void testMinByte_nullArray() {
430 NumberUtils.min((byte[]) null);
431 }
432
433 @Test(expected = IllegalArgumentException.class)
434 public void testMinByte_emptyArray() {
435 NumberUtils.min(new byte[0]);
436 }
437
438 @Test
439 public void testMinByte() {
440 assertEquals(
441 "min(byte[]) failed for array length 1",
442 5,
443 NumberUtils.min(new byte[] { 5 }));
444
445 assertEquals(
446 "min(byte[]) failed for array length 2",
447 6,
448 NumberUtils.min(new byte[] { 6, 9 }));
449
450 assertEquals(-10, NumberUtils.min(new byte[] { -10, -5, 0, 5, 10 }));
451 assertEquals(-10, NumberUtils.min(new byte[] { -5, 0, -10, 5, 10 }));
452 }
453
454 @Test(expected = IllegalArgumentException.class)
455 public void testMinDouble_nullArray() {
456 NumberUtils.min((double[]) null);
457 }
458
459 @Test(expected = IllegalArgumentException.class)
460 public void testMinDouble_emptyArray() {
461 NumberUtils.min(new double[0]);
462 }
463
464 @Test
465 public void testMinDouble() {
466 assertEquals(
467 "min(double[]) failed for array length 1",
468 5.12,
469 NumberUtils.min(new double[] { 5.12 }),
470 0);
471
472 assertEquals(
473 "min(double[]) failed for array length 2",
474 6.23,
475 NumberUtils.min(new double[] { 6.23, 9.34 }),
476 0);
477
478 assertEquals(
479 "min(double[]) failed for array length 5",
480 -10.45,
481 NumberUtils.min(new double[] { -10.45, -5.56, 0, 5.67, 10.78 }),
482 0);
483 assertEquals(-10, NumberUtils.min(new double[] { -10, -5, 0, 5, 10 }), 0.0001);
484 assertEquals(-10, NumberUtils.min(new double[] { -5, 0, -10, 5, 10 }), 0.0001);
485 }
486
487 @Test(expected = IllegalArgumentException.class)
488 public void testMinFloat_nullArray() {
489 NumberUtils.min((float[]) null);
490 }
491
492 @Test(expected = IllegalArgumentException.class)
493 public void testMinFloat_emptyArray() {
494 NumberUtils.min(new float[0]);
495 }
496
497 @Test
498 public void testMinFloat() {
499 assertEquals(
500 "min(float[]) failed for array length 1",
501 5.9f,
502 NumberUtils.min(new float[] { 5.9f }),
503 0);
504
505 assertEquals(
506 "min(float[]) failed for array length 2",
507 6.8f,
508 NumberUtils.min(new float[] { 6.8f, 9.7f }),
509 0);
510
511 assertEquals(
512 "min(float[]) failed for array length 5",
513 -10.6f,
514 NumberUtils.min(new float[] { -10.6f, -5.5f, 0, 5.4f, 10.3f }),
515 0);
516 assertEquals(-10, NumberUtils.min(new float[] { -10, -5, 0, 5, 10 }), 0.0001f);
517 assertEquals(-10, NumberUtils.min(new float[] { -5, 0, -10, 5, 10 }), 0.0001f);
518 }
519
520 @Test(expected = IllegalArgumentException.class)
521 public void testMaxLong_nullArray() {
522 NumberUtils.max((long[]) null);
523 }
524
525 @Test(expected = IllegalArgumentException.class)
526 public void testMaxLong_emptyArray() {
527 NumberUtils.max(new long[0]);
528 }
529
530 @Test
531 public void testMaxLong() {
532 assertEquals(
533 "max(long[]) failed for array length 1",
534 5,
535 NumberUtils.max(new long[] { 5 }));
536
537 assertEquals(
538 "max(long[]) failed for array length 2",
539 9,
540 NumberUtils.max(new long[] { 6, 9 }));
541
542 assertEquals(
543 "max(long[]) failed for array length 5",
544 10,
545 NumberUtils.max(new long[] { -10, -5, 0, 5, 10 }));
546 assertEquals(10, NumberUtils.max(new long[] { -10, -5, 0, 5, 10 }));
547 assertEquals(10, NumberUtils.max(new long[] { -5, 0, 10, 5, -10 }));
548 }
549
550 @Test(expected = IllegalArgumentException.class)
551 public void testMaxInt_nullArray() {
552 NumberUtils.max((int[]) null);
553 }
554
555 @Test(expected = IllegalArgumentException.class)
556 public void testMaxInt_emptyArray() {
557 NumberUtils.max(new int[0]);
558 }
559
560 @Test
561 public void testMaxInt() {
562 assertEquals(
563 "max(int[]) failed for array length 1",
564 5,
565 NumberUtils.max(new int[] { 5 }));
566
567 assertEquals(
568 "max(int[]) failed for array length 2",
569 9,
570 NumberUtils.max(new int[] { 6, 9 }));
571
572 assertEquals(
573 "max(int[]) failed for array length 5",
574 10,
575 NumberUtils.max(new int[] { -10, -5, 0, 5, 10 }));
576 assertEquals(10, NumberUtils.max(new int[] { -10, -5, 0, 5, 10 }));
577 assertEquals(10, NumberUtils.max(new int[] { -5, 0, 10, 5, -10 }));
578 }
579
580 @Test(expected = IllegalArgumentException.class)
581 public void testMaxShort_nullArray() {
582 NumberUtils.max((short[]) null);
583 }
584
585 @Test(expected = IllegalArgumentException.class)
586 public void testMaxShort_emptyArray() {
587 NumberUtils.max(new short[0]);
588 }
589
590 @Test
591 public void testMaxShort() {
592 assertEquals(
593 "max(short[]) failed for array length 1",
594 5,
595 NumberUtils.max(new short[] { 5 }));
596
597 assertEquals(
598 "max(short[]) failed for array length 2",
599 9,
600 NumberUtils.max(new short[] { 6, 9 }));
601
602 assertEquals(
603 "max(short[]) failed for array length 5",
604 10,
605 NumberUtils.max(new short[] { -10, -5, 0, 5, 10 }));
606 assertEquals(10, NumberUtils.max(new short[] { -10, -5, 0, 5, 10 }));
607 assertEquals(10, NumberUtils.max(new short[] { -5, 0, 10, 5, -10 }));
608 }
609
610 @Test(expected = IllegalArgumentException.class)
611 public void testMaxByte_nullArray() {
612 NumberUtils.max((byte[]) null);
613 }
614
615 @Test(expected = IllegalArgumentException.class)
616 public void testMaxByte_emptyArray() {
617 NumberUtils.max(new byte[0]);
618 }
619
620 @Test
621 public void testMaxByte() {
622 assertEquals(
623 "max(byte[]) failed for array length 1",
624 5,
625 NumberUtils.max(new byte[] { 5 }));
626
627 assertEquals(
628 "max(byte[]) failed for array length 2",
629 9,
630 NumberUtils.max(new byte[] { 6, 9 }));
631
632 assertEquals(
633 "max(byte[]) failed for array length 5",
634 10,
635 NumberUtils.max(new byte[] { -10, -5, 0, 5, 10 }));
636 assertEquals(10, NumberUtils.max(new byte[] { -10, -5, 0, 5, 10 }));
637 assertEquals(10, NumberUtils.max(new byte[] { -5, 0, 10, 5, -10 }));
638 }
639
640 @Test(expected = IllegalArgumentException.class)
641 public void testMaxDouble_nullArray() {
642 NumberUtils.max((double[]) null);
643 }
644
645 @Test(expected = IllegalArgumentException.class)
646 public void testMaxDouble_emptyArray() {
647 NumberUtils.max(new double[0]);
648 }
649
650 @Test
651 public void testMaxDouble() {
652 final double[] d = null;
653 try {
654 NumberUtils.max(d);
655 fail("No exception was thrown for null input.");
656 } catch (IllegalArgumentException ex) {}
657
658 try {
659 NumberUtils.max(new double[0]);
660 fail("No exception was thrown for empty input.");
661 } catch (IllegalArgumentException ex) {}
662
663 assertEquals(
664 "max(double[]) failed for array length 1",
665 5.1f,
666 NumberUtils.max(new double[] { 5.1f }),
667 0);
668
669 assertEquals(
670 "max(double[]) failed for array length 2",
671 9.2f,
672 NumberUtils.max(new double[] { 6.3f, 9.2f }),
673 0);
674
675 assertEquals(
676 "max(double[]) failed for float length 5",
677 10.4f,
678 NumberUtils.max(new double[] { -10.5f, -5.6f, 0, 5.7f, 10.4f }),
679 0);
680 assertEquals(10, NumberUtils.max(new double[] { -10, -5, 0, 5, 10 }), 0.0001);
681 assertEquals(10, NumberUtils.max(new double[] { -5, 0, 10, 5, -10 }), 0.0001);
682 }
683
684 @Test(expected = IllegalArgumentException.class)
685 public void testMaxFloat_nullArray() {
686 NumberUtils.max((float[]) null);
687 }
688
689 @Test(expected = IllegalArgumentException.class)
690 public void testMaxFloat_emptyArray() {
691 NumberUtils.max(new float[0]);
692 }
693
694 @Test
695 public void testMaxFloat() {
696 assertEquals(
697 "max(float[]) failed for array length 1",
698 5.1f,
699 NumberUtils.max(new float[] { 5.1f }),
700 0);
701
702 assertEquals(
703 "max(float[]) failed for array length 2",
704 9.2f,
705 NumberUtils.max(new float[] { 6.3f, 9.2f }),
706 0);
707
708 assertEquals(
709 "max(float[]) failed for float length 5",
710 10.4f,
711 NumberUtils.max(new float[] { -10.5f, -5.6f, 0, 5.7f, 10.4f }),
712 0);
713 assertEquals(10, NumberUtils.max(new float[] { -10, -5, 0, 5, 10 }), 0.0001f);
714 assertEquals(10, NumberUtils.max(new float[] { -5, 0, 10, 5, -10 }), 0.0001f);
715 }
716
717 @Test
718 public void testMinimumLong() {
719 assertEquals("minimum(long,long,long) 1 failed", 12345L, NumberUtils.min(12345L, 12345L + 1L, 12345L + 2L));
720 assertEquals("minimum(long,long,long) 2 failed", 12345L, NumberUtils.min(12345L + 1L, 12345L, 12345 + 2L));
721 assertEquals("minimum(long,long,long) 3 failed", 12345L, NumberUtils.min(12345L + 1L, 12345L + 2L, 12345L));
722 assertEquals("minimum(long,long,long) 4 failed", 12345L, NumberUtils.min(12345L + 1L, 12345L, 12345L));
723 assertEquals("minimum(long,long,long) 5 failed", 12345L, NumberUtils.min(12345L, 12345L, 12345L));
724 }
725
726 @Test
727 public void testMinimumInt() {
728 assertEquals("minimum(int,int,int) 1 failed", 12345, NumberUtils.min(12345, 12345 + 1, 12345 + 2));
729 assertEquals("minimum(int,int,int) 2 failed", 12345, NumberUtils.min(12345 + 1, 12345, 12345 + 2));
730 assertEquals("minimum(int,int,int) 3 failed", 12345, NumberUtils.min(12345 + 1, 12345 + 2, 12345));
731 assertEquals("minimum(int,int,int) 4 failed", 12345, NumberUtils.min(12345 + 1, 12345, 12345));
732 assertEquals("minimum(int,int,int) 5 failed", 12345, NumberUtils.min(12345, 12345, 12345));
733 }
734
735 @Test
736 public void testMinimumShort() {
737 short low = 1234;
738 short mid = 1234 + 1;
739 short high = 1234 + 2;
740 assertEquals("minimum(short,short,short) 1 failed", low, NumberUtils.min(low, mid, high));
741 assertEquals("minimum(short,short,short) 1 failed", low, NumberUtils.min(mid, low, high));
742 assertEquals("minimum(short,short,short) 1 failed", low, NumberUtils.min(mid, high, low));
743 assertEquals("minimum(short,short,short) 1 failed", low, NumberUtils.min(low, mid, low));
744 }
745
746 @Test
747 public void testMinimumByte() {
748 byte low = 123;
749 byte mid = 123 + 1;
750 byte high = 123 + 2;
751 assertEquals("minimum(byte,byte,byte) 1 failed", low, NumberUtils.min(low, mid, high));
752 assertEquals("minimum(byte,byte,byte) 1 failed", low, NumberUtils.min(mid, low, high));
753 assertEquals("minimum(byte,byte,byte) 1 failed", low, NumberUtils.min(mid, high, low));
754 assertEquals("minimum(byte,byte,byte) 1 failed", low, NumberUtils.min(low, mid, low));
755 }
756
757 @Test
758 public void testMinimumDouble() {
759 double low = 12.3;
760 double mid = 12.3 + 1;
761 double high = 12.3 + 2;
762 assertEquals(low, NumberUtils.min(low, mid, high), 0.0001);
763 assertEquals(low, NumberUtils.min(mid, low, high), 0.0001);
764 assertEquals(low, NumberUtils.min(mid, high, low), 0.0001);
765 assertEquals(low, NumberUtils.min(low, mid, low), 0.0001);
766 assertEquals(mid, NumberUtils.min(high, mid, high), 0.0001);
767 }
768
769 @Test
770 public void testMinimumFloat() {
771 float low = 12.3f;
772 float mid = 12.3f + 1;
773 float high = 12.3f + 2;
774 assertEquals(low, NumberUtils.min(low, mid, high), 0.0001f);
775 assertEquals(low, NumberUtils.min(mid, low, high), 0.0001f);
776 assertEquals(low, NumberUtils.min(mid, high, low), 0.0001f);
777 assertEquals(low, NumberUtils.min(low, mid, low), 0.0001f);
778 assertEquals(mid, NumberUtils.min(high, mid, high), 0.0001f);
779 }
780
781 @Test
782 public void testMaximumLong() {
783 assertEquals("maximum(long,long,long) 1 failed", 12345L, NumberUtils.max(12345L, 12345L - 1L, 12345L - 2L));
784 assertEquals("maximum(long,long,long) 2 failed", 12345L, NumberUtils.max(12345L - 1L, 12345L, 12345L - 2L));
785 assertEquals("maximum(long,long,long) 3 failed", 12345L, NumberUtils.max(12345L - 1L, 12345L - 2L, 12345L));
786 assertEquals("maximum(long,long,long) 4 failed", 12345L, NumberUtils.max(12345L - 1L, 12345L, 12345L));
787 assertEquals("maximum(long,long,long) 5 failed", 12345L, NumberUtils.max(12345L, 12345L, 12345L));
788 }
789
790 @Test
791 public void testMaximumInt() {
792 assertEquals("maximum(int,int,int) 1 failed", 12345, NumberUtils.max(12345, 12345 - 1, 12345 - 2));
793 assertEquals("maximum(int,int,int) 2 failed", 12345, NumberUtils.max(12345 - 1, 12345, 12345 - 2));
794 assertEquals("maximum(int,int,int) 3 failed", 12345, NumberUtils.max(12345 - 1, 12345 - 2, 12345));
795 assertEquals("maximum(int,int,int) 4 failed", 12345, NumberUtils.max(12345 - 1, 12345, 12345));
796 assertEquals("maximum(int,int,int) 5 failed", 12345, NumberUtils.max(12345, 12345, 12345));
797 }
798
799 @Test
800 public void testMaximumShort() {
801 short low = 1234;
802 short mid = 1234 + 1;
803 short high = 1234 + 2;
804 assertEquals("maximum(short,short,short) 1 failed", high, NumberUtils.max(low, mid, high));
805 assertEquals("maximum(short,short,short) 1 failed", high, NumberUtils.max(mid, low, high));
806 assertEquals("maximum(short,short,short) 1 failed", high, NumberUtils.max(mid, high, low));
807 assertEquals("maximum(short,short,short) 1 failed", high, NumberUtils.max(high, mid, high));
808 }
809
810 @Test
811 public void testMaximumByte() {
812 byte low = 123;
813 byte mid = 123 + 1;
814 byte high = 123 + 2;
815 assertEquals("maximum(byte,byte,byte) 1 failed", high, NumberUtils.max(low, mid, high));
816 assertEquals("maximum(byte,byte,byte) 1 failed", high, NumberUtils.max(mid, low, high));
817 assertEquals("maximum(byte,byte,byte) 1 failed", high, NumberUtils.max(mid, high, low));
818 assertEquals("maximum(byte,byte,byte) 1 failed", high, NumberUtils.max(high, mid, high));
819 }
820
821 @Test
822 public void testMaximumDouble() {
823 double low = 12.3;
824 double mid = 12.3 + 1;
825 double high = 12.3 + 2;
826 assertEquals(high, NumberUtils.max(low, mid, high), 0.0001);
827 assertEquals(high, NumberUtils.max(mid, low, high), 0.0001);
828 assertEquals(high, NumberUtils.max(mid, high, low), 0.0001);
829 assertEquals(mid, NumberUtils.max(low, mid, low), 0.0001);
830 assertEquals(high, NumberUtils.max(high, mid, high), 0.0001);
831 }
832
833 @Test
834 public void testMaximumFloat() {
835 float low = 12.3f;
836 float mid = 12.3f + 1;
837 float high = 12.3f + 2;
838 assertEquals(high, NumberUtils.max(low, mid, high), 0.0001f);
839 assertEquals(high, NumberUtils.max(mid, low, high), 0.0001f);
840 assertEquals(high, NumberUtils.max(mid, high, low), 0.0001f);
841 assertEquals(mid, NumberUtils.max(low, mid, low), 0.0001f);
842 assertEquals(high, NumberUtils.max(high, mid, high), 0.0001f);
843 }
844
845 // Testing JDK against old Lang functionality
846 @Test
847 public void testCompareDouble() {
848 assertTrue(Double.compare(Double.NaN, Double.NaN) == 0);
849 assertTrue(Double.compare(Double.NaN, Double.POSITIVE_INFINITY) == +1);
850 assertTrue(Double.compare(Double.NaN, Double.MAX_VALUE) == +1);
851 assertTrue(Double.compare(Double.NaN, 1.2d) == +1);
852 assertTrue(Double.compare(Double.NaN, 0.0d) == +1);
853 assertTrue(Double.compare(Double.NaN, -0.0d) == +1);
854 assertTrue(Double.compare(Double.NaN, -1.2d) == +1);
855 assertTrue(Double.compare(Double.NaN, -Double.MAX_VALUE) == +1);
856 assertTrue(Double.compare(Double.NaN, Double.NEGATIVE_INFINITY) == +1);
857
858 assertTrue(Double.compare(Double.POSITIVE_INFINITY, Double.NaN) == -1);
859 assertTrue(Double.compare(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY) == 0);
860 assertTrue(Double.compare(Double.POSITIVE_INFINITY, Double.MAX_VALUE) == +1);
861 assertTrue(Double.compare(Double.POSITIVE_INFINITY, 1.2d) == +1);
862 assertTrue(Double.compare(Double.POSITIVE_INFINITY, 0.0d) == +1);
863 assertTrue(Double.compare(Double.POSITIVE_INFINITY, -0.0d) == +1);
864 assertTrue(Double.compare(Double.POSITIVE_INFINITY, -1.2d) == +1);
865 assertTrue(Double.compare(Double.POSITIVE_INFINITY, -Double.MAX_VALUE) == +1);
866 assertTrue(Double.compare(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY) == +1);
867
868 assertTrue(Double.compare(Double.MAX_VALUE, Double.NaN) == -1);
869 assertTrue(Double.compare(Double.MAX_VALUE, Double.POSITIVE_INFINITY) == -1);
870 assertTrue(Double.compare(Double.MAX_VALUE, Double.MAX_VALUE) == 0);
871 assertTrue(Double.compare(Double.MAX_VALUE, 1.2d) == +1);
872 assertTrue(Double.compare(Double.MAX_VALUE, 0.0d) == +1);
873 assertTrue(Double.compare(Double.MAX_VALUE, -0.0d) == +1);
874 assertTrue(Double.compare(Double.MAX_VALUE, -1.2d) == +1);
875 assertTrue(Double.compare(Double.MAX_VALUE, -Double.MAX_VALUE) == +1);
876 assertTrue(Double.compare(Double.MAX_VALUE, Double.NEGATIVE_INFINITY) == +1);
877
878 assertTrue(Double.compare(1.2d, Double.NaN) == -1);
879 assertTrue(Double.compare(1.2d, Double.POSITIVE_INFINITY) == -1);
880 assertTrue(Double.compare(1.2d, Double.MAX_VALUE) == -1);
881 assertTrue(Double.compare(1.2d, 1.2d) == 0);
882 assertTrue(Double.compare(1.2d, 0.0d) == +1);
883 assertTrue(Double.compare(1.2d, -0.0d) == +1);
884 assertTrue(Double.compare(1.2d, -1.2d) == +1);
885 assertTrue(Double.compare(1.2d, -Double.MAX_VALUE) == +1);
886 assertTrue(Double.compare(1.2d, Double.NEGATIVE_INFINITY) == +1);
887
888 assertTrue(Double.compare(0.0d, Double.NaN) == -1);
889 assertTrue(Double.compare(0.0d, Double.POSITIVE_INFINITY) == -1);
890 assertTrue(Double.compare(0.0d, Double.MAX_VALUE) == -1);
891 assertTrue(Double.compare(0.0d, 1.2d) == -1);
892 assertTrue(Double.compare(0.0d, 0.0d) == 0);
893 assertTrue(Double.compare(0.0d, -0.0d) == +1);
894 assertTrue(Double.compare(0.0d, -1.2d) == +1);
895 assertTrue(Double.compare(0.0d, -Double.MAX_VALUE) == +1);
896 assertTrue(Double.compare(0.0d, Double.NEGATIVE_INFINITY) == +1);
897
898 assertTrue(Double.compare(-0.0d, Double.NaN) == -1);
899 assertTrue(Double.compare(-0.0d, Double.POSITIVE_INFINITY) == -1);
900 assertTrue(Double.compare(-0.0d, Double.MAX_VALUE) == -1);
901 assertTrue(Double.compare(-0.0d, 1.2d) == -1);
902 assertTrue(Double.compare(-0.0d, 0.0d) == -1);
903 assertTrue(Double.compare(-0.0d, -0.0d) == 0);
904 assertTrue(Double.compare(-0.0d, -1.2d) == +1);
905 assertTrue(Double.compare(-0.0d, -Double.MAX_VALUE) == +1);
906 assertTrue(Double.compare(-0.0d, Double.NEGATIVE_INFINITY) == +1);
907
908 assertTrue(Double.compare(-1.2d, Double.NaN) == -1);
909 assertTrue(Double.compare(-1.2d, Double.POSITIVE_INFINITY) == -1);
910 assertTrue(Double.compare(-1.2d, Double.MAX_VALUE) == -1);
911 assertTrue(Double.compare(-1.2d, 1.2d) == -1);
912 assertTrue(Double.compare(-1.2d, 0.0d) == -1);
913 assertTrue(Double.compare(-1.2d, -0.0d) == -1);
914 assertTrue(Double.compare(-1.2d, -1.2d) == 0);
915 assertTrue(Double.compare(-1.2d, -Double.MAX_VALUE) == +1);
916 assertTrue(Double.compare(-1.2d, Double.NEGATIVE_INFINITY) == +1);
917
918 assertTrue(Double.compare(-Double.MAX_VALUE, Double.NaN) == -1);
919 assertTrue(Double.compare(-Double.MAX_VALUE, Double.POSITIVE_INFINITY) == -1);
920 assertTrue(Double.compare(-Double.MAX_VALUE, Double.MAX_VALUE) == -1);
921 assertTrue(Double.compare(-Double.MAX_VALUE, 1.2d) == -1);
922 assertTrue(Double.compare(-Double.MAX_VALUE, 0.0d) == -1);
923 assertTrue(Double.compare(-Double.MAX_VALUE, -0.0d) == -1);
924 assertTrue(Double.compare(-Double.MAX_VALUE, -1.2d) == -1);
925 assertTrue(Double.compare(-Double.MAX_VALUE, -Double.MAX_VALUE) == 0);
926 assertTrue(Double.compare(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY) == +1);
927
928 assertTrue(Double.compare(Double.NEGATIVE_INFINITY, Double.NaN) == -1);
929 assertTrue(Double.compare(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY) == -1);
930 assertTrue(Double.compare(Double.NEGATIVE_INFINITY, Double.MAX_VALUE) == -1);
931 assertTrue(Double.compare(Double.NEGATIVE_INFINITY, 1.2d) == -1);
932 assertTrue(Double.compare(Double.NEGATIVE_INFINITY, 0.0d) == -1);
933 assertTrue(Double.compare(Double.NEGATIVE_INFINITY, -0.0d) == -1);
934 assertTrue(Double.compare(Double.NEGATIVE_INFINITY, -1.2d) == -1);
935 assertTrue(Double.compare(Double.NEGATIVE_INFINITY, -Double.MAX_VALUE) == -1);
936 assertTrue(Double.compare(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY) == 0);
937 }
938
939 @Test
940 public void testCompareFloat() {
941 assertTrue(Float.compare(Float.NaN, Float.NaN) == 0);
942 assertTrue(Float.compare(Float.NaN, Float.POSITIVE_INFINITY) == +1);
943 assertTrue(Float.compare(Float.NaN, Float.MAX_VALUE) == +1);
944 assertTrue(Float.compare(Float.NaN, 1.2f) == +1);
945 assertTrue(Float.compare(Float.NaN, 0.0f) == +1);
946 assertTrue(Float.compare(Float.NaN, -0.0f) == +1);
947 assertTrue(Float.compare(Float.NaN, -1.2f) == +1);
948 assertTrue(Float.compare(Float.NaN, -Float.MAX_VALUE) == +1);
949 assertTrue(Float.compare(Float.NaN, Float.NEGATIVE_INFINITY) == +1);
950
951 assertTrue(Float.compare(Float.POSITIVE_INFINITY, Float.NaN) == -1);
952 assertTrue(Float.compare(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY) == 0);
953 assertTrue(Float.compare(Float.POSITIVE_INFINITY, Float.MAX_VALUE) == +1);
954 assertTrue(Float.compare(Float.POSITIVE_INFINITY, 1.2f) == +1);
955 assertTrue(Float.compare(Float.POSITIVE_INFINITY, 0.0f) == +1);
956 assertTrue(Float.compare(Float.POSITIVE_INFINITY, -0.0f) == +1);
957 assertTrue(Float.compare(Float.POSITIVE_INFINITY, -1.2f) == +1);
958 assertTrue(Float.compare(Float.POSITIVE_INFINITY, -Float.MAX_VALUE) == +1);
959 assertTrue(Float.compare(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY) == +1);
960
961 assertTrue(Float.compare(Float.MAX_VALUE, Float.NaN) == -1);
962 assertTrue(Float.compare(Float.MAX_VALUE, Float.POSITIVE_INFINITY) == -1);
963 assertTrue(Float.compare(Float.MAX_VALUE, Float.MAX_VALUE) == 0);
964 assertTrue(Float.compare(Float.MAX_VALUE, 1.2f) == +1);
965 assertTrue(Float.compare(Float.MAX_VALUE, 0.0f) == +1);
966 assertTrue(Float.compare(Float.MAX_VALUE, -0.0f) == +1);
967 assertTrue(Float.compare(Float.MAX_VALUE, -1.2f) == +1);
968 assertTrue(Float.compare(Float.MAX_VALUE, -Float.MAX_VALUE) == +1);
969 assertTrue(Float.compare(Float.MAX_VALUE, Float.NEGATIVE_INFINITY) == +1);
970
971 assertTrue(Float.compare(1.2f, Float.NaN) == -1);
972 assertTrue(Float.compare(1.2f, Float.POSITIVE_INFINITY) == -1);
973 assertTrue(Float.compare(1.2f, Float.MAX_VALUE) == -1);
974 assertTrue(Float.compare(1.2f, 1.2f) == 0);
975 assertTrue(Float.compare(1.2f, 0.0f) == +1);
976 assertTrue(Float.compare(1.2f, -0.0f) == +1);
977 assertTrue(Float.compare(1.2f, -1.2f) == +1);
978 assertTrue(Float.compare(1.2f, -Float.MAX_VALUE) == +1);
979 assertTrue(Float.compare(1.2f, Float.NEGATIVE_INFINITY) == +1);
980
981 assertTrue(Float.compare(0.0f, Float.NaN) == -1);
982 assertTrue(Float.compare(0.0f, Float.POSITIVE_INFINITY) == -1);
983 assertTrue(Float.compare(0.0f, Float.MAX_VALUE) == -1);
984 assertTrue(Float.compare(0.0f, 1.2f) == -1);
985 assertTrue(Float.compare(0.0f, 0.0f) == 0);
986 assertTrue(Float.compare(0.0f, -0.0f) == +1);
987 assertTrue(Float.compare(0.0f, -1.2f) == +1);
988 assertTrue(Float.compare(0.0f, -Float.MAX_VALUE) == +1);
989 assertTrue(Float.compare(0.0f, Float.NEGATIVE_INFINITY) == +1);
990
991 assertTrue(Float.compare(-0.0f, Float.NaN) == -1);
992 assertTrue(Float.compare(-0.0f, Float.POSITIVE_INFINITY) == -1);
993 assertTrue(Float.compare(-0.0f, Float.MAX_VALUE) == -1);
994 assertTrue(Float.compare(-0.0f, 1.2f) == -1);
995 assertTrue(Float.compare(-0.0f, 0.0f) == -1);
996 assertTrue(Float.compare(-0.0f, -0.0f) == 0);
997 assertTrue(Float.compare(-0.0f, -1.2f) == +1);
998 assertTrue(Float.compare(-0.0f, -Float.MAX_VALUE) == +1);
999 assertTrue(Float.compare(-0.0f, Float.NEGATIVE_INFINITY) == +1);
1000
1001 assertTrue(Float.compare(-1.2f, Float.NaN) == -1);
1002 assertTrue(Float.compare(-1.2f, Float.POSITIVE_INFINITY) == -1);
1003 assertTrue(Float.compare(-1.2f, Float.MAX_VALUE) == -1);
1004 assertTrue(Float.compare(-1.2f, 1.2f) == -1);
1005 assertTrue(Float.compare(-1.2f, 0.0f) == -1);
1006 assertTrue(Float.compare(-1.2f, -0.0f) == -1);
1007 assertTrue(Float.compare(-1.2f, -1.2f) == 0);
1008 assertTrue(Float.compare(-1.2f, -Float.MAX_VALUE) == +1);
1009 assertTrue(Float.compare(-1.2f, Float.NEGATIVE_INFINITY) == +1);
1010
1011 assertTrue(Float.compare(-Float.MAX_VALUE, Float.NaN) == -1);
1012 assertTrue(Float.compare(-Float.MAX_VALUE, Float.POSITIVE_INFINITY) == -1);
1013 assertTrue(Float.compare(-Float.MAX_VALUE, Float.MAX_VALUE) == -1);
1014 assertTrue(Float.compare(-Float.MAX_VALUE, 1.2f) == -1);
1015 assertTrue(Float.compare(-Float.MAX_VALUE, 0.0f) == -1);
1016 assertTrue(Float.compare(-Float.MAX_VALUE, -0.0f) == -1);
1017 assertTrue(Float.compare(-Float.MAX_VALUE, -1.2f) == -1);
1018 assertTrue(Float.compare(-Float.MAX_VALUE, -Float.MAX_VALUE) == 0);
1019 assertTrue(Float.compare(-Float.MAX_VALUE, Float.NEGATIVE_INFINITY) == +1);
1020
1021 assertTrue(Float.compare(Float.NEGATIVE_INFINITY, Float.NaN) == -1);
1022 assertTrue(Float.compare(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY) == -1);
1023 assertTrue(Float.compare(Float.NEGATIVE_INFINITY, Float.MAX_VALUE) == -1);
1024 assertTrue(Float.compare(Float.NEGATIVE_INFINITY, 1.2f) == -1);
1025 assertTrue(Float.compare(Float.NEGATIVE_INFINITY, 0.0f) == -1);
1026 assertTrue(Float.compare(Float.NEGATIVE_INFINITY, -0.0f) == -1);
1027 assertTrue(Float.compare(Float.NEGATIVE_INFINITY, -1.2f) == -1);
1028 assertTrue(Float.compare(Float.NEGATIVE_INFINITY, -Float.MAX_VALUE) == -1);
1029 assertTrue(Float.compare(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY) == 0);
1030 }
1031
1032 @Test
1033 public void testIsDigits() {
1034 assertEquals("isDigits(null) failed", false, NumberUtils.isDigits(null));
1035 assertEquals("isDigits('') failed", false, NumberUtils.isDigits(""));
1036 assertEquals("isDigits(String) failed", true, NumberUtils.isDigits("12345"));
1037 assertEquals("isDigits(String) neg 1 failed", false, NumberUtils.isDigits("1234.5"));
1038 assertEquals("isDigits(String) neg 3 failed", false, NumberUtils.isDigits("1ab"));
1039 assertEquals("isDigits(String) neg 4 failed", false, NumberUtils.isDigits("abc"));
1040 }
1041
1042 /**
1043 * Tests isNumber(String) and tests that createNumber(String) returns
1044 * a valid number iff isNumber(String) returns false.
1045 */
1046 @Test
1047 public void testIsNumber() {
1048 String val = "12345";
1049 assertTrue("isNumber(String) 1 failed", NumberUtils.isNumber(val));
1050 assertTrue("isNumber(String)/createNumber(String) 1 failed", checkCreateNumber(val));
1051 val = "1234.5";
1052 assertTrue("isNumber(String) 2 failed", NumberUtils.isNumber(val));
1053 assertTrue("isNumber(String)/createNumber(String) 2 failed", checkCreateNumber(val));
1054 val = ".12345";
1055 assertTrue("isNumber(String) 3 failed", NumberUtils.isNumber(val));
1056 assertTrue("isNumber(String)/createNumber(String) 3 failed", checkCreateNumber(val));
1057 val = "1234E5";
1058 assertTrue("isNumber(String) 4 failed", NumberUtils.isNumber(val));
1059 assertTrue("isNumber(String)/createNumber(String) 4 failed", checkCreateNumber(val));
1060 val = "1234E+5";
1061 assertTrue("isNumber(String) 5 failed", NumberUtils.isNumber(val));
1062 assertTrue("isNumber(String)/createNumber(String) 5 failed", checkCreateNumber(val));
1063 val = "1234E-5";
1064 assertTrue("isNumber(String) 6 failed", NumberUtils.isNumber(val));
1065 assertTrue("isNumber(String)/createNumber(String) 6 failed", checkCreateNumber(val));
1066 val = "123.4E5";
1067 assertTrue("isNumber(String) 7 failed", NumberUtils.isNumber(val));
1068 assertTrue("isNumber(String)/createNumber(String) 7 failed", checkCreateNumber(val));
1069 val = "-1234";
1070 assertTrue("isNumber(String) 8 failed", NumberUtils.isNumber(val));
1071 assertTrue("isNumber(String)/createNumber(String) 8 failed", checkCreateNumber(val));
1072 val = "-1234.5";
1073 assertTrue("isNumber(String) 9 failed", NumberUtils.isNumber(val));
1074 assertTrue("isNumber(String)/createNumber(String) 9 failed", checkCreateNumber(val));
1075 val = "-.12345";
1076 assertTrue("isNumber(String) 10 failed", NumberUtils.isNumber(val));
1077 assertTrue("isNumber(String)/createNumber(String) 10 failed", checkCreateNumber(val));
1078 val = "-1234E5";
1079 assertTrue("isNumber(String) 11 failed", NumberUtils.isNumber(val));
1080 assertTrue("isNumber(String)/createNumber(String) 11 failed", checkCreateNumber(val));
1081 val = "0";
1082 assertTrue("isNumber(String) 12 failed", NumberUtils.isNumber(val));
1083 assertTrue("isNumber(String)/createNumber(String) 12 failed", checkCreateNumber(val));
1084 val = "-0";
1085 assertTrue("isNumber(String) 13 failed", NumberUtils.isNumber(val));
1086 assertTrue("isNumber(String)/createNumber(String) 13 failed", checkCreateNumber(val));
1087 val = "01234";
1088 assertTrue("isNumber(String) 14 failed", NumberUtils.isNumber(val));
1089 assertTrue("isNumber(String)/createNumber(String) 14 failed", checkCreateNumber(val));
1090 val = "-01234";
1091 assertTrue("isNumber(String) 15 failed", NumberUtils.isNumber(val));
1092 assertTrue("isNumber(String)/createNumber(String) 15 failed", checkCreateNumber(val));
1093 val = "0xABC123";
1094 assertTrue("isNumber(String) 16 failed", NumberUtils.isNumber(val));
1095 assertTrue("isNumber(String)/createNumber(String) 16 failed", checkCreateNumber(val));
1096 val = "0x0";
1097 assertTrue("isNumber(String) 17 failed", NumberUtils.isNumber(val));
1098 assertTrue("isNumber(String)/createNumber(String) 17 failed", checkCreateNumber(val));
1099 val = "123.4E21D";
1100 assertTrue("isNumber(String) 19 failed", NumberUtils.isNumber(val));
1101 assertTrue("isNumber(String)/createNumber(String) 19 failed", checkCreateNumber(val));
1102 val = "-221.23F";
1103 assertTrue("isNumber(String) 20 failed", NumberUtils.isNumber(val));
1104 assertTrue("isNumber(String)/createNumber(String) 20 failed", checkCreateNumber(val));
1105 val = "22338L";
1106 assertTrue("isNumber(String) 21 failed", NumberUtils.isNumber(val));
1107 assertTrue("isNumber(String)/createNumber(String) 21 failed", checkCreateNumber(val));
1108 val = null;
1109 assertTrue("isNumber(String) 1 Neg failed", !NumberUtils.isNumber(val));
1110 assertTrue("isNumber(String)/createNumber(String) 1 Neg failed", !checkCreateNumber(val));
1111 val = "";
1112 assertTrue("isNumber(String) 2 Neg failed", !NumberUtils.isNumber(val));
1113 assertTrue("isNumber(String)/createNumber(String) 2 Neg failed", !checkCreateNumber(val));
1114 val = "--2.3";
1115 assertTrue("isNumber(String) 3 Neg failed", !NumberUtils.isNumber(val));
1116 assertTrue("isNumber(String)/createNumber(String) 3 Neg failed", !checkCreateNumber(val));
1117 val = ".12.3";
1118 assertTrue("isNumber(String) 4 Neg failed", !NumberUtils.isNumber(val));
1119 assertTrue("isNumber(String)/createNumber(String) 4 Neg failed", !checkCreateNumber(val));
1120 val = "-123E";
1121 assertTrue("isNumber(String) 5 Neg failed", !NumberUtils.isNumber(val));
1122 assertTrue("isNumber(String)/createNumber(String) 5 Neg failed", !checkCreateNumber(val));
1123 val = "-123E+-212";
1124 assertTrue("isNumber(String) 6 Neg failed", !NumberUtils.isNumber(val));
1125 assertTrue("isNumber(String)/createNumber(String) 6 Neg failed", !checkCreateNumber(val));
1126 val = "-123E2.12";
1127 assertTrue("isNumber(String) 7 Neg failed", !NumberUtils.isNumber(val));
1128 assertTrue("isNumber(String)/createNumber(String) 7 Neg failed", !checkCreateNumber(val));
1129 val = "0xGF";
1130 assertTrue("isNumber(String) 8 Neg failed", !NumberUtils.isNumber(val));
1131 assertTrue("isNumber(String)/createNumber(String) 8 Neg failed", !checkCreateNumber(val));
1132 val = "0xFAE-1";
1133 assertTrue("isNumber(String) 9 Neg failed", !NumberUtils.isNumber(val));
1134 assertTrue("isNumber(String)/createNumber(String) 9 Neg failed", !checkCreateNumber(val));
1135 val = ".";
1136 assertTrue("isNumber(String) 10 Neg failed", !NumberUtils.isNumber(val));
1137 assertTrue("isNumber(String)/createNumber(String) 10 Neg failed", !checkCreateNumber(val));
1138 val = "-0ABC123";
1139 assertTrue("isNumber(String) 11 Neg failed", !NumberUtils.isNumber(val));
1140 assertTrue("isNumber(String)/createNumber(String) 11 Neg failed", !checkCreateNumber(val));
1141 val = "123.4E-D";
1142 assertTrue("isNumber(String) 12 Neg failed", !NumberUtils.isNumber(val));
1143 assertTrue("isNumber(String)/createNumber(String) 12 Neg failed", !checkCreateNumber(val));
1144 val = "123.4ED";
1145 assertTrue("isNumber(String) 13 Neg failed", !NumberUtils.isNumber(val));
1146 assertTrue("isNumber(String)/createNumber(String) 13 Neg failed", !checkCreateNumber(val));
1147 val = "1234E5l";
1148 assertTrue("isNumber(String) 14 Neg failed", !NumberUtils.isNumber(val));
1149 assertTrue("isNumber(String)/createNumber(String) 14 Neg failed", !checkCreateNumber(val));
1150 val = "11a";
1151 assertTrue("isNumber(String) 15 Neg failed", !NumberUtils.isNumber(val));
1152 assertTrue("isNumber(String)/createNumber(String) 15 Neg failed", !checkCreateNumber(val));
1153 val = "1a";
1154 assertTrue("isNumber(String) 16 Neg failed", !NumberUtils.isNumber(val));
1155 assertTrue("isNumber(String)/createNumber(String) 16 Neg failed", !checkCreateNumber(val));
1156 val = "a";
1157 assertTrue("isNumber(String) 17 Neg failed", !NumberUtils.isNumber(val));
1158 assertTrue("isNumber(String)/createNumber(String) 17 Neg failed", !checkCreateNumber(val));
1159 val = "11g";
1160 assertTrue("isNumber(String) 18 Neg failed", !NumberUtils.isNumber(val));
1161 assertTrue("isNumber(String)/createNumber(String) 18 Neg failed", !checkCreateNumber(val));
1162 val = "11z";
1163 assertTrue("isNumber(String) 19 Neg failed", !NumberUtils.isNumber(val));
1164 assertTrue("isNumber(String)/createNumber(String) 19 Neg failed", !checkCreateNumber(val));
1165 val = "11def";
1166 assertTrue("isNumber(String) 20 Neg failed", !NumberUtils.isNumber(val));
1167 assertTrue("isNumber(String)/createNumber(String) 20 Neg failed", !checkCreateNumber(val));
1168 val = "11d11";
1169 assertTrue("isNumber(String) 21 Neg failed", !NumberUtils.isNumber(val));
1170 assertTrue("isNumber(String)/createNumber(String) 21 Neg failed", !checkCreateNumber(val));
1171 val = "11 11";
1172 assertTrue("isNumber(String) 22 Neg failed", !NumberUtils.isNumber(val));
1173 assertTrue("isNumber(String)/createNumber(String) 22 Neg failed", !checkCreateNumber(val));
1174 val = " 1111";
1175 assertTrue("isNumber(String) 23 Neg failed", !NumberUtils.isNumber(val));
1176 assertTrue("isNumber(String)/createNumber(String) 23 Neg failed", !checkCreateNumber(val));
1177 val = "1111 ";
1178 assertTrue("isNumber(String) 24 Neg failed", !NumberUtils.isNumber(val));
1179 assertTrue("isNumber(String)/createNumber(String) 24 Neg failed", !checkCreateNumber(val));
1180
1181 // LANG-521
1182 val = "2.";
1183 assertTrue("isNumber(String) LANG-521 failed", NumberUtils.isNumber(val));
1184
1185 // LANG-664
1186 val = "1.1L";
1187 assertFalse("isNumber(String) LANG-664 failed", NumberUtils.isNumber(val));
1188 }
1189
1190 private boolean checkCreateNumber(String val) {
1191 try {
1192 Object obj = NumberUtils.createNumber(val);
1193 if (obj == null) {
1194 return false;
1195 }
1196 return true;
1197 } catch (NumberFormatException e) {
1198 return false;
1199 }
1200 }
1201
1202 @SuppressWarnings("cast") // suppress instanceof warning check
1203 @Test
1204 public void testConstants() {
1205 assertTrue(NumberUtils.LONG_ZERO instanceof Long);
1206 assertTrue(NumberUtils.LONG_ONE instanceof Long);
1207 assertTrue(NumberUtils.LONG_MINUS_ONE instanceof Long);
1208 assertTrue(NumberUtils.INTEGER_ZERO instanceof Integer);
1209 assertTrue(NumberUtils.INTEGER_ONE instanceof Integer);
1210 assertTrue(NumberUtils.INTEGER_MINUS_ONE instanceof Integer);
1211 assertTrue(NumberUtils.SHORT_ZERO instanceof Short);
1212 assertTrue(NumberUtils.SHORT_ONE instanceof Short);
1213 assertTrue(NumberUtils.SHORT_MINUS_ONE instanceof Short);
1214 assertTrue(NumberUtils.BYTE_ZERO instanceof Byte);
1215 assertTrue(NumberUtils.BYTE_ONE instanceof Byte);
1216 assertTrue(NumberUtils.BYTE_MINUS_ONE instanceof Byte);
1217 assertTrue(NumberUtils.DOUBLE_ZERO instanceof Double);
1218 assertTrue(NumberUtils.DOUBLE_ONE instanceof Double);
1219 assertTrue(NumberUtils.DOUBLE_MINUS_ONE instanceof Double);
1220 assertTrue(NumberUtils.FLOAT_ZERO instanceof Float);
1221 assertTrue(NumberUtils.FLOAT_ONE instanceof Float);
1222 assertTrue(NumberUtils.FLOAT_MINUS_ONE instanceof Float);
1223
1224 assertTrue(NumberUtils.LONG_ZERO.longValue() == 0);
1225 assertTrue(NumberUtils.LONG_ONE.longValue() == 1);
1226 assertTrue(NumberUtils.LONG_MINUS_ONE.longValue() == -1);
1227 assertTrue(NumberUtils.INTEGER_ZERO.intValue() == 0);
1228 assertTrue(NumberUtils.INTEGER_ONE.intValue() == 1);
1229 assertTrue(NumberUtils.INTEGER_MINUS_ONE.intValue() == -1);
1230 assertTrue(NumberUtils.SHORT_ZERO.shortValue() == 0);
1231 assertTrue(NumberUtils.SHORT_ONE.shortValue() == 1);
1232 assertTrue(NumberUtils.SHORT_MINUS_ONE.shortValue() == -1);
1233 assertTrue(NumberUtils.BYTE_ZERO.byteValue() == 0);
1234 assertTrue(NumberUtils.BYTE_ONE.byteValue() == 1);
1235 assertTrue(NumberUtils.BYTE_MINUS_ONE.byteValue() == -1);
1236 assertTrue(NumberUtils.DOUBLE_ZERO.doubleValue() == 0.0d);
1237 assertTrue(NumberUtils.DOUBLE_ONE.doubleValue() == 1.0d);
1238 assertTrue(NumberUtils.DOUBLE_MINUS_ONE.doubleValue() == -1.0d);
1239 assertTrue(NumberUtils.FLOAT_ZERO.floatValue() == 0.0f);
1240 assertTrue(NumberUtils.FLOAT_ONE.floatValue() == 1.0f);
1241 assertTrue(NumberUtils.FLOAT_MINUS_ONE.floatValue() == -1.0f);
1242 }
1243
1244 @Test
1245 public void testLang300() {
1246 NumberUtils.createNumber("-1l");
1247 NumberUtils.createNumber("01l");
1248 NumberUtils.createNumber("1l");
1249 }
1250
1251 @Test
1252 public void testLang381() {
1253 assertTrue(Double.isNaN(NumberUtils.min(1.2, 2.5, Double.NaN)));
1254 assertTrue(Double.isNaN(NumberUtils.max(1.2, 2.5, Double.NaN)));
1255 assertTrue(Float.isNaN(NumberUtils.min(1.2f, 2.5f, Float.NaN)));
1256 assertTrue(Float.isNaN(NumberUtils.max(1.2f, 2.5f, Float.NaN)));
1257
1258 double[] a = new double[] { 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
1259 assertTrue(Double.isNaN(NumberUtils.max(a)));
1260 assertTrue(Double.isNaN(NumberUtils.min(a)));
1261
1262 double[] b = new double[] { Double.NaN, 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
1263 assertTrue(Double.isNaN(NumberUtils.max(b)));
1264 assertTrue(Double.isNaN(NumberUtils.min(b)));
1265
1266 float[] aF = new float[] { 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
1267 assertTrue(Float.isNaN(NumberUtils.max(aF)));
1268
1269 float[] bF = new float[] { Float.NaN, 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
1270 assertTrue(Float.isNaN(NumberUtils.max(bF)));
1271 }
1272
1273 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.mutable;
18
19 import junit.framework.TestCase;
20
21 /**
22 * JUnit tests.
23 *
24 * @since 2.2
25 * @see MutableBoolean
26 * @version $Id: MutableBooleanTest.java 1088899 2011-04-05 05:31:27Z bayard $
27 */
28 public class MutableBooleanTest extends TestCase {
29
30 public MutableBooleanTest(String testName) {
31 super(testName);
32 }
33
34 public void testCompareTo() {
35 final MutableBoolean mutBool = new MutableBoolean(false);
36
37 assertEquals(0, mutBool.compareTo(new MutableBoolean(false)));
38 assertEquals(-1, mutBool.compareTo(new MutableBoolean(true)));
39 mutBool.setValue(true);
40 assertEquals(+1, mutBool.compareTo(new MutableBoolean(false)));
41 assertEquals(0, mutBool.compareTo(new MutableBoolean(true)));
42
43 try {
44 mutBool.compareTo(null);
45 fail();
46 } catch (NullPointerException ex) {
47 }
48 }
49
50 // ----------------------------------------------------------------
51 public void testConstructors() {
52 assertEquals(false, new MutableBoolean().booleanValue());
53
54 assertEquals(true, new MutableBoolean(true).booleanValue());
55 assertEquals(false, new MutableBoolean(false).booleanValue());
56
57 assertEquals(true, new MutableBoolean(Boolean.TRUE).booleanValue());
58 assertEquals(false, new MutableBoolean(Boolean.FALSE).booleanValue());
59
60 try {
61 new MutableBoolean(null);
62 fail();
63 } catch (NullPointerException ex) {
64 }
65 }
66
67 public void testEquals() {
68 final MutableBoolean mutBoolA = new MutableBoolean(false);
69 final MutableBoolean mutBoolB = new MutableBoolean(false);
70 final MutableBoolean mutBoolC = new MutableBoolean(true);
71
72 assertEquals(true, mutBoolA.equals(mutBoolA));
73 assertEquals(true, mutBoolA.equals(mutBoolB));
74 assertEquals(true, mutBoolB.equals(mutBoolA));
75 assertEquals(true, mutBoolB.equals(mutBoolB));
76 assertEquals(false, mutBoolA.equals(mutBoolC));
77 assertEquals(false, mutBoolB.equals(mutBoolC));
78 assertEquals(true, mutBoolC.equals(mutBoolC));
79 assertEquals(false, mutBoolA.equals(null));
80 assertEquals(false, mutBoolA.equals(Boolean.FALSE));
81 assertEquals(false, mutBoolA.equals("false"));
82 }
83
84 public void testGetSet() {
85 assertEquals(false, new MutableBoolean().booleanValue());
86 assertEquals(Boolean.FALSE, new MutableBoolean().getValue());
87
88 final MutableBoolean mutBool = new MutableBoolean(false);
89 assertEquals(Boolean.FALSE, mutBool.toBoolean());
90 assertEquals(false, mutBool.booleanValue());
91 assertEquals(true, mutBool.isFalse());
92 assertEquals(false, mutBool.isTrue());
93
94 mutBool.setValue(Boolean.TRUE);
95 assertEquals(Boolean.TRUE, mutBool.toBoolean());
96 assertEquals(true, mutBool.booleanValue());
97 assertEquals(false, mutBool.isFalse());
98 assertEquals(true, mutBool.isTrue());
99
100 mutBool.setValue(false);
101 assertEquals(false, mutBool.booleanValue());
102
103 mutBool.setValue(true);
104 assertEquals(true, mutBool.booleanValue());
105
106 try {
107 mutBool.setValue(null);
108 fail();
109 } catch (NullPointerException ex) {
110 }
111 }
112
113 public void testHashCode() {
114 final MutableBoolean mutBoolA = new MutableBoolean(false);
115 final MutableBoolean mutBoolB = new MutableBoolean(false);
116 final MutableBoolean mutBoolC = new MutableBoolean(true);
117
118 assertEquals(true, mutBoolA.hashCode() == mutBoolA.hashCode());
119 assertEquals(true, mutBoolA.hashCode() == mutBoolB.hashCode());
120 assertEquals(false, mutBoolA.hashCode() == mutBoolC.hashCode());
121 assertEquals(true, mutBoolA.hashCode() == Boolean.FALSE.hashCode());
122 assertEquals(true, mutBoolC.hashCode() == Boolean.TRUE.hashCode());
123 }
124
125 public void testToString() {
126 assertEquals(Boolean.FALSE.toString(), new MutableBoolean(false).toString());
127 assertEquals(Boolean.TRUE.toString(), new MutableBoolean(true).toString());
128 }
129
130 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 import junit.framework.TestCase;
19
20 /**
21 * JUnit tests.
22 *
23 * @version $Id: MutableByteTest.java 1153484 2011-08-03 13:39:42Z ggregory $
24 * @see MutableByte
25 */
26 public class MutableByteTest extends TestCase {
27
28 public MutableByteTest(String testName) {
29 super(testName);
30 }
31
32 // ----------------------------------------------------------------
33 public void testConstructors() {
34 assertEquals((byte) 0, new MutableByte().byteValue());
35
36 assertEquals((byte) 1, new MutableByte((byte) 1).byteValue());
37
38 assertEquals((byte) 2, new MutableByte(Byte.valueOf((byte) 2)).byteValue());
39 assertEquals((byte) 3, new MutableByte(new MutableByte((byte) 3)).byteValue());
40
41 assertEquals((byte) 2, new MutableByte("2").byteValue());
42
43 try {
44 new MutableByte((Number)null);
45 fail();
46 } catch (NullPointerException ex) {}
47 }
48
49 public void testGetSet() {
50 final MutableByte mutNum = new MutableByte((byte) 0);
51 assertEquals((byte) 0, new MutableByte().byteValue());
52 assertEquals(Byte.valueOf((byte) 0), new MutableByte().getValue());
53
54 mutNum.setValue((byte) 1);
55 assertEquals((byte) 1, mutNum.byteValue());
56 assertEquals(Byte.valueOf((byte) 1), mutNum.getValue());
57
58 mutNum.setValue(Byte.valueOf((byte) 2));
59 assertEquals((byte) 2, mutNum.byteValue());
60 assertEquals(Byte.valueOf((byte) 2), mutNum.getValue());
61
62 mutNum.setValue(new MutableByte((byte) 3));
63 assertEquals((byte) 3, mutNum.byteValue());
64 assertEquals(Byte.valueOf((byte) 3), mutNum.getValue());
65 try {
66 mutNum.setValue(null);
67 fail();
68 } catch (NullPointerException ex) {}
69 }
70
71 public void testEquals() {
72 final MutableByte mutNumA = new MutableByte((byte) 0);
73 final MutableByte mutNumB = new MutableByte((byte) 0);
74 final MutableByte mutNumC = new MutableByte((byte) 1);
75
76 assertEquals(true, mutNumA.equals(mutNumA));
77 assertEquals(true, mutNumA.equals(mutNumB));
78 assertEquals(true, mutNumB.equals(mutNumA));
79 assertEquals(true, mutNumB.equals(mutNumB));
80 assertEquals(false, mutNumA.equals(mutNumC));
81 assertEquals(false, mutNumB.equals(mutNumC));
82 assertEquals(true, mutNumC.equals(mutNumC));
83 assertEquals(false, mutNumA.equals(null));
84 assertEquals(false, mutNumA.equals(Byte.valueOf((byte) 0)));
85 assertEquals(false, mutNumA.equals("0"));
86 }
87
88 public void testHashCode() {
89 final MutableByte mutNumA = new MutableByte((byte) 0);
90 final MutableByte mutNumB = new MutableByte((byte) 0);
91 final MutableByte mutNumC = new MutableByte((byte) 1);
92
93 assertEquals(true, mutNumA.hashCode() == mutNumA.hashCode());
94 assertEquals(true, mutNumA.hashCode() == mutNumB.hashCode());
95 assertEquals(false, mutNumA.hashCode() == mutNumC.hashCode());
96 assertEquals(true, mutNumA.hashCode() == Byte.valueOf((byte) 0).hashCode());
97 }
98
99 public void testCompareTo() {
100 final MutableByte mutNum = new MutableByte((byte) 0);
101
102 assertEquals((byte) 0, mutNum.compareTo(new MutableByte((byte) 0)));
103 assertEquals((byte) +1, mutNum.compareTo(new MutableByte((byte) -1)));
104 assertEquals((byte) -1, mutNum.compareTo(new MutableByte((byte) 1)));
105 try {
106 mutNum.compareTo(null);
107 fail();
108 } catch (NullPointerException ex) {}
109 }
110
111 public void testPrimitiveValues() {
112 MutableByte mutNum = new MutableByte( (byte) 1 );
113
114 assertEquals( 1.0F, mutNum.floatValue(), 0 );
115 assertEquals( 1.0, mutNum.doubleValue(), 0 );
116 assertEquals( (byte) 1, mutNum.byteValue() );
117 assertEquals( (short) 1, mutNum.shortValue() );
118 assertEquals( 1, mutNum.intValue() );
119 assertEquals( 1L, mutNum.longValue() );
120 }
121
122 public void testToByte() {
123 assertEquals(Byte.valueOf((byte) 0), new MutableByte((byte) 0).toByte());
124 assertEquals(Byte.valueOf((byte) 123), new MutableByte((byte) 123).toByte());
125 }
126
127 public void testIncrement() {
128 MutableByte mutNum = new MutableByte((byte) 1);
129 mutNum.increment();
130
131 assertEquals(2, mutNum.intValue());
132 assertEquals(2L, mutNum.longValue());
133 }
134
135 public void testDecrement() {
136 MutableByte mutNum = new MutableByte((byte) 1);
137 mutNum.decrement();
138
139 assertEquals(0, mutNum.intValue());
140 assertEquals(0L, mutNum.longValue());
141 }
142
143 public void testAddValuePrimitive() {
144 MutableByte mutNum = new MutableByte((byte) 1);
145 mutNum.add((byte)1);
146
147 assertEquals((byte) 2, mutNum.byteValue());
148 }
149
150 public void testAddValueObject() {
151 MutableByte mutNum = new MutableByte((byte) 1);
152 mutNum.add(Integer.valueOf(1));
153
154 assertEquals((byte) 2, mutNum.byteValue());
155 }
156
157 public void testSubtractValuePrimitive() {
158 MutableByte mutNum = new MutableByte((byte) 1);
159 mutNum.subtract((byte) 1);
160
161 assertEquals((byte) 0, mutNum.byteValue());
162 }
163
164 public void testSubtractValueObject() {
165 MutableByte mutNum = new MutableByte((byte) 1);
166 mutNum.subtract(Integer.valueOf(1));
167
168 assertEquals((byte) 0, mutNum.byteValue());
169 }
170
171 public void testToString() {
172 assertEquals("0", new MutableByte((byte) 0).toString());
173 assertEquals("10", new MutableByte((byte) 10).toString());
174 assertEquals("-123", new MutableByte((byte) -123).toString());
175 }
176
177 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 import junit.framework.TestCase;
19
20 /**
21 * JUnit tests.
22 *
23 * @version $Id: MutableDoubleTest.java 1153490 2011-08-03 13:53:35Z ggregory $
24 * @see MutableDouble
25 */
26 public class MutableDoubleTest extends TestCase {
27
28 public MutableDoubleTest(String testName) {
29 super(testName);
30 }
31
32 // ----------------------------------------------------------------
33 public void testConstructors() {
34 assertEquals(0d, new MutableDouble().doubleValue(), 0.0001d);
35
36 assertEquals(1d, new MutableDouble(1d).doubleValue(), 0.0001d);
37
38 assertEquals(2d, new MutableDouble(Double.valueOf(2d)).doubleValue(), 0.0001d);
39 assertEquals(3d, new MutableDouble(new MutableDouble(3d)).doubleValue(), 0.0001d);
40
41 assertEquals(2d, new MutableDouble("2.0").doubleValue(), 0.0001d);
42
43 try {
44 new MutableDouble((Number)null);
45 fail();
46 } catch (NullPointerException ex) {}
47 }
48
49 public void testGetSet() {
50 final MutableDouble mutNum = new MutableDouble(0d);
51 assertEquals(0d, new MutableDouble().doubleValue(), 0.0001d);
52 assertEquals(Double.valueOf(0), new MutableDouble().getValue());
53
54 mutNum.setValue(1);
55 assertEquals(1d, mutNum.doubleValue(), 0.0001d);
56 assertEquals(Double.valueOf(1d), mutNum.getValue());
57
58 mutNum.setValue(Double.valueOf(2d));
59 assertEquals(2d, mutNum.doubleValue(), 0.0001d);
60 assertEquals(Double.valueOf(2d), mutNum.getValue());
61
62 mutNum.setValue(new MutableDouble(3d));
63 assertEquals(3d, mutNum.doubleValue(), 0.0001d);
64 assertEquals(Double.valueOf(3d), mutNum.getValue());
65 try {
66 mutNum.setValue(null);
67 fail();
68 } catch (NullPointerException ex) {}
69 }
70
71 public void testNanInfinite() {
72 MutableDouble mutNum = new MutableDouble(Double.NaN);
73 assertEquals(true, mutNum.isNaN());
74
75 mutNum = new MutableDouble(Double.POSITIVE_INFINITY);
76 assertEquals(true, mutNum.isInfinite());
77
78 mutNum = new MutableDouble(Double.NEGATIVE_INFINITY);
79 assertEquals(true, mutNum.isInfinite());
80 }
81
82 public void testEquals() {
83 final MutableDouble mutNumA = new MutableDouble(0d);
84 final MutableDouble mutNumB = new MutableDouble(0d);
85 final MutableDouble mutNumC = new MutableDouble(1d);
86
87 assertEquals(true, mutNumA.equals(mutNumA));
88 assertEquals(true, mutNumA.equals(mutNumB));
89 assertEquals(true, mutNumB.equals(mutNumA));
90 assertEquals(true, mutNumB.equals(mutNumB));
91 assertEquals(false, mutNumA.equals(mutNumC));
92 assertEquals(false, mutNumB.equals(mutNumC));
93 assertEquals(true, mutNumC.equals(mutNumC));
94 assertEquals(false, mutNumA.equals(null));
95 assertEquals(false, mutNumA.equals(Double.valueOf(0d)));
96 assertEquals(false, mutNumA.equals("0"));
97 }
98
99 public void testHashCode() {
100 final MutableDouble mutNumA = new MutableDouble(0d);
101 final MutableDouble mutNumB = new MutableDouble(0d);
102 final MutableDouble mutNumC = new MutableDouble(1d);
103
104 assertEquals(true, mutNumA.hashCode() == mutNumA.hashCode());
105 assertEquals(true, mutNumA.hashCode() == mutNumB.hashCode());
106 assertEquals(false, mutNumA.hashCode() == mutNumC.hashCode());
107 assertEquals(true, mutNumA.hashCode() == Double.valueOf(0d).hashCode());
108 }
109
110 public void testCompareTo() {
111 final MutableDouble mutNum = new MutableDouble(0d);
112
113 assertEquals(0, mutNum.compareTo(new MutableDouble(0d)));
114 assertEquals(+1, mutNum.compareTo(new MutableDouble(-1d)));
115 assertEquals(-1, mutNum.compareTo(new MutableDouble(1d)));
116 try {
117 mutNum.compareTo(null);
118 fail();
119 } catch (NullPointerException ex) {}
120 }
121
122 public void testPrimitiveValues() {
123 MutableDouble mutNum = new MutableDouble(1.7);
124
125 assertEquals( 1.7F, mutNum.floatValue(), 0 );
126 assertEquals( 1.7, mutNum.doubleValue(), 0 );
127 assertEquals( (byte) 1, mutNum.byteValue() );
128 assertEquals( (short) 1, mutNum.shortValue() );
129 assertEquals( 1, mutNum.intValue() );
130 assertEquals( 1L, mutNum.longValue() );
131 }
132
133 public void testToDouble() {
134 assertEquals(Double.valueOf(0d), new MutableDouble(0d).toDouble());
135 assertEquals(Double.valueOf(12.3d), new MutableDouble(12.3d).toDouble());
136 }
137
138 public void testIncrement() {
139 MutableDouble mutNum = new MutableDouble(1);
140 mutNum.increment();
141
142 assertEquals(2, mutNum.intValue());
143 assertEquals(2L, mutNum.longValue());
144 }
145
146 public void testDecrement() {
147 MutableDouble mutNum = new MutableDouble(1);
148 mutNum.decrement();
149
150 assertEquals(0, mutNum.intValue());
151 assertEquals(0L, mutNum.longValue());
152 }
153
154 public void testAddValuePrimitive() {
155 MutableDouble mutNum = new MutableDouble(1);
156 mutNum.add(1.1d);
157
158 assertEquals(2.1d, mutNum.doubleValue(), 0.01d);
159 }
160
161 public void testAddValueObject() {
162 MutableDouble mutNum = new MutableDouble(1);
163 mutNum.add(Double.valueOf(1.1d));
164
165 assertEquals(2.1d, mutNum.doubleValue(), 0.01d);
166 }
167
168 public void testSubtractValuePrimitive() {
169 MutableDouble mutNum = new MutableDouble(1);
170 mutNum.subtract(0.9d);
171
172 assertEquals(0.1d, mutNum.doubleValue(), 0.01d);
173 }
174
175 public void testSubtractValueObject() {
176 MutableDouble mutNum = new MutableDouble(1);
177 mutNum.subtract(Double.valueOf(0.9d));
178
179 assertEquals(0.1d, mutNum.doubleValue(), 0.01d);
180 }
181
182 public void testToString() {
183 assertEquals("0.0", new MutableDouble(0d).toString());
184 assertEquals("10.0", new MutableDouble(10d).toString());
185 assertEquals("-123.0", new MutableDouble(-123d).toString());
186 }
187
188 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 import junit.framework.TestCase;
19
20 /**
21 * JUnit tests.
22 *
23 * @version $Id: MutableFloatTest.java 1153490 2011-08-03 13:53:35Z ggregory $
24 * @see MutableFloat
25 */
26 public class MutableFloatTest extends TestCase {
27
28 public MutableFloatTest(String testName) {
29 super(testName);
30 }
31
32 // ----------------------------------------------------------------
33 public void testConstructors() {
34 assertEquals(0f, new MutableFloat().floatValue(), 0.0001f);
35
36 assertEquals(1f, new MutableFloat(1f).floatValue(), 0.0001f);
37
38 assertEquals(2f, new MutableFloat(Float.valueOf(2f)).floatValue(), 0.0001f);
39 assertEquals(3f, new MutableFloat(new MutableFloat(3f)).floatValue(), 0.0001f);
40
41 assertEquals(2f, new MutableFloat("2.0").floatValue(), 0.0001f);
42
43 try {
44 new MutableFloat((Number)null);
45 fail();
46 } catch (NullPointerException ex) {}
47 }
48
49 public void testGetSet() {
50 final MutableFloat mutNum = new MutableFloat(0f);
51 assertEquals(0f, new MutableFloat().floatValue(), 0.0001f);
52 assertEquals(Float.valueOf(0), new MutableFloat().getValue());
53
54 mutNum.setValue(1);
55 assertEquals(1f, mutNum.floatValue(), 0.0001f);
56 assertEquals(Float.valueOf(1f), mutNum.getValue());
57
58 mutNum.setValue(Float.valueOf(2f));
59 assertEquals(2f, mutNum.floatValue(), 0.0001f);
60 assertEquals(Float.valueOf(2f), mutNum.getValue());
61
62 mutNum.setValue(new MutableFloat(3f));
63 assertEquals(3f, mutNum.floatValue(), 0.0001f);
64 assertEquals(Float.valueOf(3f), mutNum.getValue());
65 try {
66 mutNum.setValue(null);
67 fail();
68 } catch (NullPointerException ex) {}
69 }
70
71 public void testNanInfinite() {
72 MutableFloat mutNum = new MutableFloat(Float.NaN);
73 assertEquals(true, mutNum.isNaN());
74
75 mutNum = new MutableFloat(Float.POSITIVE_INFINITY);
76 assertEquals(true, mutNum.isInfinite());
77
78 mutNum = new MutableFloat(Float.NEGATIVE_INFINITY);
79 assertEquals(true, mutNum.isInfinite());
80 }
81
82 public void testEquals() {
83 final MutableFloat mutNumA = new MutableFloat(0f);
84 final MutableFloat mutNumB = new MutableFloat(0f);
85 final MutableFloat mutNumC = new MutableFloat(1f);
86
87 assertEquals(true, mutNumA.equals(mutNumA));
88 assertEquals(true, mutNumA.equals(mutNumB));
89 assertEquals(true, mutNumB.equals(mutNumA));
90 assertEquals(true, mutNumB.equals(mutNumB));
91 assertEquals(false, mutNumA.equals(mutNumC));
92 assertEquals(false, mutNumB.equals(mutNumC));
93 assertEquals(true, mutNumC.equals(mutNumC));
94 assertEquals(false, mutNumA.equals(null));
95 assertEquals(false, mutNumA.equals(Float.valueOf(0f)));
96 assertEquals(false, mutNumA.equals("0"));
97 }
98
99 public void testHashCode() {
100 final MutableFloat mutNumA = new MutableFloat(0f);
101 final MutableFloat mutNumB = new MutableFloat(0f);
102 final MutableFloat mutNumC = new MutableFloat(1f);
103
104 assertEquals(true, mutNumA.hashCode() == mutNumA.hashCode());
105 assertEquals(true, mutNumA.hashCode() == mutNumB.hashCode());
106 assertEquals(false, mutNumA.hashCode() == mutNumC.hashCode());
107 assertEquals(true, mutNumA.hashCode() == Float.valueOf(0f).hashCode());
108 }
109
110 public void testCompareTo() {
111 final MutableFloat mutNum = new MutableFloat(0f);
112
113 assertEquals(0, mutNum.compareTo(new MutableFloat(0f)));
114 assertEquals(+1, mutNum.compareTo(new MutableFloat(-1f)));
115 assertEquals(-1, mutNum.compareTo(new MutableFloat(1f)));
116 try {
117 mutNum.compareTo(null);
118 fail();
119 } catch (NullPointerException ex) {}
120 }
121
122 public void testPrimitiveValues() {
123 MutableFloat mutNum = new MutableFloat(1.7F);
124
125 assertEquals( 1, mutNum.intValue() );
126 assertEquals( 1.7, mutNum.doubleValue(), 0.00001 );
127 assertEquals( (byte) 1, mutNum.byteValue() );
128 assertEquals( (short) 1, mutNum.shortValue() );
129 assertEquals( 1, mutNum.intValue() );
130 assertEquals( 1L, mutNum.longValue() );
131 }
132
133 public void testToFloat() {
134 assertEquals(Float.valueOf(0f), new MutableFloat(0f).toFloat());
135 assertEquals(Float.valueOf(12.3f), new MutableFloat(12.3f).toFloat());
136 }
137
138 public void testIncrement() {
139 MutableFloat mutNum = new MutableFloat(1);
140 mutNum.increment();
141
142 assertEquals(2, mutNum.intValue());
143 assertEquals(2L, mutNum.longValue());
144 }
145
146 public void testDecrement() {
147 MutableFloat mutNum = new MutableFloat(1);
148 mutNum.decrement();
149
150 assertEquals(0, mutNum.intValue());
151 assertEquals(0L, mutNum.longValue());
152 }
153
154 public void testAddValuePrimitive() {
155 MutableFloat mutNum = new MutableFloat(1);
156 mutNum.add(1.1f);
157
158 assertEquals(2.1f, mutNum.floatValue(), 0.01f);
159 }
160
161 public void testAddValueObject() {
162 MutableFloat mutNum = new MutableFloat(1);
163 mutNum.add(Float.valueOf(1.1f));
164
165 assertEquals(2.1f, mutNum.floatValue(), 0.01f);
166 }
167
168 public void testSubtractValuePrimitive() {
169 MutableFloat mutNum = new MutableFloat(1);
170 mutNum.subtract(0.9f);
171
172 assertEquals(0.1f, mutNum.floatValue(), 0.01f);
173 }
174
175 public void testSubtractValueObject() {
176 MutableFloat mutNum = new MutableFloat(1);
177 mutNum.subtract(Float.valueOf(0.9f));
178
179 assertEquals(0.1f, mutNum.floatValue(), 0.01f);
180 }
181
182 public void testToString() {
183 assertEquals("0.0", new MutableFloat(0f).toString());
184 assertEquals("10.0", new MutableFloat(10f).toString());
185 assertEquals("-123.0", new MutableFloat(-123f).toString());
186 }
187
188 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 import junit.framework.TestCase;
19
20 /**
21 * JUnit tests.
22 *
23 * @version $Id: MutableIntTest.java 1153484 2011-08-03 13:39:42Z ggregory $
24 * @see MutableInt
25 */
26 public class MutableIntTest extends TestCase {
27
28 public MutableIntTest(String testName) {
29 super(testName);
30 }
31
32 // ----------------------------------------------------------------
33 public void testConstructors() {
34 assertEquals(0, new MutableInt().intValue());
35
36 assertEquals(1, new MutableInt(1).intValue());
37
38 assertEquals(2, new MutableInt(Integer.valueOf(2)).intValue());
39 assertEquals(3, new MutableInt(new MutableLong(3)).intValue());
40
41 assertEquals(2, new MutableInt("2").intValue());
42
43 try {
44 new MutableInt((Number)null);
45 fail();
46 } catch (NullPointerException ex) {}
47 }
48
49 public void testGetSet() {
50 final MutableInt mutNum = new MutableInt(0);
51 assertEquals(0, new MutableInt().intValue());
52 assertEquals(Integer.valueOf(0), new MutableInt().getValue());
53
54 mutNum.setValue(1);
55 assertEquals(1, mutNum.intValue());
56 assertEquals(Integer.valueOf(1), mutNum.getValue());
57
58 mutNum.setValue(Integer.valueOf(2));
59 assertEquals(2, mutNum.intValue());
60 assertEquals(Integer.valueOf(2), mutNum.getValue());
61
62 mutNum.setValue(new MutableLong(3));
63 assertEquals(3, mutNum.intValue());
64 assertEquals(Integer.valueOf(3), mutNum.getValue());
65 try {
66 mutNum.setValue(null);
67 fail();
68 } catch (NullPointerException ex) {}
69 }
70
71 public void testEquals() {
72 this.testEquals(new MutableInt(0), new MutableInt(0), new MutableInt(1));
73 // Should Numbers be supported? GaryG July-21-2005.
74 //this.testEquals(mutNumA, Integer.valueOf(0), mutNumC);
75 }
76
77 /**
78 * @param numA must not be a 0 Integer; must not equal numC.
79 * @param numB must equal numA; must not equal numC.
80 * @param numC must not equal numA; must not equal numC.
81 */
82 void testEquals(final Number numA, final Number numB, final Number numC) {
83 assertEquals(true, numA.equals(numA));
84 assertEquals(true, numA.equals(numB));
85 assertEquals(true, numB.equals(numA));
86 assertEquals(true, numB.equals(numB));
87 assertEquals(false, numA.equals(numC));
88 assertEquals(false, numB.equals(numC));
89 assertEquals(true, numC.equals(numC));
90 assertEquals(false, numA.equals(null));
91 assertEquals(false, numA.equals(Integer.valueOf(0)));
92 assertEquals(false, numA.equals("0"));
93 }
94
95 public void testHashCode() {
96 final MutableInt mutNumA = new MutableInt(0);
97 final MutableInt mutNumB = new MutableInt(0);
98 final MutableInt mutNumC = new MutableInt(1);
99
100 assertEquals(true, mutNumA.hashCode() == mutNumA.hashCode());
101 assertEquals(true, mutNumA.hashCode() == mutNumB.hashCode());
102 assertEquals(false, mutNumA.hashCode() == mutNumC.hashCode());
103 assertEquals(true, mutNumA.hashCode() == Integer.valueOf(0).hashCode());
104 }
105
106 public void testCompareTo() {
107 final MutableInt mutNum = new MutableInt(0);
108
109 assertEquals(0, mutNum.compareTo(new MutableInt(0)));
110 assertEquals(+1, mutNum.compareTo(new MutableInt(-1)));
111 assertEquals(-1, mutNum.compareTo(new MutableInt(1)));
112 try {
113 mutNum.compareTo(null);
114 fail();
115 } catch (NullPointerException ex) {}
116 }
117
118 public void testPrimitiveValues() {
119 MutableInt mutNum = new MutableInt(1);
120
121 assertEquals( (byte) 1, mutNum.byteValue() );
122 assertEquals( (short) 1, mutNum.shortValue() );
123 assertEquals( 1.0F, mutNum.floatValue(), 0 );
124 assertEquals( 1.0, mutNum.doubleValue(), 0 );
125 assertEquals( 1L, mutNum.longValue() );
126 }
127
128 public void testToInteger() {
129 assertEquals(Integer.valueOf(0), new MutableInt(0).toInteger());
130 assertEquals(Integer.valueOf(123), new MutableInt(123).toInteger());
131 }
132
133 public void testIncrement() {
134 MutableInt mutNum = new MutableInt(1);
135 mutNum.increment();
136
137 assertEquals(2, mutNum.intValue());
138 assertEquals(2L, mutNum.longValue());
139 }
140
141 public void testDecrement() {
142 MutableInt mutNum = new MutableInt(1);
143 mutNum.decrement();
144
145 assertEquals(0, mutNum.intValue());
146 assertEquals(0L, mutNum.longValue());
147 }
148
149 public void testAddValuePrimitive() {
150 MutableInt mutNum = new MutableInt(1);
151 mutNum.add(1);
152
153 assertEquals(2, mutNum.intValue());
154 assertEquals(2L, mutNum.longValue());
155 }
156
157 public void testAddValueObject() {
158 MutableInt mutNum = new MutableInt(1);
159 mutNum.add(Integer.valueOf(1));
160
161 assertEquals(2, mutNum.intValue());
162 assertEquals(2L, mutNum.longValue());
163 }
164
165 public void testSubtractValuePrimitive() {
166 MutableInt mutNum = new MutableInt(1);
167 mutNum.subtract(1);
168
169 assertEquals(0, mutNum.intValue());
170 assertEquals(0L, mutNum.longValue());
171 }
172
173 public void testSubtractValueObject() {
174 MutableInt mutNum = new MutableInt(1);
175 mutNum.subtract(Integer.valueOf(1));
176
177 assertEquals(0, mutNum.intValue());
178 assertEquals(0L, mutNum.longValue());
179 }
180
181 public void testToString() {
182 assertEquals("0", new MutableInt(0).toString());
183 assertEquals("10", new MutableInt(10).toString());
184 assertEquals("-123", new MutableInt(-123).toString());
185 }
186
187 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 import junit.framework.TestCase;
19
20 /**
21 * JUnit tests.
22 *
23 * @version $Id: MutableLongTest.java 1153487 2011-08-03 13:44:51Z ggregory $
24 * @see MutableLong
25 */
26 public class MutableLongTest extends TestCase {
27
28 public MutableLongTest(String testName) {
29 super(testName);
30 }
31
32 // ----------------------------------------------------------------
33 public void testConstructors() {
34 assertEquals(0, new MutableLong().longValue());
35
36 assertEquals(1, new MutableLong(1).longValue());
37
38 assertEquals(2, new MutableLong(Long.valueOf(2)).longValue());
39 assertEquals(3, new MutableLong(new MutableLong(3)).longValue());
40
41 assertEquals(2, new MutableLong("2").longValue());
42
43 try {
44 new MutableLong((Number)null);
45 fail();
46 } catch (NullPointerException ex) {}
47 }
48
49 public void testGetSet() {
50 final MutableLong mutNum = new MutableLong(0);
51 assertEquals(0, new MutableLong().longValue());
52 assertEquals(Long.valueOf(0), new MutableLong().getValue());
53
54 mutNum.setValue(1);
55 assertEquals(1, mutNum.longValue());
56 assertEquals(Long.valueOf(1), mutNum.getValue());
57
58 mutNum.setValue(Long.valueOf(2));
59 assertEquals(2, mutNum.longValue());
60 assertEquals(Long.valueOf(2), mutNum.getValue());
61
62 mutNum.setValue(new MutableLong(3));
63 assertEquals(3, mutNum.longValue());
64 assertEquals(Long.valueOf(3), mutNum.getValue());
65 try {
66 mutNum.setValue(null);
67 fail();
68 } catch (NullPointerException ex) {}
69 }
70
71 public void testEquals() {
72 final MutableLong mutNumA = new MutableLong(0);
73 final MutableLong mutNumB = new MutableLong(0);
74 final MutableLong mutNumC = new MutableLong(1);
75
76 assertEquals(true, mutNumA.equals(mutNumA));
77 assertEquals(true, mutNumA.equals(mutNumB));
78 assertEquals(true, mutNumB.equals(mutNumA));
79 assertEquals(true, mutNumB.equals(mutNumB));
80 assertEquals(false, mutNumA.equals(mutNumC));
81 assertEquals(false, mutNumB.equals(mutNumC));
82 assertEquals(true, mutNumC.equals(mutNumC));
83 assertEquals(false, mutNumA.equals(null));
84 assertEquals(false, mutNumA.equals(Long.valueOf(0)));
85 assertEquals(false, mutNumA.equals("0"));
86 }
87
88 public void testHashCode() {
89 final MutableLong mutNumA = new MutableLong(0);
90 final MutableLong mutNumB = new MutableLong(0);
91 final MutableLong mutNumC = new MutableLong(1);
92
93 assertEquals(true, mutNumA.hashCode() == mutNumA.hashCode());
94 assertEquals(true, mutNumA.hashCode() == mutNumB.hashCode());
95 assertEquals(false, mutNumA.hashCode() == mutNumC.hashCode());
96 assertEquals(true, mutNumA.hashCode() == Long.valueOf(0).hashCode());
97 }
98
99 public void testCompareTo() {
100 final MutableLong mutNum = new MutableLong(0);
101
102 assertEquals(0, mutNum.compareTo(new MutableLong(0)));
103 assertEquals(+1, mutNum.compareTo(new MutableLong(-1)));
104 assertEquals(-1, mutNum.compareTo(new MutableLong(1)));
105 try {
106 mutNum.compareTo(null);
107 fail();
108 } catch (NullPointerException ex) {}
109 }
110
111 public void testPrimitiveValues() {
112 MutableLong mutNum = new MutableLong(1L);
113
114 assertEquals( 1.0F, mutNum.floatValue(), 0 );
115 assertEquals( 1.0, mutNum.doubleValue(), 0 );
116 assertEquals( (byte) 1, mutNum.byteValue() );
117 assertEquals( (short) 1, mutNum.shortValue() );
118 assertEquals( 1, mutNum.intValue() );
119 assertEquals( 1L, mutNum.longValue() );
120 }
121
122 public void testToLong() {
123 assertEquals(Long.valueOf(0L), new MutableLong(0L).toLong());
124 assertEquals(Long.valueOf(123L), new MutableLong(123L).toLong());
125 }
126
127 public void testIncrement() {
128 MutableLong mutNum = new MutableLong(1);
129 mutNum.increment();
130
131 assertEquals(2, mutNum.intValue());
132 assertEquals(2L, mutNum.longValue());
133 }
134
135 public void testDecrement() {
136 MutableLong mutNum = new MutableLong(1);
137 mutNum.decrement();
138
139 assertEquals(0, mutNum.intValue());
140 assertEquals(0L, mutNum.longValue());
141 }
142
143 public void testAddValuePrimitive() {
144 MutableLong mutNum = new MutableLong(1);
145 mutNum.add(1);
146
147 assertEquals(2, mutNum.intValue());
148 assertEquals(2L, mutNum.longValue());
149 }
150
151 public void testAddValueObject() {
152 MutableLong mutNum = new MutableLong(1);
153 mutNum.add(Long.valueOf(1));
154
155 assertEquals(2, mutNum.intValue());
156 assertEquals(2L, mutNum.longValue());
157 }
158
159 public void testSubtractValuePrimitive() {
160 MutableLong mutNum = new MutableLong(1);
161 mutNum.subtract(1);
162
163 assertEquals(0, mutNum.intValue());
164 assertEquals(0L, mutNum.longValue());
165 }
166
167 public void testSubtractValueObject() {
168 MutableLong mutNum = new MutableLong(1);
169 mutNum.subtract(Long.valueOf(1));
170
171 assertEquals(0, mutNum.intValue());
172 assertEquals(0L, mutNum.longValue());
173 }
174
175 public void testToString() {
176 assertEquals("0", new MutableLong(0).toString());
177 assertEquals("10", new MutableLong(10).toString());
178 assertEquals("-123", new MutableLong(-123).toString());
179 }
180
181 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 import junit.framework.TestCase;
19
20 /**
21 * JUnit tests.
22 *
23 * @version $Id: MutableObjectTest.java 1153490 2011-08-03 13:53:35Z ggregory $
24 * @see MutableShort
25 */
26 public class MutableObjectTest extends TestCase {
27
28 public MutableObjectTest(String testName) {
29 super(testName);
30 }
31
32 // ----------------------------------------------------------------
33 public void testConstructors() {
34 assertEquals(null, new MutableObject<String>().getValue());
35
36 Integer i = Integer.valueOf(6);
37 assertSame(i, new MutableObject<Integer>(i).getValue());
38 assertSame("HI", new MutableObject<String>("HI").getValue());
39 assertSame(null, new MutableObject<Object>(null).getValue());
40 }
41
42 public void testGetSet() {
43 final MutableObject<String> mutNum = new MutableObject<String>();
44 assertEquals(null, new MutableObject<Object>().getValue());
45
46 mutNum.setValue("HELLO");
47 assertSame("HELLO", mutNum.getValue());
48
49 mutNum.setValue(null);
50 assertSame(null, mutNum.getValue());
51 }
52
53 public void testEquals() {
54 final MutableObject<String> mutNumA = new MutableObject<String>("ALPHA");
55 final MutableObject<String> mutNumB = new MutableObject<String>("ALPHA");
56 final MutableObject<String> mutNumC = new MutableObject<String>("BETA");
57 final MutableObject<String> mutNumD = new MutableObject<String>(null);
58
59 assertEquals(true, mutNumA.equals(mutNumA));
60 assertEquals(true, mutNumA.equals(mutNumB));
61 assertEquals(true, mutNumB.equals(mutNumA));
62 assertEquals(true, mutNumB.equals(mutNumB));
63 assertEquals(false, mutNumA.equals(mutNumC));
64 assertEquals(false, mutNumB.equals(mutNumC));
65 assertEquals(true, mutNumC.equals(mutNumC));
66 assertEquals(false, mutNumA.equals(mutNumD));
67 assertEquals(true, mutNumD.equals(mutNumD));
68
69 assertEquals(false, mutNumA.equals(null));
70 assertEquals(false, mutNumA.equals(new Object()));
71 assertEquals(false, mutNumA.equals("0"));
72 }
73
74 public void testHashCode() {
75 final MutableObject<String> mutNumA = new MutableObject<String>("ALPHA");
76 final MutableObject<String> mutNumB = new MutableObject<String>("ALPHA");
77 final MutableObject<String> mutNumC = new MutableObject<String>("BETA");
78 final MutableObject<String> mutNumD = new MutableObject<String>(null);
79
80 assertEquals(true, mutNumA.hashCode() == mutNumA.hashCode());
81 assertEquals(true, mutNumA.hashCode() == mutNumB.hashCode());
82 assertEquals(false, mutNumA.hashCode() == mutNumC.hashCode());
83 assertEquals(false, mutNumA.hashCode() == mutNumD.hashCode());
84 assertEquals(true, mutNumA.hashCode() == "ALPHA".hashCode());
85 assertEquals(0, mutNumD.hashCode());
86 }
87
88 public void testToString() {
89 assertEquals("HI", new MutableObject<String>("HI").toString());
90 assertEquals("10.0", new MutableObject<Double>(Double.valueOf(10)).toString());
91 assertEquals("null", new MutableObject<Object>(null).toString());
92 }
93
94 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.mutable;
17
18 import junit.framework.TestCase;
19
20 /**
21 * JUnit tests.
22 *
23 * @version $Id: MutableShortTest.java 1153488 2011-08-03 13:47:49Z ggregory $
24 * @see MutableShort
25 */
26 public class MutableShortTest extends TestCase {
27
28 public MutableShortTest(String testName) {
29 super(testName);
30 }
31
32 // ----------------------------------------------------------------
33 public void testConstructors() {
34 assertEquals((short) 0, new MutableShort().shortValue());
35
36 assertEquals((short) 1, new MutableShort((short) 1).shortValue());
37
38 assertEquals((short) 2, new MutableShort(Short.valueOf((short) 2)).shortValue());
39 assertEquals((short) 3, new MutableShort(new MutableShort((short) 3)).shortValue());
40
41 assertEquals((short) 2, new MutableShort("2").shortValue());
42
43 try {
44 new MutableShort((Number)null);
45 fail();
46 } catch (NullPointerException ex) {}
47 }
48
49 public void testGetSet() {
50 final MutableShort mutNum = new MutableShort((short) 0);
51 assertEquals((short) 0, new MutableShort().shortValue());
52 assertEquals(Short.valueOf((short) 0), new MutableShort().getValue());
53
54 mutNum.setValue((short) 1);
55 assertEquals((short) 1, mutNum.shortValue());
56 assertEquals(Short.valueOf((short) 1), mutNum.getValue());
57
58 mutNum.setValue(Short.valueOf((short) 2));
59 assertEquals((short) 2, mutNum.shortValue());
60 assertEquals(Short.valueOf((short) 2), mutNum.getValue());
61
62 mutNum.setValue(new MutableShort((short) 3));
63 assertEquals((short) 3, mutNum.shortValue());
64 assertEquals(Short.valueOf((short) 3), mutNum.getValue());
65 try {
66 mutNum.setValue(null);
67 fail();
68 } catch (NullPointerException ex) {}
69 }
70
71 public void testEquals() {
72 final MutableShort mutNumA = new MutableShort((short) 0);
73 final MutableShort mutNumB = new MutableShort((short) 0);
74 final MutableShort mutNumC = new MutableShort((short) 1);
75
76 assertEquals(true, mutNumA.equals(mutNumA));
77 assertEquals(true, mutNumA.equals(mutNumB));
78 assertEquals(true, mutNumB.equals(mutNumA));
79 assertEquals(true, mutNumB.equals(mutNumB));
80 assertEquals(false, mutNumA.equals(mutNumC));
81 assertEquals(false, mutNumB.equals(mutNumC));
82 assertEquals(true, mutNumC.equals(mutNumC));
83 assertEquals(false, mutNumA.equals(null));
84 assertEquals(false, mutNumA.equals(Short.valueOf((short) 0)));
85 assertEquals(false, mutNumA.equals("0"));
86 }
87
88 public void testHashCode() {
89 final MutableShort mutNumA = new MutableShort((short) 0);
90 final MutableShort mutNumB = new MutableShort((short) 0);
91 final MutableShort mutNumC = new MutableShort((short) 1);
92
93 assertEquals(true, mutNumA.hashCode() == mutNumA.hashCode());
94 assertEquals(true, mutNumA.hashCode() == mutNumB.hashCode());
95 assertEquals(false, mutNumA.hashCode() == mutNumC.hashCode());
96 assertEquals(true, mutNumA.hashCode() == Short.valueOf((short) 0).hashCode());
97 }
98
99 public void testCompareTo() {
100 final MutableShort mutNum = new MutableShort((short) 0);
101
102 assertEquals((short) 0, mutNum.compareTo(new MutableShort((short) 0)));
103 assertEquals((short) +1, mutNum.compareTo(new MutableShort((short) -1)));
104 assertEquals((short) -1, mutNum.compareTo(new MutableShort((short) 1)));
105 try {
106 mutNum.compareTo(null);
107 fail();
108 } catch (NullPointerException ex) {}
109 }
110
111 public void testPrimitiveValues() {
112 MutableShort mutNum = new MutableShort( (short) 1 );
113
114 assertEquals( 1.0F, mutNum.floatValue(), 0 );
115 assertEquals( 1.0, mutNum.doubleValue(), 0 );
116 assertEquals( (byte) 1, mutNum.byteValue() );
117 assertEquals( (short) 1, mutNum.shortValue() );
118 assertEquals( 1, mutNum.intValue() );
119 assertEquals( 1L, mutNum.longValue() );
120 }
121
122 public void testToShort() {
123 assertEquals(Short.valueOf((short) 0), new MutableShort((short) 0).toShort());
124 assertEquals(Short.valueOf((short) 123), new MutableShort((short) 123).toShort());
125 }
126
127 public void testIncrement() {
128 MutableShort mutNum = new MutableShort((short) 1);
129 mutNum.increment();
130
131 assertEquals(2, mutNum.intValue());
132 assertEquals(2L, mutNum.longValue());
133 }
134
135 public void testDecrement() {
136 MutableShort mutNum = new MutableShort((short) 1);
137 mutNum.decrement();
138
139 assertEquals(0, mutNum.intValue());
140 assertEquals(0L, mutNum.longValue());
141 }
142
143 public void testAddValuePrimitive() {
144 MutableShort mutNum = new MutableShort((short) 1);
145 mutNum.add((short) 1);
146
147 assertEquals((short) 2, mutNum.shortValue());
148 }
149
150 public void testAddValueObject() {
151 MutableShort mutNum = new MutableShort((short) 1);
152 mutNum.add(Short.valueOf((short) 1));
153
154 assertEquals((short) 2, mutNum.shortValue());
155 }
156
157 public void testSubtractValuePrimitive() {
158 MutableShort mutNum = new MutableShort((short) 1);
159 mutNum.subtract((short) 1);
160
161 assertEquals((short) 0, mutNum.shortValue());
162 }
163
164 public void testSubtractValueObject() {
165 MutableShort mutNum = new MutableShort((short) 1);
166 mutNum.subtract(Short.valueOf((short) 1));
167
168 assertEquals((short) 0, mutNum.shortValue());
169 }
170
171 public void testToString() {
172 assertEquals("0", new MutableShort((short) 0).toString());
173 assertEquals("10", new MutableShort((short) 10).toString());
174 assertEquals("-123", new MutableShort((short) -123).toString());
175 }
176
177 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect;
17
18 import java.lang.reflect.Constructor;
19 import java.util.Arrays;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import junit.framework.TestCase;
24
25 import org.apache.commons.lang3.ArrayUtils;
26 import org.apache.commons.lang3.math.NumberUtils;
27
28 /**
29 * Unit tests ConstructorUtils
30 * @version $Id: ConstructorUtilsTest.java 1097487 2011-04-28 14:49:45Z ggregory $
31 */
32 public class ConstructorUtilsTest extends TestCase {
33 public static class TestBean {
34 private String toString;
35
36 public TestBean() {
37 toString = "()";
38 }
39
40 public TestBean(int i) {
41 toString = "(int)";
42 }
43
44 public TestBean(Integer i) {
45 toString = "(Integer)";
46 }
47
48 public TestBean(double d) {
49 toString = "(double)";
50 }
51
52 public TestBean(String s) {
53 toString = "(String)";
54 }
55
56 public TestBean(Object o) {
57 toString = "(Object)";
58 }
59
60 @Override
61 public String toString() {
62 return toString;
63 }
64 }
65
66 private static class PrivateClass {
67 @SuppressWarnings("unused")
68 public PrivateClass() {
69 }
70 }
71
72 private Map<Class<?>, Class<?>[]> classCache;
73
74 public ConstructorUtilsTest(String name) {
75 super(name);
76 classCache = new HashMap<Class<?>, Class<?>[]>();
77 }
78
79 @Override
80 protected void setUp() throws Exception {
81 super.setUp();
82 classCache.clear();
83 }
84
85 public void testConstructor() throws Exception {
86 assertNotNull(MethodUtils.class.newInstance());
87 }
88
89 public void testInvokeConstructor() throws Exception {
90 assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class,
91 (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY).toString());
92 assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class,
93 (Object[]) null).toString());
94 assertEquals("()", ConstructorUtils.invokeConstructor(TestBean.class).toString());
95 assertEquals("(String)", ConstructorUtils.invokeConstructor(
96 TestBean.class, "").toString());
97 assertEquals("(Object)", ConstructorUtils.invokeConstructor(
98 TestBean.class, new Object()).toString());
99 assertEquals("(Object)", ConstructorUtils.invokeConstructor(
100 TestBean.class, Boolean.TRUE).toString());
101 assertEquals("(Integer)", ConstructorUtils.invokeConstructor(
102 TestBean.class, NumberUtils.INTEGER_ONE).toString());
103 assertEquals("(int)", ConstructorUtils.invokeConstructor(
104 TestBean.class, NumberUtils.BYTE_ONE).toString());
105 assertEquals("(double)", ConstructorUtils.invokeConstructor(
106 TestBean.class, NumberUtils.LONG_ONE).toString());
107 assertEquals("(double)", ConstructorUtils.invokeConstructor(
108 TestBean.class, NumberUtils.DOUBLE_ONE).toString());
109 }
110
111 public void testInvokeExactConstructor() throws Exception {
112 assertEquals("()", ConstructorUtils.invokeExactConstructor(
113 TestBean.class, (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY).toString());
114 assertEquals("()", ConstructorUtils.invokeExactConstructor(
115 TestBean.class, (Object[]) null).toString());
116 assertEquals("(String)", ConstructorUtils.invokeExactConstructor(
117 TestBean.class, "").toString());
118 assertEquals("(Object)", ConstructorUtils.invokeExactConstructor(
119 TestBean.class, new Object()).toString());
120 assertEquals("(Integer)", ConstructorUtils.invokeExactConstructor(
121 TestBean.class, NumberUtils.INTEGER_ONE).toString());
122 assertEquals("(double)", ConstructorUtils.invokeExactConstructor(
123 TestBean.class, new Object[] { NumberUtils.DOUBLE_ONE },
124 new Class[] { Double.TYPE }).toString());
125
126 try {
127 ConstructorUtils.invokeExactConstructor(TestBean.class,
128 NumberUtils.BYTE_ONE);
129 fail("should throw NoSuchMethodException");
130 } catch (NoSuchMethodException e) {
131 }
132 try {
133 ConstructorUtils.invokeExactConstructor(TestBean.class,
134 NumberUtils.LONG_ONE);
135 fail("should throw NoSuchMethodException");
136 } catch (NoSuchMethodException e) {
137 }
138 try {
139 ConstructorUtils.invokeExactConstructor(TestBean.class,
140 Boolean.TRUE);
141 fail("should throw NoSuchMethodException");
142 } catch (NoSuchMethodException e) {
143 }
144 }
145
146 public void testGetAccessibleConstructor() throws Exception {
147 assertNotNull(ConstructorUtils.getAccessibleConstructor(Object.class
148 .getConstructor(ArrayUtils.EMPTY_CLASS_ARRAY)));
149 assertNull(ConstructorUtils.getAccessibleConstructor(PrivateClass.class
150 .getConstructor(ArrayUtils.EMPTY_CLASS_ARRAY)));
151 }
152
153 public void testGetAccessibleConstructorFromDescription() throws Exception {
154 assertNotNull(ConstructorUtils.getAccessibleConstructor(Object.class,
155 ArrayUtils.EMPTY_CLASS_ARRAY));
156 assertNull(ConstructorUtils.getAccessibleConstructor(
157 PrivateClass.class, ArrayUtils.EMPTY_CLASS_ARRAY));
158 }
159
160 public void testGetMatchingAccessibleMethod() throws Exception {
161 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
162 ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_CLASS_ARRAY);
163 expectMatchingAccessibleConstructorParameterTypes(TestBean.class, null,
164 ArrayUtils.EMPTY_CLASS_ARRAY);
165 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
166 singletonArray(String.class), singletonArray(String.class));
167 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
168 singletonArray(Object.class), singletonArray(Object.class));
169 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
170 singletonArray(Boolean.class), singletonArray(Object.class));
171 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
172 singletonArray(Byte.class), singletonArray(Integer.TYPE));
173 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
174 singletonArray(Byte.TYPE), singletonArray(Integer.TYPE));
175 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
176 singletonArray(Short.class), singletonArray(Integer.TYPE));
177 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
178 singletonArray(Short.TYPE), singletonArray(Integer.TYPE));
179 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
180 singletonArray(Character.class), singletonArray(Integer.TYPE));
181 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
182 singletonArray(Character.TYPE), singletonArray(Integer.TYPE));
183 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
184 singletonArray(Integer.class), singletonArray(Integer.class));
185 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
186 singletonArray(Integer.TYPE), singletonArray(Integer.TYPE));
187 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
188 singletonArray(Long.class), singletonArray(Double.TYPE));
189 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
190 singletonArray(Long.TYPE), singletonArray(Double.TYPE));
191 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
192 singletonArray(Float.class), singletonArray(Double.TYPE));
193 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
194 singletonArray(Float.TYPE), singletonArray(Double.TYPE));
195 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
196 singletonArray(Double.class), singletonArray(Double.TYPE));
197 expectMatchingAccessibleConstructorParameterTypes(TestBean.class,
198 singletonArray(Double.TYPE), singletonArray(Double.TYPE));
199 }
200
201 private void expectMatchingAccessibleConstructorParameterTypes(Class<?> cls,
202 Class<?>[] requestTypes, Class<?>[] actualTypes) {
203 Constructor<?> c = ConstructorUtils.getMatchingAccessibleConstructor(cls,
204 requestTypes);
205 assertTrue(toString(c.getParameterTypes()) + " not equals "
206 + toString(actualTypes), Arrays.equals(actualTypes, c
207 .getParameterTypes()));
208 }
209
210 private String toString(Class<?>[] c) {
211 return Arrays.asList(c).toString();
212 }
213
214 private Class<?>[] singletonArray(Class<?> c) {
215 Class<?>[] result = classCache.get(c);
216 if (result == null) {
217 result = new Class[] { c };
218 classCache.put(c, result);
219 }
220 return result;
221 }
222
223 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.fail;
22 import static org.junit.Assume.assumeNotNull;
23
24 import java.lang.reflect.Constructor;
25 import java.lang.reflect.Field;
26 import java.lang.reflect.Modifier;
27
28 import org.apache.commons.lang3.reflect.testbed.Ambig;
29 import org.apache.commons.lang3.reflect.testbed.Foo;
30 import org.apache.commons.lang3.reflect.testbed.PrivatelyShadowedChild;
31 import org.apache.commons.lang3.reflect.testbed.PublicChild;
32 import org.apache.commons.lang3.reflect.testbed.PubliclyShadowedChild;
33 import org.apache.commons.lang3.reflect.testbed.StaticContainer;
34 import org.apache.commons.lang3.reflect.testbed.StaticContainerChild;
35 import org.junit.Before;
36 import org.junit.Test;
37
38 /**
39 * Unit tests FieldUtils
40 * @version $Id: FieldUtilsTest.java 1153490 2011-08-03 13:53:35Z ggregory $
41 */
42 public class FieldUtilsTest {
43
44 static final String S = "s";
45 static final String SS = "ss";
46 static final Integer I0 = Integer.valueOf(0);
47 static final Integer I1 = Integer.valueOf(1);
48 static final Double D0 = Double.valueOf(0.0);
49 static final Double D1 = Double.valueOf(1.0);
50
51 private PublicChild publicChild;
52 private PubliclyShadowedChild publiclyShadowedChild;
53 private PrivatelyShadowedChild privatelyShadowedChild;
54 private Class<?> parentClass = PublicChild.class.getSuperclass();
55
56 @Before
57 public void setUp() {
58 StaticContainer.reset();
59 publicChild = new PublicChild();
60 publiclyShadowedChild = new PubliclyShadowedChild();
61 privatelyShadowedChild = new PrivatelyShadowedChild();
62 }
63
64 @Test
65 public void testConstructor() {
66 assertNotNull(new FieldUtils());
67 Constructor<?>[] cons = FieldUtils.class.getDeclaredConstructors();
68 assertEquals(1, cons.length);
69 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
70 assertEquals(true, Modifier.isPublic(FieldUtils.class.getModifiers()));
71 assertEquals(false, Modifier.isFinal(FieldUtils.class.getModifiers()));
72 }
73
74 @Test
75 public void testGetField() {
76 assertEquals(Foo.class, FieldUtils.getField(PublicChild.class, "VALUE").getDeclaringClass());
77 assertEquals(parentClass, FieldUtils.getField(PublicChild.class, "s").getDeclaringClass());
78 assertNull(FieldUtils.getField(PublicChild.class, "b"));
79 assertNull(FieldUtils.getField(PublicChild.class, "i"));
80 assertNull(FieldUtils.getField(PublicChild.class, "d"));
81 assertEquals(Foo.class, FieldUtils.getField(PubliclyShadowedChild.class, "VALUE").getDeclaringClass());
82 assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "s")
83 .getDeclaringClass());
84 assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "b")
85 .getDeclaringClass());
86 assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "i")
87 .getDeclaringClass());
88 assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "d")
89 .getDeclaringClass());
90 assertEquals(Foo.class, FieldUtils.getField(PrivatelyShadowedChild.class, "VALUE").getDeclaringClass());
91 assertEquals(parentClass, FieldUtils.getField(PrivatelyShadowedChild.class, "s").getDeclaringClass());
92 assertNull(FieldUtils.getField(PrivatelyShadowedChild.class, "b"));
93 assertNull(FieldUtils.getField(PrivatelyShadowedChild.class, "i"));
94 assertNull(FieldUtils.getField(PrivatelyShadowedChild.class, "d"));
95 }
96
97 @Test(expected=IllegalArgumentException.class)
98 public void testGetFieldIllegalArgumentException1() {
99 FieldUtils.getField(null, "none");
100 }
101
102 @Test(expected=IllegalArgumentException.class)
103 public void testGetFieldIllegalArgumentException2() {
104 FieldUtils.getField(PublicChild.class, null);
105 }
106
107 @Test
108 public void testGetFieldForceAccess() {
109 assertEquals(PublicChild.class, FieldUtils.getField(PublicChild.class, "VALUE", true).getDeclaringClass());
110 assertEquals(parentClass, FieldUtils.getField(PublicChild.class, "s", true).getDeclaringClass());
111 assertEquals(parentClass, FieldUtils.getField(PublicChild.class, "b", true).getDeclaringClass());
112 assertEquals(parentClass, FieldUtils.getField(PublicChild.class, "i", true).getDeclaringClass());
113 assertEquals(parentClass, FieldUtils.getField(PublicChild.class, "d", true).getDeclaringClass());
114 assertEquals(Foo.class, FieldUtils.getField(PubliclyShadowedChild.class, "VALUE", true).getDeclaringClass());
115 assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "s", true)
116 .getDeclaringClass());
117 assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "b", true)
118 .getDeclaringClass());
119 assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "i", true)
120 .getDeclaringClass());
121 assertEquals(PubliclyShadowedChild.class, FieldUtils.getField(PubliclyShadowedChild.class, "d", true)
122 .getDeclaringClass());
123 assertEquals(Foo.class, FieldUtils.getField(PrivatelyShadowedChild.class, "VALUE", true).getDeclaringClass());
124 assertEquals(PrivatelyShadowedChild.class, FieldUtils.getField(PrivatelyShadowedChild.class, "s", true)
125 .getDeclaringClass());
126 assertEquals(PrivatelyShadowedChild.class, FieldUtils.getField(PrivatelyShadowedChild.class, "b", true)
127 .getDeclaringClass());
128 assertEquals(PrivatelyShadowedChild.class, FieldUtils.getField(PrivatelyShadowedChild.class, "i", true)
129 .getDeclaringClass());
130 assertEquals(PrivatelyShadowedChild.class, FieldUtils.getField(PrivatelyShadowedChild.class, "d", true)
131 .getDeclaringClass());
132 }
133
134 @Test(expected=IllegalArgumentException.class)
135 public void testGetFieldForceAccessIllegalArgumentException1() {
136 FieldUtils.getField(null, "none", true);
137 }
138
139 @Test(expected=IllegalArgumentException.class)
140 public void testGetFieldForceAccessIllegalArgumentException2() {
141 FieldUtils.getField(PublicChild.class, null, true);
142 }
143
144 @Test
145 public void testGetDeclaredField() {
146 assertNull(FieldUtils.getDeclaredField(PublicChild.class, "VALUE"));
147 assertNull(FieldUtils.getDeclaredField(PublicChild.class, "s"));
148 assertNull(FieldUtils.getDeclaredField(PublicChild.class, "b"));
149 assertNull(FieldUtils.getDeclaredField(PublicChild.class, "i"));
150 assertNull(FieldUtils.getDeclaredField(PublicChild.class, "d"));
151 assertNull(FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "VALUE"));
152 assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "s")
153 .getDeclaringClass());
154 assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "b")
155 .getDeclaringClass());
156 assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "i")
157 .getDeclaringClass());
158 assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "d")
159 .getDeclaringClass());
160 assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "VALUE"));
161 assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "s"));
162 assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "b"));
163 assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "i"));
164 assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "d"));
165 }
166
167 @Test(expected=IllegalArgumentException.class)
168 public void testGetDeclaredFieldAccessIllegalArgumentException1() {
169 FieldUtils.getDeclaredField(null, "none");
170 }
171
172 @Test(expected=IllegalArgumentException.class)
173 public void testGetDeclaredFieldAccessIllegalArgumentException2() {
174 FieldUtils.getDeclaredField(PublicChild.class, null);
175 }
176
177 @Test
178 public void testGetDeclaredFieldForceAccess() {
179 assertEquals(PublicChild.class, FieldUtils.getDeclaredField(PublicChild.class, "VALUE", true)
180 .getDeclaringClass());
181 assertNull(FieldUtils.getDeclaredField(PublicChild.class, "s", true));
182 assertNull(FieldUtils.getDeclaredField(PublicChild.class, "b", true));
183 assertNull(FieldUtils.getDeclaredField(PublicChild.class, "i", true));
184 assertNull(FieldUtils.getDeclaredField(PublicChild.class, "d", true));
185 assertNull(FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "VALUE", true));
186 assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "s", true)
187 .getDeclaringClass());
188 assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "b", true)
189 .getDeclaringClass());
190 assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "i", true)
191 .getDeclaringClass());
192 assertEquals(PubliclyShadowedChild.class, FieldUtils.getDeclaredField(PubliclyShadowedChild.class, "d", true)
193 .getDeclaringClass());
194 assertNull(FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "VALUE", true));
195 assertEquals(PrivatelyShadowedChild.class, FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "s", true)
196 .getDeclaringClass());
197 assertEquals(PrivatelyShadowedChild.class, FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "b", true)
198 .getDeclaringClass());
199 assertEquals(PrivatelyShadowedChild.class, FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "i", true)
200 .getDeclaringClass());
201 assertEquals(PrivatelyShadowedChild.class, FieldUtils.getDeclaredField(PrivatelyShadowedChild.class, "d", true)
202 .getDeclaringClass());
203 }
204
205 @Test(expected=IllegalArgumentException.class)
206 public void testGetDeclaredFieldForceAccessIllegalArgumentException1() {
207 FieldUtils.getDeclaredField(null, "none", true);
208 }
209
210 @Test(expected=IllegalArgumentException.class)
211 public void testGetDeclaredFieldForceAccessIllegalArgumentException2() {
212 FieldUtils.getDeclaredField(PublicChild.class, null, true);
213 }
214
215 @Test
216 public void testReadStaticField() throws Exception {
217 assertEquals(Foo.VALUE, FieldUtils.readStaticField(FieldUtils.getField(Foo.class, "VALUE")));
218 }
219
220 @Test(expected=IllegalArgumentException.class)
221 public void testReadStaticFieldIllegalArgumentException1() throws Exception {
222 FieldUtils.readStaticField(null);
223 }
224
225 @Test(expected=IllegalArgumentException.class)
226 public void testReadStaticFieldIllegalArgumentException2() throws Exception {
227 assertEquals(Foo.VALUE, FieldUtils.readStaticField(FieldUtils.getField(Foo.class, "VALUE")));
228 Field nonStaticField = FieldUtils.getField(PublicChild.class, "s");
229 assumeNotNull(nonStaticField);
230 FieldUtils.readStaticField(nonStaticField);
231 }
232
233 @Test
234 public void testReadStaticFieldForceAccess() throws Exception {
235 assertEquals(Foo.VALUE, FieldUtils.readStaticField(FieldUtils.getField(Foo.class, "VALUE")));
236 assertEquals(Foo.VALUE, FieldUtils.readStaticField(FieldUtils.getField(PublicChild.class, "VALUE")));
237 }
238
239 @Test(expected=IllegalArgumentException.class)
240 public void testReadStaticFieldForceAccessIllegalArgumentException1() throws Exception {
241 FieldUtils.readStaticField(null, true);
242 }
243
244 @Test(expected=IllegalArgumentException.class)
245 public void testReadStaticFieldForceAccessIllegalArgumentException2() throws Exception {
246 Field nonStaticField = FieldUtils.getField(PublicChild.class, "s", true);
247 assumeNotNull(nonStaticField);
248 FieldUtils.readStaticField(nonStaticField);
249 }
250
251 @Test
252 public void testReadNamedStaticField() throws Exception {
253 assertEquals(Foo.VALUE, FieldUtils.readStaticField(Foo.class, "VALUE"));
254 assertEquals(Foo.VALUE, FieldUtils.readStaticField(PubliclyShadowedChild.class, "VALUE"));
255 assertEquals(Foo.VALUE, FieldUtils.readStaticField(PrivatelyShadowedChild.class, "VALUE"));
256 assertEquals(Foo.VALUE, FieldUtils.readStaticField(PublicChild.class, "VALUE"));
257
258 try {
259 FieldUtils.readStaticField(null, "none");
260 fail("null class should cause an IllegalArgumentException");
261 } catch (IllegalArgumentException e) {
262 // expected
263 }
264
265 try {
266 FieldUtils.readStaticField(Foo.class, null);
267 fail("null field name should cause an IllegalArgumentException");
268 } catch (IllegalArgumentException e) {
269 // expected
270 }
271
272 try {
273 FieldUtils.readStaticField(Foo.class, "does_not_exist");
274 fail("a field that doesn't exist should cause an IllegalArgumentException");
275 } catch (IllegalArgumentException e) {
276 // expected
277 }
278
279 try {
280 FieldUtils.readStaticField(PublicChild.class, "s");
281 fail("non-static field should cause an IllegalArgumentException");
282 } catch (IllegalArgumentException e) {
283 // expected
284 }
285 }
286
287 @Test
288 public void testReadNamedStaticFieldForceAccess() throws Exception {
289 assertEquals(Foo.VALUE, FieldUtils.readStaticField(Foo.class, "VALUE", true));
290 assertEquals(Foo.VALUE, FieldUtils.readStaticField(PubliclyShadowedChild.class, "VALUE", true));
291 assertEquals(Foo.VALUE, FieldUtils.readStaticField(PrivatelyShadowedChild.class, "VALUE", true));
292 assertEquals("child", FieldUtils.readStaticField(PublicChild.class, "VALUE", true));
293
294 try {
295 FieldUtils.readStaticField(null, "none", true);
296 fail("null class should cause an IllegalArgumentException");
297 } catch (IllegalArgumentException e) {
298 // expected
299 }
300
301 try {
302 FieldUtils.readStaticField(Foo.class, null, true);
303 fail("null field name should cause an IllegalArgumentException");
304 } catch (IllegalArgumentException e) {
305 // expected
306 }
307
308 try {
309 FieldUtils.readStaticField(Foo.class, "does_not_exist", true);
310 fail("a field that doesn't exist should cause an IllegalArgumentException");
311 } catch (IllegalArgumentException e) {
312 // expected
313 }
314
315 try {
316 FieldUtils.readStaticField(PublicChild.class, "s", false);
317 fail("non-static field should cause an IllegalArgumentException");
318 } catch (IllegalArgumentException e) {
319 // expected
320 }
321 }
322
323 @Test
324 public void testReadDeclaredNamedStaticField() throws Exception {
325 assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(Foo.class, "VALUE"));
326 try {
327 assertEquals("child", FieldUtils.readDeclaredStaticField(PublicChild.class, "VALUE"));
328 fail("expected IllegalArgumentException");
329 } catch (IllegalArgumentException e) {
330 // pass
331 }
332 try {
333 assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(PubliclyShadowedChild.class, "VALUE"));
334 fail("expected IllegalArgumentException");
335 } catch (IllegalArgumentException e) {
336 // pass
337 }
338 try {
339 assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(PrivatelyShadowedChild.class, "VALUE"));
340 fail("expected IllegalArgumentException");
341 } catch (IllegalArgumentException e) {
342 // pass
343 }
344 }
345
346 @Test
347 public void testReadDeclaredNamedStaticFieldForceAccess() throws Exception {
348 assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(Foo.class, "VALUE", true));
349 assertEquals("child", FieldUtils.readDeclaredStaticField(PublicChild.class, "VALUE", true));
350 try {
351 assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(PubliclyShadowedChild.class, "VALUE", true));
352 fail("expected IllegalArgumentException");
353 } catch (IllegalArgumentException e) {
354 // pass
355 }
356 try {
357 assertEquals(Foo.VALUE, FieldUtils.readDeclaredStaticField(PrivatelyShadowedChild.class, "VALUE", true));
358 fail("expected IllegalArgumentException");
359 } catch (IllegalArgumentException e) {
360 // pass
361 }
362 }
363
364 @Test
365 public void testReadField() throws Exception {
366 Field parentS = FieldUtils.getDeclaredField(parentClass, "s");
367 assertEquals("s", FieldUtils.readField(parentS, publicChild));
368 assertEquals("s", FieldUtils.readField(parentS, publiclyShadowedChild));
369 assertEquals("s", FieldUtils.readField(parentS, privatelyShadowedChild));
370 Field parentB = FieldUtils.getDeclaredField(parentClass, "b", true);
371 assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, publicChild));
372 assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, publiclyShadowedChild));
373 assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, privatelyShadowedChild));
374 Field parentI = FieldUtils.getDeclaredField(parentClass, "i", true);
375 assertEquals(I0, FieldUtils.readField(parentI, publicChild));
376 assertEquals(I0, FieldUtils.readField(parentI, publiclyShadowedChild));
377 assertEquals(I0, FieldUtils.readField(parentI, privatelyShadowedChild));
378 Field parentD = FieldUtils.getDeclaredField(parentClass, "d", true);
379 assertEquals(D0, FieldUtils.readField(parentD, publicChild));
380 assertEquals(D0, FieldUtils.readField(parentD, publiclyShadowedChild));
381 assertEquals(D0, FieldUtils.readField(parentD, privatelyShadowedChild));
382
383 try {
384 FieldUtils.readField((Field)null, publicChild);
385 fail("a null field should cause an IllegalArgumentException");
386 } catch (IllegalArgumentException e) {
387 // expected
388 }
389 }
390
391 @Test
392 public void testReadFieldForceAccess() throws Exception {
393 Field parentS = FieldUtils.getDeclaredField(parentClass, "s");
394 parentS.setAccessible(false);
395 assertEquals("s", FieldUtils.readField(parentS, publicChild, true));
396 assertEquals("s", FieldUtils.readField(parentS, publiclyShadowedChild, true));
397 assertEquals("s", FieldUtils.readField(parentS, privatelyShadowedChild, true));
398 Field parentB = FieldUtils.getDeclaredField(parentClass, "b", true);
399 parentB.setAccessible(false);
400 assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, publicChild, true));
401 assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, publiclyShadowedChild, true));
402 assertEquals(Boolean.FALSE, FieldUtils.readField(parentB, privatelyShadowedChild, true));
403 Field parentI = FieldUtils.getDeclaredField(parentClass, "i", true);
404 parentI.setAccessible(false);
405 assertEquals(I0, FieldUtils.readField(parentI, publicChild, true));
406 assertEquals(I0, FieldUtils.readField(parentI, publiclyShadowedChild, true));
407 assertEquals(I0, FieldUtils.readField(parentI, privatelyShadowedChild, true));
408 Field parentD = FieldUtils.getDeclaredField(parentClass, "d", true);
409 parentD.setAccessible(false);
410 assertEquals(D0, FieldUtils.readField(parentD, publicChild, true));
411 assertEquals(D0, FieldUtils.readField(parentD, publiclyShadowedChild, true));
412 assertEquals(D0, FieldUtils.readField(parentD, privatelyShadowedChild, true));
413
414 try {
415 FieldUtils.readField((Field)null, publicChild, true);
416 fail("a null field should cause an IllegalArgumentException");
417 } catch (IllegalArgumentException e) {
418 // expected
419 }
420 }
421
422 @Test
423 public void testReadNamedField() throws Exception {
424 assertEquals("s", FieldUtils.readField(publicChild, "s"));
425 assertEquals("ss", FieldUtils.readField(publiclyShadowedChild, "s"));
426 assertEquals("s", FieldUtils.readField(privatelyShadowedChild, "s"));
427
428 try {
429 FieldUtils.readField(publicChild, null);
430 fail("a null field name should cause an IllegalArgumentException");
431 } catch (IllegalArgumentException e) {
432 // expected
433 }
434
435 try {
436 FieldUtils.readField((Object)null, "none");
437 fail("a null target should cause an IllegalArgumentException");
438 } catch (IllegalArgumentException e) {
439 // expected
440 }
441
442 try {
443 assertEquals(Boolean.FALSE, FieldUtils.readField(publicChild, "b"));
444 fail("expected IllegalArgumentException");
445 } catch (IllegalArgumentException e) {
446 // pass
447 }
448 assertEquals(Boolean.TRUE, FieldUtils.readField(publiclyShadowedChild, "b"));
449 try {
450 assertEquals(Boolean.FALSE, FieldUtils.readField(privatelyShadowedChild, "b"));
451 fail("expected IllegalArgumentException");
452 } catch (IllegalArgumentException e) {
453 // pass
454 }
455 try {
456 assertEquals(I0, FieldUtils.readField(publicChild, "i"));
457 fail("expected IllegalArgumentException");
458 } catch (IllegalArgumentException e) {
459 // pass
460 }
461 assertEquals(I1, FieldUtils.readField(publiclyShadowedChild, "i"));
462 try {
463 assertEquals(I0, FieldUtils.readField(privatelyShadowedChild, "i"));
464 fail("expected IllegalArgumentException");
465 } catch (IllegalArgumentException e) {
466 // pass
467 }
468 try {
469 assertEquals(D0, FieldUtils.readField(publicChild, "d"));
470 fail("expected IllegalArgumentException");
471 } catch (IllegalArgumentException e) {
472 // pass
473 }
474 assertEquals(D1, FieldUtils.readField(publiclyShadowedChild, "d"));
475 try {
476 assertEquals(D0, FieldUtils.readField(privatelyShadowedChild, "d"));
477 fail("expected IllegalArgumentException");
478 } catch (IllegalArgumentException e) {
479 // pass
480 }
481 }
482
483 @Test
484 public void testReadNamedFieldForceAccess() throws Exception {
485 assertEquals("s", FieldUtils.readField(publicChild, "s", true));
486 assertEquals("ss", FieldUtils.readField(publiclyShadowedChild, "s", true));
487 assertEquals("ss", FieldUtils.readField(privatelyShadowedChild, "s", true));
488 assertEquals(Boolean.FALSE, FieldUtils.readField(publicChild, "b", true));
489 assertEquals(Boolean.TRUE, FieldUtils.readField(publiclyShadowedChild, "b", true));
490 assertEquals(Boolean.TRUE, FieldUtils.readField(privatelyShadowedChild, "b", true));
491 assertEquals(I0, FieldUtils.readField(publicChild, "i", true));
492 assertEquals(I1, FieldUtils.readField(publiclyShadowedChild, "i", true));
493 assertEquals(I1, FieldUtils.readField(privatelyShadowedChild, "i", true));
494 assertEquals(D0, FieldUtils.readField(publicChild, "d", true));
495 assertEquals(D1, FieldUtils.readField(publiclyShadowedChild, "d", true));
496 assertEquals(D1, FieldUtils.readField(privatelyShadowedChild, "d", true));
497
498 try {
499 FieldUtils.readField(publicChild, null, true);
500 fail("a null field name should cause an IllegalArgumentException");
501 } catch (IllegalArgumentException e) {
502 // expected
503 }
504
505 try {
506 FieldUtils.readField((Object)null, "none", true);
507 fail("a null target should cause an IllegalArgumentException");
508 } catch (IllegalArgumentException e) {
509 // expected
510 }
511 }
512
513 @Test
514 public void testReadDeclaredNamedField() throws Exception {
515 try {
516 FieldUtils.readDeclaredField(publicChild, null);
517 fail("a null field name should cause an IllegalArgumentException");
518 } catch (IllegalArgumentException e) {
519 // expected
520 }
521
522 try {
523 FieldUtils.readDeclaredField((Object)null, "none");
524 fail("a null target should cause an IllegalArgumentException");
525 } catch (IllegalArgumentException e) {
526 // expected
527 }
528
529 try {
530 assertEquals("s", FieldUtils.readDeclaredField(publicChild, "s"));
531 fail("expected IllegalArgumentException");
532 } catch (IllegalArgumentException e) {
533 // pass
534 }
535 assertEquals("ss", FieldUtils.readDeclaredField(publiclyShadowedChild, "s"));
536 try {
537 assertEquals("s", FieldUtils.readDeclaredField(privatelyShadowedChild, "s"));
538 fail("expected IllegalArgumentException");
539 } catch (IllegalArgumentException e) {
540 // pass
541 }
542 try {
543 assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(publicChild, "b"));
544 fail("expected IllegalArgumentException");
545 } catch (IllegalArgumentException e) {
546 // pass
547 }
548 assertEquals(Boolean.TRUE, FieldUtils.readDeclaredField(publiclyShadowedChild, "b"));
549 try {
550 assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(privatelyShadowedChild, "b"));
551 fail("expected IllegalArgumentException");
552 } catch (IllegalArgumentException e) {
553 // pass
554 }
555 try {
556 assertEquals(I0, FieldUtils.readDeclaredField(publicChild, "i"));
557 fail("expected IllegalArgumentException");
558 } catch (IllegalArgumentException e) {
559 // pass
560 }
561 assertEquals(I1, FieldUtils.readDeclaredField(publiclyShadowedChild, "i"));
562 try {
563 assertEquals(I0, FieldUtils.readDeclaredField(privatelyShadowedChild, "i"));
564 fail("expected IllegalArgumentException");
565 } catch (IllegalArgumentException e) {
566 // pass
567 }
568 try {
569 assertEquals(D0, FieldUtils.readDeclaredField(publicChild, "d"));
570 fail("expected IllegalArgumentException");
571 } catch (IllegalArgumentException e) {
572 // pass
573 }
574 assertEquals(D1, FieldUtils.readDeclaredField(publiclyShadowedChild, "d"));
575 try {
576 assertEquals(D0, FieldUtils.readDeclaredField(privatelyShadowedChild, "d"));
577 fail("expected IllegalArgumentException");
578 } catch (IllegalArgumentException e) {
579 // pass
580 }
581 }
582
583 @Test
584 public void testReadDeclaredNamedFieldForceAccess() throws Exception {
585 try {
586 FieldUtils.readDeclaredField(publicChild, null, true);
587 fail("a null field name should cause an IllegalArgumentException");
588 } catch (IllegalArgumentException e) {
589 // expected
590 }
591
592 try {
593 FieldUtils.readDeclaredField((Object)null, "none", true);
594 fail("a null target should cause an IllegalArgumentException");
595 } catch (IllegalArgumentException e) {
596 // expected
597 }
598
599 try {
600 assertEquals("s", FieldUtils.readDeclaredField(publicChild, "s", true));
601 fail("expected IllegalArgumentException");
602 } catch (IllegalArgumentException e) {
603 // pass
604 }
605 assertEquals("ss", FieldUtils.readDeclaredField(publiclyShadowedChild, "s", true));
606 assertEquals("ss", FieldUtils.readDeclaredField(privatelyShadowedChild, "s", true));
607 try {
608 assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(publicChild, "b", true));
609 fail("expected IllegalArgumentException");
610 } catch (IllegalArgumentException e) {
611 // pass
612 }
613 assertEquals(Boolean.TRUE, FieldUtils.readDeclaredField(publiclyShadowedChild, "b", true));
614 assertEquals(Boolean.TRUE, FieldUtils.readDeclaredField(privatelyShadowedChild, "b", true));
615 try {
616 assertEquals(I0, FieldUtils.readDeclaredField(publicChild, "i", true));
617 fail("expected IllegalArgumentException");
618 } catch (IllegalArgumentException e) {
619 // pass
620 }
621 assertEquals(I1, FieldUtils.readDeclaredField(publiclyShadowedChild, "i", true));
622 assertEquals(I1, FieldUtils.readDeclaredField(privatelyShadowedChild, "i", true));
623 try {
624 assertEquals(D0, FieldUtils.readDeclaredField(publicChild, "d", true));
625 fail("expected IllegalArgumentException");
626 } catch (IllegalArgumentException e) {
627 // pass
628 }
629 assertEquals(D1, FieldUtils.readDeclaredField(publiclyShadowedChild, "d", true));
630 assertEquals(D1, FieldUtils.readDeclaredField(privatelyShadowedChild, "d", true));
631 }
632
633 @Test
634 public void testWriteStaticField() throws Exception {
635 Field field = StaticContainer.class.getDeclaredField("mutablePublic");
636 FieldUtils.writeStaticField(field, "new");
637 assertEquals("new", StaticContainer.mutablePublic);
638 field = StaticContainer.class.getDeclaredField("mutableProtected");
639 try {
640 FieldUtils.writeStaticField(field, "new");
641 fail("Expected IllegalAccessException");
642 } catch (IllegalAccessException e) {
643 // pass
644 }
645 field = StaticContainer.class.getDeclaredField("mutablePackage");
646 try {
647 FieldUtils.writeStaticField(field, "new");
648 fail("Expected IllegalAccessException");
649 } catch (IllegalAccessException e) {
650 // pass
651 }
652 field = StaticContainer.class.getDeclaredField("mutablePrivate");
653 try {
654 FieldUtils.writeStaticField(field, "new");
655 fail("Expected IllegalAccessException");
656 } catch (IllegalAccessException e) {
657 // pass
658 }
659 field = StaticContainer.class.getDeclaredField("IMMUTABLE_PUBLIC");
660 try {
661 FieldUtils.writeStaticField(field, "new");
662 fail("Expected IllegalAccessException");
663 } catch (IllegalAccessException e) {
664 // pass
665 }
666 field = StaticContainer.class.getDeclaredField("IMMUTABLE_PROTECTED");
667 try {
668 FieldUtils.writeStaticField(field, "new");
669 fail("Expected IllegalAccessException");
670 } catch (IllegalAccessException e) {
671 // pass
672 }
673 field = StaticContainer.class.getDeclaredField("IMMUTABLE_PACKAGE");
674 try {
675 FieldUtils.writeStaticField(field, "new");
676 fail("Expected IllegalAccessException");
677 } catch (IllegalAccessException e) {
678 // pass
679 }
680 field = StaticContainer.class.getDeclaredField("IMMUTABLE_PRIVATE");
681 try {
682 FieldUtils.writeStaticField(field, "new");
683 fail("Expected IllegalAccessException");
684 } catch (IllegalAccessException e) {
685 // pass
686 }
687 }
688
689 @Test
690 public void testWriteStaticFieldForceAccess() throws Exception {
691 Field field = StaticContainer.class.getDeclaredField("mutablePublic");
692 FieldUtils.writeStaticField(field, "new", true);
693 assertEquals("new", StaticContainer.mutablePublic);
694 field = StaticContainer.class.getDeclaredField("mutableProtected");
695 FieldUtils.writeStaticField(field, "new", true);
696 assertEquals("new", StaticContainer.getMutableProtected());
697 field = StaticContainer.class.getDeclaredField("mutablePackage");
698 FieldUtils.writeStaticField(field, "new", true);
699 assertEquals("new", StaticContainer.getMutablePackage());
700 field = StaticContainer.class.getDeclaredField("mutablePrivate");
701 FieldUtils.writeStaticField(field, "new", true);
702 assertEquals("new", StaticContainer.getMutablePrivate());
703 field = StaticContainer.class.getDeclaredField("IMMUTABLE_PUBLIC");
704 try {
705 FieldUtils.writeStaticField(field, "new", true);
706 fail("Expected IllegalAccessException");
707 } catch (IllegalAccessException e) {
708 // pass
709 }
710 field = StaticContainer.class.getDeclaredField("IMMUTABLE_PROTECTED");
711 try {
712 FieldUtils.writeStaticField(field, "new", true);
713 fail("Expected IllegalAccessException");
714 } catch (IllegalAccessException e) {
715 // pass
716 }
717 field = StaticContainer.class.getDeclaredField("IMMUTABLE_PACKAGE");
718 try {
719 FieldUtils.writeStaticField(field, "new", true);
720 fail("Expected IllegalAccessException");
721 } catch (IllegalAccessException e) {
722 // pass
723 }
724 field = StaticContainer.class.getDeclaredField("IMMUTABLE_PRIVATE");
725 try {
726 FieldUtils.writeStaticField(field, "new", true);
727 fail("Expected IllegalAccessException");
728 } catch (IllegalAccessException e) {
729 // pass
730 }
731 }
732
733 @Test
734 public void testWriteNamedStaticField() throws Exception {
735 FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePublic", "new");
736 assertEquals("new", StaticContainer.mutablePublic);
737 try {
738 FieldUtils.writeStaticField(StaticContainerChild.class, "mutableProtected", "new");
739 fail("Expected IllegalArgumentException");
740 } catch (IllegalArgumentException e) {
741 // pass
742 }
743 try {
744 FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePackage", "new");
745 fail("Expected IllegalArgumentException");
746 } catch (IllegalArgumentException e) {
747 // pass
748 }
749 try {
750 FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePrivate", "new");
751 fail("Expected IllegalArgumentException");
752 } catch (IllegalArgumentException e) {
753 // pass
754 }
755 try {
756 FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PUBLIC", "new");
757 fail("Expected IllegalAccessException");
758 } catch (IllegalAccessException e) {
759 // pass
760 }
761 try {
762 FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PROTECTED", "new");
763 fail("Expected IllegalArgumentException");
764 } catch (IllegalArgumentException e) {
765 // pass
766 }
767 try {
768 FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PACKAGE", "new");
769 fail("Expected IllegalArgumentException");
770 } catch (IllegalArgumentException e) {
771 // pass
772 }
773 try {
774 FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PRIVATE", "new");
775 fail("Expected IllegalArgumentException");
776 } catch (IllegalArgumentException e) {
777 // pass
778 }
779 }
780
781 @Test
782 public void testWriteNamedStaticFieldForceAccess() throws Exception {
783 FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePublic", "new", true);
784 assertEquals("new", StaticContainer.mutablePublic);
785 FieldUtils.writeStaticField(StaticContainerChild.class, "mutableProtected", "new", true);
786 assertEquals("new", StaticContainer.getMutableProtected());
787 FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePackage", "new", true);
788 assertEquals("new", StaticContainer.getMutablePackage());
789 FieldUtils.writeStaticField(StaticContainerChild.class, "mutablePrivate", "new", true);
790 assertEquals("new", StaticContainer.getMutablePrivate());
791 try {
792 FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PUBLIC", "new", true);
793 fail("Expected IllegalAccessException");
794 } catch (IllegalAccessException e) {
795 // pass
796 }
797 try {
798 FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PROTECTED", "new", true);
799 fail("Expected IllegalAccessException");
800 } catch (IllegalAccessException e) {
801 // pass
802 }
803 try {
804 FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PACKAGE", "new", true);
805 fail("Expected IllegalAccessException");
806 } catch (IllegalAccessException e) {
807 // pass
808 }
809 try {
810 FieldUtils.writeStaticField(StaticContainerChild.class, "IMMUTABLE_PRIVATE", "new", true);
811 fail("Expected IllegalAccessException");
812 } catch (IllegalAccessException e) {
813 // pass
814 }
815 }
816
817 @Test
818 public void testWriteDeclaredNamedStaticField() throws Exception {
819 FieldUtils.writeStaticField(StaticContainer.class, "mutablePublic", "new");
820 assertEquals("new", StaticContainer.mutablePublic);
821 try {
822 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutableProtected", "new");
823 fail("Expected IllegalArgumentException");
824 } catch (IllegalArgumentException e) {
825 // pass
826 }
827 try {
828 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutablePackage", "new");
829 fail("Expected IllegalArgumentException");
830 } catch (IllegalArgumentException e) {
831 // pass
832 }
833 try {
834 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutablePrivate", "new");
835 fail("Expected IllegalArgumentException");
836 } catch (IllegalArgumentException e) {
837 // pass
838 }
839 try {
840 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PUBLIC", "new");
841 fail("Expected IllegalAccessException");
842 } catch (IllegalAccessException e) {
843 // pass
844 }
845 try {
846 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PROTECTED", "new");
847 fail("Expected IllegalArgumentException");
848 } catch (IllegalArgumentException e) {
849 // pass
850 }
851 try {
852 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PACKAGE", "new");
853 fail("Expected IllegalArgumentException");
854 } catch (IllegalArgumentException e) {
855 // pass
856 }
857 try {
858 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PRIVATE", "new");
859 fail("Expected IllegalArgumentException");
860 } catch (IllegalArgumentException e) {
861 // pass
862 }
863 }
864
865 @Test
866 public void testWriteDeclaredNamedStaticFieldForceAccess() throws Exception {
867 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutablePublic", "new", true);
868 assertEquals("new", StaticContainer.mutablePublic);
869 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutableProtected", "new", true);
870 assertEquals("new", StaticContainer.getMutableProtected());
871 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutablePackage", "new", true);
872 assertEquals("new", StaticContainer.getMutablePackage());
873 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "mutablePrivate", "new", true);
874 assertEquals("new", StaticContainer.getMutablePrivate());
875 try {
876 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PUBLIC", "new", true);
877 fail("Expected IllegalAccessException");
878 } catch (IllegalAccessException e) {
879 // pass
880 }
881 try {
882 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PROTECTED", "new", true);
883 fail("Expected IllegalAccessException");
884 } catch (IllegalAccessException e) {
885 // pass
886 }
887 try {
888 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PACKAGE", "new", true);
889 fail("Expected IllegalAccessException");
890 } catch (IllegalAccessException e) {
891 // pass
892 }
893 try {
894 FieldUtils.writeDeclaredStaticField(StaticContainer.class, "IMMUTABLE_PRIVATE", "new", true);
895 fail("Expected IllegalAccessException");
896 } catch (IllegalAccessException e) {
897 // pass
898 }
899 }
900
901 @Test
902 public void testWriteField() throws Exception {
903 Field field = parentClass.getDeclaredField("s");
904 FieldUtils.writeField(field, publicChild, "S");
905 assertEquals("S", field.get(publicChild));
906 field = parentClass.getDeclaredField("b");
907 try {
908 FieldUtils.writeField(field, publicChild, Boolean.TRUE);
909 fail("Expected IllegalAccessException");
910 } catch (IllegalAccessException e) {
911 // pass
912 }
913 field = parentClass.getDeclaredField("i");
914 try {
915 FieldUtils.writeField(field, publicChild, Integer.valueOf(Integer.MAX_VALUE));
916 } catch (IllegalAccessException e) {
917 // pass
918 }
919 field = parentClass.getDeclaredField("d");
920 try {
921 FieldUtils.writeField(field, publicChild, Double.valueOf(Double.MAX_VALUE));
922 } catch (IllegalAccessException e) {
923 // pass
924 }
925 }
926
927 @Test
928 public void testWriteFieldForceAccess() throws Exception {
929 Field field = parentClass.getDeclaredField("s");
930 FieldUtils.writeField(field, publicChild, "S", true);
931 assertEquals("S", field.get(publicChild));
932 field = parentClass.getDeclaredField("b");
933 FieldUtils.writeField(field, publicChild, Boolean.TRUE, true);
934 assertEquals(Boolean.TRUE, field.get(publicChild));
935 field = parentClass.getDeclaredField("i");
936 FieldUtils.writeField(field, publicChild, Integer.valueOf(Integer.MAX_VALUE), true);
937 assertEquals(Integer.valueOf(Integer.MAX_VALUE), field.get(publicChild));
938 field = parentClass.getDeclaredField("d");
939 FieldUtils.writeField(field, publicChild, Double.valueOf(Double.MAX_VALUE), true);
940 assertEquals(Double.valueOf(Double.MAX_VALUE), field.get(publicChild));
941 }
942
943 @Test
944 public void testWriteNamedField() throws Exception {
945 FieldUtils.writeField(publicChild, "s", "S");
946 assertEquals("S", FieldUtils.readField(publicChild, "s"));
947 try {
948 FieldUtils.writeField(publicChild, "b", Boolean.TRUE);
949 fail("Expected IllegalArgumentException");
950 } catch (IllegalArgumentException e) {
951 // pass
952 }
953 try {
954 FieldUtils.writeField(publicChild, "i", Integer.valueOf(1));
955 fail("Expected IllegalArgumentException");
956 } catch (IllegalArgumentException e) {
957 // pass
958 }
959 try {
960 FieldUtils.writeField(publicChild, "d", Double.valueOf(1.0));
961 fail("Expected IllegalArgumentException");
962 } catch (IllegalArgumentException e) {
963 // pass
964 }
965
966 FieldUtils.writeField(publiclyShadowedChild, "s", "S");
967 assertEquals("S", FieldUtils.readField(publiclyShadowedChild, "s"));
968 FieldUtils.writeField(publiclyShadowedChild, "b", Boolean.FALSE);
969 assertEquals(Boolean.FALSE, FieldUtils.readField(publiclyShadowedChild, "b"));
970 FieldUtils.writeField(publiclyShadowedChild, "i", Integer.valueOf(0));
971 assertEquals(Integer.valueOf(0), FieldUtils.readField(publiclyShadowedChild, "i"));
972 FieldUtils.writeField(publiclyShadowedChild, "d", Double.valueOf(0.0));
973 assertEquals(Double.valueOf(0.0), FieldUtils.readField(publiclyShadowedChild, "d"));
974
975 FieldUtils.writeField(privatelyShadowedChild, "s", "S");
976 assertEquals("S", FieldUtils.readField(privatelyShadowedChild, "s"));
977 try {
978 FieldUtils.writeField(privatelyShadowedChild, "b", Boolean.TRUE);
979 fail("Expected IllegalArgumentException");
980 } catch (IllegalArgumentException e) {
981 // pass
982 }
983 try {
984 FieldUtils.writeField(privatelyShadowedChild, "i", Integer.valueOf(1));
985 fail("Expected IllegalArgumentException");
986 } catch (IllegalArgumentException e) {
987 // pass
988 }
989 try {
990 FieldUtils.writeField(privatelyShadowedChild, "d", Double.valueOf(1.0));
991 fail("Expected IllegalArgumentException");
992 } catch (IllegalArgumentException e) {
993 // pass
994 }
995 }
996
997 @Test
998 public void testWriteNamedFieldForceAccess() throws Exception {
999 FieldUtils.writeField(publicChild, "s", "S", true);
1000 assertEquals("S", FieldUtils.readField(publicChild, "s", true));
1001 FieldUtils.writeField(publicChild, "b", Boolean.TRUE, true);
1002 assertEquals(Boolean.TRUE, FieldUtils.readField(publicChild, "b", true));
1003 FieldUtils.writeField(publicChild, "i", Integer.valueOf(1), true);
1004 assertEquals(Integer.valueOf(1), FieldUtils.readField(publicChild, "i", true));
1005 FieldUtils.writeField(publicChild, "d", Double.valueOf(1.0), true);
1006 assertEquals(Double.valueOf(1.0), FieldUtils.readField(publicChild, "d", true));
1007
1008 FieldUtils.writeField(publiclyShadowedChild, "s", "S", true);
1009 assertEquals("S", FieldUtils.readField(publiclyShadowedChild, "s", true));
1010 FieldUtils.writeField(publiclyShadowedChild, "b", Boolean.FALSE, true);
1011 assertEquals(Boolean.FALSE, FieldUtils.readField(publiclyShadowedChild, "b", true));
1012 FieldUtils.writeField(publiclyShadowedChild, "i", Integer.valueOf(0), true);
1013 assertEquals(Integer.valueOf(0), FieldUtils.readField(publiclyShadowedChild, "i", true));
1014 FieldUtils.writeField(publiclyShadowedChild, "d", Double.valueOf(0.0), true);
1015 assertEquals(Double.valueOf(0.0), FieldUtils.readField(publiclyShadowedChild, "d", true));
1016
1017 FieldUtils.writeField(privatelyShadowedChild, "s", "S", true);
1018 assertEquals("S", FieldUtils.readField(privatelyShadowedChild, "s", true));
1019 FieldUtils.writeField(privatelyShadowedChild, "b", Boolean.FALSE, true);
1020 assertEquals(Boolean.FALSE, FieldUtils.readField(privatelyShadowedChild, "b", true));
1021 FieldUtils.writeField(privatelyShadowedChild, "i", Integer.valueOf(0), true);
1022 assertEquals(Integer.valueOf(0), FieldUtils.readField(privatelyShadowedChild, "i", true));
1023 FieldUtils.writeField(privatelyShadowedChild, "d", Double.valueOf(0.0), true);
1024 assertEquals(Double.valueOf(0.0), FieldUtils.readField(privatelyShadowedChild, "d", true));
1025 }
1026
1027 @Test
1028 public void testWriteDeclaredNamedField() throws Exception {
1029 try {
1030 FieldUtils.writeDeclaredField(publicChild, "s", "S");
1031 fail("Expected IllegalArgumentException");
1032 } catch (IllegalArgumentException e) {
1033 // pass
1034 }
1035 try {
1036 FieldUtils.writeDeclaredField(publicChild, "b", Boolean.TRUE);
1037 fail("Expected IllegalArgumentException");
1038 } catch (IllegalArgumentException e) {
1039 // pass
1040 }
1041 try {
1042 FieldUtils.writeDeclaredField(publicChild, "i", Integer.valueOf(1));
1043 fail("Expected IllegalArgumentException");
1044 } catch (IllegalArgumentException e) {
1045 // pass
1046 }
1047 try {
1048 FieldUtils.writeDeclaredField(publicChild, "d", Double.valueOf(1.0));
1049 fail("Expected IllegalArgumentException");
1050 } catch (IllegalArgumentException e) {
1051 // pass
1052 }
1053
1054 FieldUtils.writeDeclaredField(publiclyShadowedChild, "s", "S");
1055 assertEquals("S", FieldUtils.readDeclaredField(publiclyShadowedChild, "s"));
1056 FieldUtils.writeDeclaredField(publiclyShadowedChild, "b", Boolean.FALSE);
1057 assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(publiclyShadowedChild, "b"));
1058 FieldUtils.writeDeclaredField(publiclyShadowedChild, "i", Integer.valueOf(0));
1059 assertEquals(Integer.valueOf(0), FieldUtils.readDeclaredField(publiclyShadowedChild, "i"));
1060 FieldUtils.writeDeclaredField(publiclyShadowedChild, "d", Double.valueOf(0.0));
1061 assertEquals(Double.valueOf(0.0), FieldUtils.readDeclaredField(publiclyShadowedChild, "d"));
1062
1063 try {
1064 FieldUtils.writeDeclaredField(privatelyShadowedChild, "s", "S");
1065 fail("Expected IllegalArgumentException");
1066 } catch (IllegalArgumentException e) {
1067 // pass
1068 }
1069 try {
1070 FieldUtils.writeDeclaredField(privatelyShadowedChild, "b", Boolean.TRUE);
1071 fail("Expected IllegalArgumentException");
1072 } catch (IllegalArgumentException e) {
1073 // pass
1074 }
1075 try {
1076 FieldUtils.writeDeclaredField(privatelyShadowedChild, "i", Integer.valueOf(1));
1077 fail("Expected IllegalArgumentException");
1078 } catch (IllegalArgumentException e) {
1079 // pass
1080 }
1081 try {
1082 FieldUtils.writeDeclaredField(privatelyShadowedChild, "d", Double.valueOf(1.0));
1083 fail("Expected IllegalArgumentException");
1084 } catch (IllegalArgumentException e) {
1085 // pass
1086 }
1087 }
1088
1089 @Test
1090 public void testWriteDeclaredNamedFieldForceAccess() throws Exception {
1091 try {
1092 FieldUtils.writeDeclaredField(publicChild, "s", "S", true);
1093 fail("Expected IllegalArgumentException");
1094 } catch (IllegalArgumentException e) {
1095 // pass
1096 }
1097 try {
1098 FieldUtils.writeDeclaredField(publicChild, "b", Boolean.TRUE, true);
1099 fail("Expected IllegalArgumentException");
1100 } catch (IllegalArgumentException e) {
1101 // pass
1102 }
1103 try {
1104 FieldUtils.writeDeclaredField(publicChild, "i", Integer.valueOf(1), true);
1105 fail("Expected IllegalArgumentException");
1106 } catch (IllegalArgumentException e) {
1107 // pass
1108 }
1109 try {
1110 FieldUtils.writeDeclaredField(publicChild, "d", Double.valueOf(1.0), true);
1111 fail("Expected IllegalArgumentException");
1112 } catch (IllegalArgumentException e) {
1113 // pass
1114 }
1115
1116 FieldUtils.writeDeclaredField(publiclyShadowedChild, "s", "S", true);
1117 assertEquals("S", FieldUtils.readDeclaredField(publiclyShadowedChild, "s", true));
1118 FieldUtils.writeDeclaredField(publiclyShadowedChild, "b", Boolean.FALSE, true);
1119 assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(publiclyShadowedChild, "b", true));
1120 FieldUtils.writeDeclaredField(publiclyShadowedChild, "i", Integer.valueOf(0), true);
1121 assertEquals(Integer.valueOf(0), FieldUtils.readDeclaredField(publiclyShadowedChild, "i", true));
1122 FieldUtils.writeDeclaredField(publiclyShadowedChild, "d", Double.valueOf(0.0), true);
1123 assertEquals(Double.valueOf(0.0), FieldUtils.readDeclaredField(publiclyShadowedChild, "d", true));
1124
1125 FieldUtils.writeDeclaredField(privatelyShadowedChild, "s", "S", true);
1126 assertEquals("S", FieldUtils.readDeclaredField(privatelyShadowedChild, "s", true));
1127 FieldUtils.writeDeclaredField(privatelyShadowedChild, "b", Boolean.FALSE, true);
1128 assertEquals(Boolean.FALSE, FieldUtils.readDeclaredField(privatelyShadowedChild, "b", true));
1129 FieldUtils.writeDeclaredField(privatelyShadowedChild, "i", Integer.valueOf(0), true);
1130 assertEquals(Integer.valueOf(0), FieldUtils.readDeclaredField(privatelyShadowedChild, "i", true));
1131 FieldUtils.writeDeclaredField(privatelyShadowedChild, "d", Double.valueOf(0.0), true);
1132 assertEquals(Double.valueOf(0.0), FieldUtils.readDeclaredField(privatelyShadowedChild, "d", true));
1133 }
1134
1135 @Test(expected=IllegalArgumentException.class)
1136 public void testAmbig() {
1137 FieldUtils.getField(Ambig.class, "VALUE");
1138 }
1139
1140 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect;
17
18 import java.lang.reflect.Method;
19 import java.util.Arrays;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import junit.framework.TestCase;
24
25 import org.apache.commons.lang3.ArrayUtils;
26 import org.apache.commons.lang3.math.NumberUtils;
27 import org.apache.commons.lang3.mutable.Mutable;
28 import org.apache.commons.lang3.mutable.MutableObject;
29
30 /**
31 * Unit tests MethodUtils
32 * @version $Id: MethodUtilsTest.java 1144929 2011-07-10 18:26:16Z ggregory $
33 */
34 public class MethodUtilsTest extends TestCase {
35
36 private static interface PrivateInterface {}
37
38 static class TestBeanWithInterfaces implements PrivateInterface {
39 public String foo() {
40 return "foo()";
41 }
42 }
43
44 public static class TestBean {
45
46 public static String bar() {
47 return "bar()";
48 }
49
50 public static String bar(int i) {
51 return "bar(int)";
52 }
53
54 public static String bar(Integer i) {
55 return "bar(Integer)";
56 }
57
58 public static String bar(double d) {
59 return "bar(double)";
60 }
61
62 public static String bar(String s) {
63 return "bar(String)";
64 }
65
66 public static String bar(Object o) {
67 return "bar(Object)";
68 }
69
70 @SuppressWarnings("unused")
71 private void privateStuff() {
72 }
73
74
75 public String foo() {
76 return "foo()";
77 }
78
79 public String foo(int i) {
80 return "foo(int)";
81 }
82
83 public String foo(Integer i) {
84 return "foo(Integer)";
85 }
86
87 public String foo(double d) {
88 return "foo(double)";
89 }
90
91 public String foo(String s) {
92 return "foo(String)";
93 }
94
95 public String foo(Object o) {
96 return "foo(Object)";
97 }
98 }
99
100 private static class TestMutable implements Mutable<Object> {
101 public Object getValue() {
102 return null;
103 }
104
105 public void setValue(Object value) {
106 }
107 }
108
109 private TestBean testBean;
110 private Map<Class<?>, Class<?>[]> classCache;
111
112 public MethodUtilsTest(String name) {
113 super(name);
114 classCache = new HashMap<Class<?>, Class<?>[]>();
115 }
116
117 @Override
118 protected void setUp() throws Exception {
119 super.setUp();
120 testBean = new TestBean();
121 classCache.clear();
122 }
123
124 public void testConstructor() throws Exception {
125 assertNotNull(MethodUtils.class.newInstance());
126 }
127
128 public void testInvokeMethod() throws Exception {
129 assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo",
130 (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
131 assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo",
132 (Object[]) null));
133 assertEquals("foo()", MethodUtils.invokeMethod(testBean, "foo",
134 (Object[]) null, (Class<?>[]) null));
135 assertEquals("foo(String)", MethodUtils.invokeMethod(testBean, "foo",
136 ""));
137 assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo",
138 new Object()));
139 assertEquals("foo(Object)", MethodUtils.invokeMethod(testBean, "foo",
140 Boolean.TRUE));
141 assertEquals("foo(Integer)", MethodUtils.invokeMethod(testBean, "foo",
142 NumberUtils.INTEGER_ONE));
143 assertEquals("foo(int)", MethodUtils.invokeMethod(testBean, "foo",
144 NumberUtils.BYTE_ONE));
145 assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo",
146 NumberUtils.LONG_ONE));
147 assertEquals("foo(double)", MethodUtils.invokeMethod(testBean, "foo",
148 NumberUtils.DOUBLE_ONE));
149 }
150
151 public void testInvokeExactMethod() throws Exception {
152 assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo",
153 (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
154 assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo",
155 (Object[]) null));
156 assertEquals("foo()", MethodUtils.invokeExactMethod(testBean, "foo",
157 (Object[]) null, (Class<?>[]) null));
158 assertEquals("foo(String)", MethodUtils.invokeExactMethod(testBean,
159 "foo", ""));
160 assertEquals("foo(Object)", MethodUtils.invokeExactMethod(testBean,
161 "foo", new Object()));
162 assertEquals("foo(Integer)", MethodUtils.invokeExactMethod(testBean,
163 "foo", NumberUtils.INTEGER_ONE));
164 assertEquals("foo(double)", MethodUtils.invokeExactMethod(testBean,
165 "foo", new Object[] { NumberUtils.DOUBLE_ONE },
166 new Class[] { Double.TYPE }));
167
168 try {
169 MethodUtils
170 .invokeExactMethod(testBean, "foo", NumberUtils.BYTE_ONE);
171 fail("should throw NoSuchMethodException");
172 } catch (NoSuchMethodException e) {
173 }
174 try {
175 MethodUtils
176 .invokeExactMethod(testBean, "foo", NumberUtils.LONG_ONE);
177 fail("should throw NoSuchMethodException");
178 } catch (NoSuchMethodException e) {
179 }
180 try {
181 MethodUtils.invokeExactMethod(testBean, "foo", Boolean.TRUE);
182 fail("should throw NoSuchMethodException");
183 } catch (NoSuchMethodException e) {
184 }
185 }
186
187 public void testInvokeStaticMethod() throws Exception {
188 assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class,
189 "bar", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
190 assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class,
191 "bar", (Object[]) null));
192 assertEquals("bar()", MethodUtils.invokeStaticMethod(TestBean.class,
193 "bar", (Object[]) null, (Class<?>[]) null));
194 assertEquals("bar(String)", MethodUtils.invokeStaticMethod(
195 TestBean.class, "bar", ""));
196 assertEquals("bar(Object)", MethodUtils.invokeStaticMethod(
197 TestBean.class, "bar", new Object()));
198 assertEquals("bar(Object)", MethodUtils.invokeStaticMethod(
199 TestBean.class, "bar", Boolean.TRUE));
200 assertEquals("bar(Integer)", MethodUtils.invokeStaticMethod(
201 TestBean.class, "bar", NumberUtils.INTEGER_ONE));
202 assertEquals("bar(int)", MethodUtils.invokeStaticMethod(TestBean.class,
203 "bar", NumberUtils.BYTE_ONE));
204 assertEquals("bar(double)", MethodUtils.invokeStaticMethod(
205 TestBean.class, "bar", NumberUtils.LONG_ONE));
206 assertEquals("bar(double)", MethodUtils.invokeStaticMethod(
207 TestBean.class, "bar", NumberUtils.DOUBLE_ONE));
208
209 try {
210 MethodUtils.invokeStaticMethod(TestBean.class, "does_not_exist");
211 fail("should throw NoSuchMethodException");
212 } catch (NoSuchMethodException e) {
213 }
214 }
215
216 public void testInvokeExactStaticMethod() throws Exception {
217 assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class,
218 "bar", (Object[]) ArrayUtils.EMPTY_CLASS_ARRAY));
219 assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class,
220 "bar", (Object[]) null));
221 assertEquals("bar()", MethodUtils.invokeExactStaticMethod(TestBean.class,
222 "bar", (Object[]) null, (Class<?>[]) null));
223 assertEquals("bar(String)", MethodUtils.invokeExactStaticMethod(
224 TestBean.class, "bar", ""));
225 assertEquals("bar(Object)", MethodUtils.invokeExactStaticMethod(
226 TestBean.class, "bar", new Object()));
227 assertEquals("bar(Integer)", MethodUtils.invokeExactStaticMethod(
228 TestBean.class, "bar", NumberUtils.INTEGER_ONE));
229 assertEquals("bar(double)", MethodUtils.invokeExactStaticMethod(
230 TestBean.class, "bar", new Object[] { NumberUtils.DOUBLE_ONE },
231 new Class[] { Double.TYPE }));
232
233 try {
234 MethodUtils.invokeExactStaticMethod(TestBean.class, "bar",
235 NumberUtils.BYTE_ONE);
236 fail("should throw NoSuchMethodException");
237 } catch (NoSuchMethodException e) {
238 }
239 try {
240 MethodUtils.invokeExactStaticMethod(TestBean.class, "bar",
241 NumberUtils.LONG_ONE);
242 fail("should throw NoSuchMethodException");
243 } catch (NoSuchMethodException e) {
244 }
245 try {
246 MethodUtils.invokeExactStaticMethod(TestBean.class, "bar",
247 Boolean.TRUE);
248 fail("should throw NoSuchMethodException");
249 } catch (NoSuchMethodException e) {
250 }
251 }
252
253 public void testGetAccessibleInterfaceMethod() throws Exception {
254
255 Class<?>[][] p = { ArrayUtils.EMPTY_CLASS_ARRAY, null };
256 for (Class<?>[] element : p) {
257 Method method = TestMutable.class.getMethod("getValue", element);
258 Method accessibleMethod = MethodUtils.getAccessibleMethod(method);
259 assertNotSame(accessibleMethod, method);
260 assertSame(Mutable.class, accessibleMethod.getDeclaringClass());
261 }
262 }
263
264 public void testGetAccessibleMethodPrivateInterface() throws Exception {
265 Method expected = TestBeanWithInterfaces.class.getMethod("foo");
266 assertNotNull(expected);
267 Method actual = MethodUtils.getAccessibleMethod(TestBeanWithInterfaces.class, "foo");
268 assertNull(actual);
269 }
270
271 public void testGetAccessibleInterfaceMethodFromDescription()
272 throws Exception {
273 Class<?>[][] p = { ArrayUtils.EMPTY_CLASS_ARRAY, null };
274 for (Class<?>[] element : p) {
275 Method accessibleMethod = MethodUtils.getAccessibleMethod(
276 TestMutable.class, "getValue", element);
277 assertSame(Mutable.class, accessibleMethod.getDeclaringClass());
278 }
279 }
280
281 public void testGetAccessiblePublicMethod() throws Exception {
282 assertSame(MutableObject.class, MethodUtils.getAccessibleMethod(
283 MutableObject.class.getMethod("getValue",
284 ArrayUtils.EMPTY_CLASS_ARRAY)).getDeclaringClass());
285 }
286
287 public void testGetAccessiblePublicMethodFromDescription() throws Exception {
288 assertSame(MutableObject.class, MethodUtils.getAccessibleMethod(
289 MutableObject.class, "getValue", ArrayUtils.EMPTY_CLASS_ARRAY)
290 .getDeclaringClass());
291 }
292
293 public void testGetAccessibleMethodInaccessible() throws Exception {
294 Method expected = TestBean.class.getDeclaredMethod("privateStuff");
295 Method actual = MethodUtils.getAccessibleMethod(expected);
296 assertNull(actual);
297 }
298
299 public void testGetMatchingAccessibleMethod() throws Exception {
300 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
301 ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_CLASS_ARRAY);
302 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
303 null, ArrayUtils.EMPTY_CLASS_ARRAY);
304 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
305 singletonArray(String.class), singletonArray(String.class));
306 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
307 singletonArray(Object.class), singletonArray(Object.class));
308 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
309 singletonArray(Boolean.class), singletonArray(Object.class));
310 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
311 singletonArray(Byte.class), singletonArray(Integer.TYPE));
312 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
313 singletonArray(Byte.TYPE), singletonArray(Integer.TYPE));
314 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
315 singletonArray(Short.class), singletonArray(Integer.TYPE));
316 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
317 singletonArray(Short.TYPE), singletonArray(Integer.TYPE));
318 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
319 singletonArray(Character.class), singletonArray(Integer.TYPE));
320 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
321 singletonArray(Character.TYPE), singletonArray(Integer.TYPE));
322 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
323 singletonArray(Integer.class), singletonArray(Integer.class));
324 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
325 singletonArray(Integer.TYPE), singletonArray(Integer.TYPE));
326 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
327 singletonArray(Long.class), singletonArray(Double.TYPE));
328 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
329 singletonArray(Long.TYPE), singletonArray(Double.TYPE));
330 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
331 singletonArray(Float.class), singletonArray(Double.TYPE));
332 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
333 singletonArray(Float.TYPE), singletonArray(Double.TYPE));
334 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
335 singletonArray(Double.class), singletonArray(Double.TYPE));
336 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
337 singletonArray(Double.TYPE), singletonArray(Double.TYPE));
338 expectMatchingAccessibleMethodParameterTypes(TestBean.class, "foo",
339 singletonArray(Double.TYPE), singletonArray(Double.TYPE));
340 expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testOne",
341 singletonArray(ParentObject.class), singletonArray(ParentObject.class));
342 expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testOne",
343 singletonArray(ChildObject.class), singletonArray(ParentObject.class));
344 expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testTwo",
345 singletonArray(ParentObject.class), singletonArray(GrandParentObject.class));
346 expectMatchingAccessibleMethodParameterTypes(InheritanceBean.class, "testTwo",
347 singletonArray(ChildObject.class), singletonArray(ChildInterface.class));
348 }
349
350 private void expectMatchingAccessibleMethodParameterTypes(Class<?> cls,
351 String methodName, Class<?>[] requestTypes, Class<?>[] actualTypes) {
352 Method m = MethodUtils.getMatchingAccessibleMethod(cls, methodName,
353 requestTypes);
354 assertTrue(toString(m.getParameterTypes()) + " not equals "
355 + toString(actualTypes), Arrays.equals(actualTypes, m
356 .getParameterTypes()));
357 }
358
359 private String toString(Class<?>[] c) {
360 return Arrays.asList(c).toString();
361 }
362
363 private Class<?>[] singletonArray(Class<?> c) {
364 Class<?>[] result = classCache.get(c);
365 if (result == null) {
366 result = new Class[] { c };
367 classCache.put(c, result);
368 }
369 return result;
370 }
371
372 public static class InheritanceBean {
373 public void testOne(Object obj) {}
374 public void testOne(GrandParentObject obj) {}
375 public void testOne(ParentObject obj) {}
376 public void testTwo(Object obj) {}
377 public void testTwo(GrandParentObject obj) {}
378 public void testTwo(ChildInterface obj) {}
379 }
380 interface ChildInterface {}
381 public static class GrandParentObject {}
382 public static class ParentObject extends GrandParentObject {}
383 public static class ChildObject extends ParentObject implements ChildInterface {}
384
385 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect;
17
18 import java.io.Serializable;
19 import java.lang.reflect.Method;
20 import java.lang.reflect.ParameterizedType;
21 import java.lang.reflect.Type;
22 import java.lang.reflect.TypeVariable;
23 import java.net.URI;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.TreeSet;
30
31 import org.apache.commons.lang3.StringEscapeUtils;
32 import org.apache.commons.lang3.reflect.testbed.Foo;
33 import org.apache.commons.lang3.reflect.testbed.GenericParent;
34 import org.apache.commons.lang3.reflect.testbed.GenericTypeHolder;
35 import org.apache.commons.lang3.reflect.testbed.StringParameterizedChild;
36 import org.junit.Assert;
37 import org.junit.Test;
38
39 /**
40 * Test TypeUtils
41 * @version $Id: TypeUtilsTest.java 1153484 2011-08-03 13:39:42Z ggregory $
42 */
43 @SuppressWarnings({ "unchecked", "unused" , "rawtypes", "null"})
44 //raw types, where used, are used purposely
45 public class TypeUtilsTest<B> {
46
47 public interface This<K, V> {
48 }
49
50 public class That<K, V> implements This<K, V> {
51 }
52
53 public interface And<K, V> extends This<Number, Number> {
54 }
55
56 public class The<K, V> extends That<Number, Number> implements And<String, String> {
57 }
58
59 public class Other<T> implements This<String, T> {
60 }
61
62 public class Thing<Q> extends Other<B> {
63 }
64
65 public class Tester implements This<String, B> {
66 }
67
68 public This<String, String> dis;
69
70 public That<String, String> dat;
71
72 public The<String, String> da;
73
74 public Other<String> uhder;
75
76 public Thing ding;
77
78 public TypeUtilsTest<String>.Tester tester;
79
80 public Tester tester2;
81
82 public TypeUtilsTest<String>.That<String, String> dat2;
83
84 public TypeUtilsTest<Number>.That<String, String> dat3;
85
86 public Comparable<? extends Integer>[] intWildcardComparable;
87
88 public static Comparable<String> stringComparable;
89
90 public static Comparable<URI> uriComparable;
91
92 public static Comparable<Integer> intComparable;
93
94 public static Comparable<Long> longComparable;
95
96 public static URI uri;
97
98 public void dummyMethod(List list0, List<Object> list1, List<?> list2,
99 List<? super Object> list3, List<String> list4, List<? extends String> list5,
100 List<? super String> list6, List[] list7, List<Object>[] list8, List<?>[] list9,
101 List<? super Object>[] list10, List<String>[] list11, List<? extends String>[] list12,
102 List<? super String>[] list13) {
103 }
104
105 @SuppressWarnings("boxing") // deliberately used here
106 @Test
107 public void testIsAssignable() throws SecurityException, NoSuchMethodException,
108 NoSuchFieldException {
109 List list0 = null;
110 List<Object> list1 = null;
111 List<?> list2 = null;
112 List<? super Object> list3 = null;
113 List<String> list4 = null;
114 List<? extends String> list5 = null;
115 List<? super String> list6 = null;
116 List[] list7 = null;
117 List<Object>[] list8 = null;
118 List<?>[] list9 = null;
119 List<? super Object>[] list10 = null;
120 List<String>[] list11 = null;
121 List<? extends String>[] list12 = null;
122 List<? super String>[] list13;
123 Class<?> clazz = getClass();
124 Method method = clazz.getMethod("dummyMethod", List.class, List.class, List.class,
125 List.class, List.class, List.class, List.class, List[].class, List[].class,
126 List[].class, List[].class, List[].class, List[].class, List[].class);
127 Type[] types = method.getGenericParameterTypes();
128 // list0 = list0;
129 delegateBooleanAssertion(types, 0, 0, true);
130 list1 = list0;
131 delegateBooleanAssertion(types, 0, 1, true);
132 list0 = list1;
133 delegateBooleanAssertion(types, 1, 0, true);
134 list2 = list0;
135 delegateBooleanAssertion(types, 0, 2, true);
136 list0 = list2;
137 delegateBooleanAssertion(types, 2, 0, true);
138 list3 = list0;
139 delegateBooleanAssertion(types, 0, 3, true);
140 list0 = list3;
141 delegateBooleanAssertion(types, 3, 0, true);
142 list4 = list0;
143 delegateBooleanAssertion(types, 0, 4, true);
144 list0 = list4;
145 delegateBooleanAssertion(types, 4, 0, true);
146 list5 = list0;
147 delegateBooleanAssertion(types, 0, 5, true);
148 list0 = list5;
149 delegateBooleanAssertion(types, 5, 0, true);
150 list6 = list0;
151 delegateBooleanAssertion(types, 0, 6, true);
152 list0 = list6;
153 delegateBooleanAssertion(types, 6, 0, true);
154 // list1 = list1;
155 delegateBooleanAssertion(types, 1, 1, true);
156 list2 = list1;
157 delegateBooleanAssertion(types, 1, 2, true);
158 list1 = (List<Object>) list2;
159 delegateBooleanAssertion(types, 2, 1, false);
160 list3 = list1;
161 delegateBooleanAssertion(types, 1, 3, true);
162 list1 = (List<Object>) list3;
163 delegateBooleanAssertion(types, 3, 1, false);
164 // list4 = list1;
165 delegateBooleanAssertion(types, 1, 4, false);
166 // list1 = list4;
167 delegateBooleanAssertion(types, 4, 1, false);
168 // list5 = list1;
169 delegateBooleanAssertion(types, 1, 5, false);
170 // list1 = list5;
171 delegateBooleanAssertion(types, 5, 1, false);
172 list6 = list1;
173 delegateBooleanAssertion(types, 1, 6, true);
174 list1 = (List<Object>) list6;
175 delegateBooleanAssertion(types, 6, 1, false);
176 // list2 = list2;
177 delegateBooleanAssertion(types, 2, 2, true);
178 list2 = list3;
179 delegateBooleanAssertion(types, 2, 3, false);
180 list2 = list4;
181 delegateBooleanAssertion(types, 3, 2, true);
182 list3 = (List<? super Object>) list2;
183 delegateBooleanAssertion(types, 2, 4, false);
184 list2 = list5;
185 delegateBooleanAssertion(types, 4, 2, true);
186 list4 = (List<String>) list2;
187 delegateBooleanAssertion(types, 2, 5, false);
188 list2 = list6;
189 delegateBooleanAssertion(types, 5, 2, true);
190 list5 = (List<? extends String>) list2;
191 delegateBooleanAssertion(types, 2, 6, false);
192 // list3 = list3;
193 delegateBooleanAssertion(types, 6, 2, true);
194 list6 = (List<? super String>) list2;
195 delegateBooleanAssertion(types, 3, 3, true);
196 // list4 = list3;
197 delegateBooleanAssertion(types, 3, 4, false);
198 // list3 = list4;
199 delegateBooleanAssertion(types, 4, 3, false);
200 // list5 = list3;
201 delegateBooleanAssertion(types, 3, 5, false);
202 // list3 = list5;
203 delegateBooleanAssertion(types, 5, 3, false);
204 list6 = list3;
205 delegateBooleanAssertion(types, 3, 6, true);
206 list3 = (List<? super Object>) list6;
207 delegateBooleanAssertion(types, 6, 3, false);
208 // list4 = list4;
209 delegateBooleanAssertion(types, 4, 4, true);
210 list5 = list4;
211 delegateBooleanAssertion(types, 4, 5, true);
212 list4 = (List<String>) list5;
213 delegateBooleanAssertion(types, 5, 4, false);
214 list6 = list4;
215 delegateBooleanAssertion(types, 4, 6, true);
216 list4 = (List<String>) list6;
217 delegateBooleanAssertion(types, 6, 4, false);
218 // list5 = list5;
219 delegateBooleanAssertion(types, 5, 5, true);
220 list6 = (List<? super String>) list5;
221 delegateBooleanAssertion(types, 5, 6, false);
222 list5 = (List<? extends String>) list6;
223 delegateBooleanAssertion(types, 6, 5, false);
224 // list6 = list6;
225 delegateBooleanAssertion(types, 6, 6, true);
226
227 // list7 = list7;
228 delegateBooleanAssertion(types, 7, 7, true);
229 list8 = list7;
230 delegateBooleanAssertion(types, 7, 8, true);
231 list7 = list8;
232 delegateBooleanAssertion(types, 8, 7, true);
233 list9 = list7;
234 delegateBooleanAssertion(types, 7, 9, true);
235 list7 = list9;
236 delegateBooleanAssertion(types, 9, 7, true);
237 list10 = list7;
238 delegateBooleanAssertion(types, 7, 10, true);
239 list7 = list10;
240 delegateBooleanAssertion(types, 10, 7, true);
241 list11 = list7;
242 delegateBooleanAssertion(types, 7, 11, true);
243 list7 = list11;
244 delegateBooleanAssertion(types, 11, 7, true);
245 list12 = list7;
246 delegateBooleanAssertion(types, 7, 12, true);
247 list7 = list12;
248 delegateBooleanAssertion(types, 12, 7, true);
249 list13 = list7;
250 delegateBooleanAssertion(types, 7, 13, true);
251 list7 = list13;
252 delegateBooleanAssertion(types, 13, 7, true);
253 // list8 = list8;
254 delegateBooleanAssertion(types, 8, 8, true);
255 list9 = list8;
256 delegateBooleanAssertion(types, 8, 9, true);
257 list8 = (List<Object>[]) list9;
258 delegateBooleanAssertion(types, 9, 8, false);
259 list10 = list8;
260 delegateBooleanAssertion(types, 8, 10, true);
261 list8 = (List<Object>[]) list10; // NOTE cast is required by Sun Java, but not by Eclipse
262 delegateBooleanAssertion(types, 10, 8, false);
263 // list11 = list8;
264 delegateBooleanAssertion(types, 8, 11, false);
265 // list8 = list11;
266 delegateBooleanAssertion(types, 11, 8, false);
267 // list12 = list8;
268 delegateBooleanAssertion(types, 8, 12, false);
269 // list8 = list12;
270 delegateBooleanAssertion(types, 12, 8, false);
271 list13 = list8;
272 delegateBooleanAssertion(types, 8, 13, true);
273 list8 = (List<Object>[]) list13;
274 delegateBooleanAssertion(types, 13, 8, false);
275 // list9 = list9;
276 delegateBooleanAssertion(types, 9, 9, true);
277 list10 = (List<? super Object>[]) list9;
278 delegateBooleanAssertion(types, 9, 10, false);
279 list9 = list10;
280 delegateBooleanAssertion(types, 10, 9, true);
281 list11 = (List<String>[]) list9;
282 delegateBooleanAssertion(types, 9, 11, false);
283 list9 = list11;
284 delegateBooleanAssertion(types, 11, 9, true);
285 list12 = (List<? extends String>[]) list9;
286 delegateBooleanAssertion(types, 9, 12, false);
287 list9 = list12;
288 delegateBooleanAssertion(types, 12, 9, true);
289 list13 = (List<? super String>[]) list9;
290 delegateBooleanAssertion(types, 9, 13, false);
291 list9 = list13;
292 delegateBooleanAssertion(types, 13, 9, true);
293 // list10 = list10;
294 delegateBooleanAssertion(types, 10, 10, true);
295 // list11 = list10;
296 delegateBooleanAssertion(types, 10, 11, false);
297 // list10 = list11;
298 delegateBooleanAssertion(types, 11, 10, false);
299 // list12 = list10;
300 delegateBooleanAssertion(types, 10, 12, false);
301 // list10 = list12;
302 delegateBooleanAssertion(types, 12, 10, false);
303 list13 = list10;
304 delegateBooleanAssertion(types, 10, 13, true);
305 list10 = (List<? super Object>[]) list13;
306 delegateBooleanAssertion(types, 13, 10, false);
307 // list11 = list11;
308 delegateBooleanAssertion(types, 11, 11, true);
309 list12 = list11;
310 delegateBooleanAssertion(types, 11, 12, true);
311 list11 = (List<String>[]) list12;
312 delegateBooleanAssertion(types, 12, 11, false);
313 list13 = list11;
314 delegateBooleanAssertion(types, 11, 13, true);
315 list11 = (List<String>[]) list13;
316 delegateBooleanAssertion(types, 13, 11, false);
317 // list12 = list12;
318 delegateBooleanAssertion(types, 12, 12, true);
319 list13 = (List<? super String>[]) list12;
320 delegateBooleanAssertion(types, 12, 13, false);
321 list12 = (List<? extends String>[]) list13;
322 delegateBooleanAssertion(types, 13, 12, false);
323 // list13 = list13;
324 delegateBooleanAssertion(types, 13, 13, true);
325 Type disType = getClass().getField("dis").getGenericType();
326 // Reporter.log( ( ( ParameterizedType ) disType
327 // ).getOwnerType().getClass().toString() );
328 Type datType = getClass().getField("dat").getGenericType();
329 Type daType = getClass().getField("da").getGenericType();
330 Type uhderType = getClass().getField("uhder").getGenericType();
331 Type dingType = getClass().getField("ding").getGenericType();
332 Type testerType = getClass().getField("tester").getGenericType();
333 Type tester2Type = getClass().getField("tester2").getGenericType();
334 Type dat2Type = getClass().getField("dat2").getGenericType();
335 Type dat3Type = getClass().getField("dat3").getGenericType();
336 dis = dat;
337 Assert.assertTrue(TypeUtils.isAssignable(datType, disType));
338 // dis = da;
339 Assert.assertFalse(TypeUtils.isAssignable(daType, disType));
340 dis = uhder;
341 Assert.assertTrue(TypeUtils.isAssignable(uhderType, disType));
342 dis = ding;
343 Assert.assertTrue("WRONG!", TypeUtils.isAssignable(dingType, disType));
344 dis = tester;
345 Assert.assertTrue(TypeUtils.isAssignable(testerType, disType));
346 // dis = tester2;
347 Assert.assertFalse(TypeUtils.isAssignable(tester2Type, disType));
348 // dat = dat2;
349 Assert.assertFalse(TypeUtils.isAssignable(dat2Type, datType));
350 // dat2 = dat;
351 Assert.assertFalse(TypeUtils.isAssignable(datType, dat2Type));
352 // dat = dat3;
353 Assert.assertFalse(TypeUtils.isAssignable(dat3Type, datType));
354 char ch = 0;
355 boolean bo = false;
356 byte by = 0;
357 short sh = 0;
358 int in = 0;
359 long lo = 0;
360 float fl = 0;
361 double du = 0;
362 du = ch;
363 Assert.assertTrue(TypeUtils.isAssignable(char.class, double.class));
364 du = by;
365 Assert.assertTrue(TypeUtils.isAssignable(byte.class, double.class));
366 du = sh;
367 Assert.assertTrue(TypeUtils.isAssignable(short.class, double.class));
368 du = in;
369 Assert.assertTrue(TypeUtils.isAssignable(int.class, double.class));
370 du = lo;
371 Assert.assertTrue(TypeUtils.isAssignable(long.class, double.class));
372 du = fl;
373 Assert.assertTrue(TypeUtils.isAssignable(float.class, double.class));
374 lo = in;
375 Assert.assertTrue(TypeUtils.isAssignable(int.class, long.class));
376 lo = Integer.valueOf(0);
377 Assert.assertTrue(TypeUtils.isAssignable(Integer.class, long.class));
378 // Long lngW = 1;
379 Assert.assertFalse(TypeUtils.isAssignable(int.class, Long.class));
380 // lngW = Integer.valueOf( 0 );
381 Assert.assertFalse(TypeUtils.isAssignable(Integer.class, Long.class));
382 in = Integer.valueOf(0);
383 Assert.assertTrue(TypeUtils.isAssignable(Integer.class, int.class));
384 Integer inte = in;
385 Assert.assertTrue(TypeUtils.isAssignable(int.class, Integer.class));
386 Assert.assertTrue(TypeUtils.isAssignable(int.class, Number.class));
387 Assert.assertTrue(TypeUtils.isAssignable(int.class, Object.class));
388 Type intComparableType = getClass().getField("intComparable").getGenericType();
389 intComparable = 1;
390 Assert.assertTrue(TypeUtils.isAssignable(int.class, intComparableType));
391 Assert.assertTrue(TypeUtils.isAssignable(int.class, Comparable.class));
392 Serializable ser = 1;
393 Assert.assertTrue(TypeUtils.isAssignable(int.class, Serializable.class));
394 Type longComparableType = getClass().getField("longComparable").getGenericType();
395 // longComparable = 1;
396 Assert.assertFalse(TypeUtils.isAssignable(int.class, longComparableType));
397 // longComparable = Integer.valueOf( 0 );
398 Assert.assertFalse(TypeUtils.isAssignable(Integer.class, longComparableType));
399 // int[] ia;
400 // long[] la = ia;
401 Assert.assertFalse(TypeUtils.isAssignable(int[].class, long[].class));
402 Integer[] ia = null;
403 Type caType = getClass().getField("intWildcardComparable").getGenericType();
404 intWildcardComparable = ia;
405 Assert.assertTrue(TypeUtils.isAssignable(Integer[].class, caType));
406 // int[] ina = ia;
407 Assert.assertFalse(TypeUtils.isAssignable(Integer[].class, int[].class));
408 int[] ina = null;
409 Object[] oa;
410 // oa = ina;
411 Assert.assertFalse(TypeUtils.isAssignable(int[].class, Object[].class));
412 oa = new Integer[0];
413 Assert.assertTrue(TypeUtils.isAssignable(Integer[].class, Object[].class));
414 Type bClassType = AClass.class.getField("bClass").getGenericType();
415 Type cClassType = AClass.class.getField("cClass").getGenericType();
416 Type dClassType = AClass.class.getField("dClass").getGenericType();
417 Type eClassType = AClass.class.getField("eClass").getGenericType();
418 Type fClassType = AClass.class.getField("fClass").getGenericType();
419 AClass aClass = new AClass(new AAClass<String>());
420 aClass.bClass = aClass.cClass;
421 Assert.assertTrue(TypeUtils.isAssignable(cClassType, bClassType));
422 aClass.bClass = aClass.dClass;
423 Assert.assertTrue(TypeUtils.isAssignable(dClassType, bClassType));
424 aClass.bClass = aClass.eClass;
425 Assert.assertTrue(TypeUtils.isAssignable(eClassType, bClassType));
426 aClass.bClass = aClass.fClass;
427 Assert.assertTrue(TypeUtils.isAssignable(fClassType, bClassType));
428 aClass.cClass = aClass.dClass;
429 Assert.assertTrue(TypeUtils.isAssignable(dClassType, cClassType));
430 aClass.cClass = aClass.eClass;
431 Assert.assertTrue(TypeUtils.isAssignable(eClassType, cClassType));
432 aClass.cClass = aClass.fClass;
433 Assert.assertTrue(TypeUtils.isAssignable(fClassType, cClassType));
434 aClass.dClass = aClass.eClass;
435 Assert.assertTrue(TypeUtils.isAssignable(eClassType, dClassType));
436 aClass.dClass = aClass.fClass;
437 Assert.assertTrue(TypeUtils.isAssignable(fClassType, dClassType));
438 aClass.eClass = aClass.fClass;
439 Assert.assertTrue(TypeUtils.isAssignable(fClassType, eClassType));
440 }
441
442 public void delegateBooleanAssertion(Type[] types, int i2, int i1, boolean expected) {
443 Type type1 = types[i1];
444 Type type2 = types[i2];
445 boolean isAssignable = TypeUtils.isAssignable(type2, type1);
446
447 if (expected) {
448 Assert.assertTrue("[" + i1 + ", " + i2 + "]: From "
449 + StringEscapeUtils.escapeHtml4(String.valueOf(type2)) + " to "
450 + StringEscapeUtils.escapeHtml4(String.valueOf(type1)), isAssignable);
451 } else {
452 Assert.assertFalse("[" + i1 + ", " + i2 + "]: From "
453 + StringEscapeUtils.escapeHtml4(String.valueOf(type2)) + " to "
454 + StringEscapeUtils.escapeHtml4(String.valueOf(type1)), isAssignable);
455 }
456 }
457
458 @SuppressWarnings("boxing") // boxing is deliberate here
459 @Test
460 public void testIsInstance() throws SecurityException, NoSuchFieldException {
461 Type intComparableType = getClass().getField("intComparable").getGenericType();
462 Type uriComparableType = getClass().getField("uriComparable").getGenericType();
463 intComparable = 1;
464 Assert.assertTrue(TypeUtils.isInstance(1, intComparableType));
465 // uriComparable = 1;
466 Assert.assertFalse(TypeUtils.isInstance(1, uriComparableType));
467 }
468
469 @Test
470 public void testGetTypeArguments() {
471 Map<TypeVariable<?>, Type> typeVarAssigns;
472 TypeVariable<?> treeSetTypeVar;
473 Type typeArg;
474
475 typeVarAssigns = TypeUtils.getTypeArguments(Integer.class, Comparable.class);
476 treeSetTypeVar = Comparable.class.getTypeParameters()[0];
477 Assert.assertTrue("Type var assigns for Comparable from Integer: " + typeVarAssigns,
478 typeVarAssigns.containsKey(treeSetTypeVar));
479 typeArg = typeVarAssigns.get(treeSetTypeVar);
480 Assert.assertEquals("Type argument of Comparable from Integer: " + typeArg, Integer.class,
481 typeVarAssigns.get(treeSetTypeVar));
482
483 typeVarAssigns = TypeUtils.getTypeArguments(int.class, Comparable.class);
484 treeSetTypeVar = Comparable.class.getTypeParameters()[0];
485 Assert.assertTrue("Type var assigns for Comparable from int: " + typeVarAssigns,
486 typeVarAssigns.containsKey(treeSetTypeVar));
487 typeArg = typeVarAssigns.get(treeSetTypeVar);
488 Assert.assertEquals("Type argument of Comparable from int: " + typeArg, Integer.class,
489 typeVarAssigns.get(treeSetTypeVar));
490
491 Collection<Integer> col = Arrays.asList(new Integer[0]);
492 typeVarAssigns = TypeUtils.getTypeArguments(List.class, Collection.class);
493 treeSetTypeVar = Comparable.class.getTypeParameters()[0];
494 Assert.assertFalse("Type var assigns for Collection from List: " + typeVarAssigns,
495 typeVarAssigns.containsKey(treeSetTypeVar));
496
497 typeVarAssigns = TypeUtils.getTypeArguments(AAAClass.BBBClass.class, AAClass.BBClass.class);
498 Assert.assertTrue(typeVarAssigns.size() == 2);
499 Assert.assertEquals(String.class, typeVarAssigns.get(AAClass.class.getTypeParameters()[0]));
500 Assert.assertEquals(String.class, typeVarAssigns.get(AAClass.BBClass.class.getTypeParameters()[0]));
501 }
502
503 @Test
504 public void testTypesSatisfyVariables() throws SecurityException, NoSuchFieldException,
505 NoSuchMethodException {
506 Map<TypeVariable<?>, Type> typeVarAssigns = new HashMap<TypeVariable<?>, Type>();
507 Integer max = TypeUtilsTest.stub();
508 typeVarAssigns.put(getClass().getMethod("stub").getTypeParameters()[0], Integer.class);
509 Assert.assertTrue(TypeUtils.typesSatisfyVariables(typeVarAssigns));
510 typeVarAssigns.clear();
511 typeVarAssigns.put(getClass().getMethod("stub2").getTypeParameters()[0], Integer.class);
512 Assert.assertTrue(TypeUtils.typesSatisfyVariables(typeVarAssigns));
513 typeVarAssigns.clear();
514 typeVarAssigns.put(getClass().getMethod("stub3").getTypeParameters()[0], Integer.class);
515 Assert.assertTrue(TypeUtils.typesSatisfyVariables(typeVarAssigns));
516 }
517
518 @Test
519 public void testDetermineTypeVariableAssignments() throws SecurityException,
520 NoSuchFieldException, NoSuchMethodException {
521 ParameterizedType iterableType = (ParameterizedType) getClass().getField("iterable")
522 .getGenericType();
523 Map<TypeVariable<?>, Type> typeVarAssigns = TypeUtils.determineTypeArguments(TreeSet.class,
524 iterableType);
525 TypeVariable<?> treeSetTypeVar = TreeSet.class.getTypeParameters()[0];
526 Assert.assertTrue(typeVarAssigns.containsKey(treeSetTypeVar));
527 Assert.assertEquals(iterableType.getActualTypeArguments()[0], typeVarAssigns
528 .get(treeSetTypeVar));
529 }
530
531 @Test
532 public void testGetRawType() throws SecurityException, NoSuchFieldException {
533 Type stringParentFieldType = GenericTypeHolder.class.getDeclaredField("stringParent")
534 .getGenericType();
535 Type integerParentFieldType = GenericTypeHolder.class.getDeclaredField("integerParent")
536 .getGenericType();
537 Type foosFieldType = GenericTypeHolder.class.getDeclaredField("foos").getGenericType();
538 Type genericParentT = GenericParent.class.getTypeParameters()[0];
539 Assert.assertEquals(GenericParent.class, TypeUtils.getRawType(stringParentFieldType, null));
540 Assert
541 .assertEquals(GenericParent.class, TypeUtils.getRawType(integerParentFieldType,
542 null));
543 Assert.assertEquals(List.class, TypeUtils.getRawType(foosFieldType, null));
544 Assert.assertEquals(String.class, TypeUtils.getRawType(genericParentT,
545 StringParameterizedChild.class));
546 Assert.assertEquals(String.class, TypeUtils.getRawType(genericParentT,
547 stringParentFieldType));
548 Assert.assertEquals(Foo.class, TypeUtils.getRawType(Iterable.class.getTypeParameters()[0],
549 foosFieldType));
550 Assert.assertEquals(Foo.class, TypeUtils.getRawType(List.class.getTypeParameters()[0],
551 foosFieldType));
552 Assert.assertNull(TypeUtils.getRawType(genericParentT, GenericParent.class));
553 Assert.assertEquals(GenericParent[].class, TypeUtils.getRawType(GenericTypeHolder.class
554 .getDeclaredField("barParents").getGenericType(), null));
555 }
556
557 @Test
558 public void testIsArrayTypeClasses() {
559 Assert.assertTrue(TypeUtils.isArrayType(boolean[].class));
560 Assert.assertTrue(TypeUtils.isArrayType(byte[].class));
561 Assert.assertTrue(TypeUtils.isArrayType(short[].class));
562 Assert.assertTrue(TypeUtils.isArrayType(int[].class));
563 Assert.assertTrue(TypeUtils.isArrayType(char[].class));
564 Assert.assertTrue(TypeUtils.isArrayType(long[].class));
565 Assert.assertTrue(TypeUtils.isArrayType(float[].class));
566 Assert.assertTrue(TypeUtils.isArrayType(double[].class));
567 Assert.assertTrue(TypeUtils.isArrayType(Object[].class));
568 Assert.assertTrue(TypeUtils.isArrayType(String[].class));
569
570 Assert.assertFalse(TypeUtils.isArrayType(boolean.class));
571 Assert.assertFalse(TypeUtils.isArrayType(byte.class));
572 Assert.assertFalse(TypeUtils.isArrayType(short.class));
573 Assert.assertFalse(TypeUtils.isArrayType(int.class));
574 Assert.assertFalse(TypeUtils.isArrayType(char.class));
575 Assert.assertFalse(TypeUtils.isArrayType(long.class));
576 Assert.assertFalse(TypeUtils.isArrayType(float.class));
577 Assert.assertFalse(TypeUtils.isArrayType(double.class));
578 Assert.assertFalse(TypeUtils.isArrayType(Object.class));
579 Assert.assertFalse(TypeUtils.isArrayType(String.class));
580 }
581
582 @Test
583 public void testIsArrayGenericTypes() throws Exception {
584 Method method = getClass().getMethod("dummyMethod", List.class, List.class, List.class,
585 List.class, List.class, List.class, List.class, List[].class, List[].class,
586 List[].class, List[].class, List[].class, List[].class, List[].class);
587
588 Type[] types = method.getGenericParameterTypes();
589
590 Assert.assertFalse(TypeUtils.isArrayType(types[0]));
591 Assert.assertFalse(TypeUtils.isArrayType(types[1]));
592 Assert.assertFalse(TypeUtils.isArrayType(types[2]));
593 Assert.assertFalse(TypeUtils.isArrayType(types[3]));
594 Assert.assertFalse(TypeUtils.isArrayType(types[4]));
595 Assert.assertFalse(TypeUtils.isArrayType(types[5]));
596 Assert.assertFalse(TypeUtils.isArrayType(types[6]));
597 Assert.assertTrue(TypeUtils.isArrayType(types[7]));
598 Assert.assertTrue(TypeUtils.isArrayType(types[8]));
599 Assert.assertTrue(TypeUtils.isArrayType(types[9]));
600 Assert.assertTrue(TypeUtils.isArrayType(types[10]));
601 Assert.assertTrue(TypeUtils.isArrayType(types[11]));
602 Assert.assertTrue(TypeUtils.isArrayType(types[12]));
603 Assert.assertTrue(TypeUtils.isArrayType(types[13]));
604 }
605
606 @Test
607 public void testGetPrimitiveArrayComponentType() throws Exception {
608 Assert.assertEquals(boolean.class, TypeUtils.getArrayComponentType(boolean[].class));
609 Assert.assertEquals(byte.class, TypeUtils.getArrayComponentType(byte[].class));
610 Assert.assertEquals(short.class, TypeUtils.getArrayComponentType(short[].class));
611 Assert.assertEquals(int.class, TypeUtils.getArrayComponentType(int[].class));
612 Assert.assertEquals(char.class, TypeUtils.getArrayComponentType(char[].class));
613 Assert.assertEquals(long.class, TypeUtils.getArrayComponentType(long[].class));
614 Assert.assertEquals(float.class, TypeUtils.getArrayComponentType(float[].class));
615 Assert.assertEquals(double.class, TypeUtils.getArrayComponentType(double[].class));
616
617 Assert.assertNull(TypeUtils.getArrayComponentType(boolean.class));
618 Assert.assertNull(TypeUtils.getArrayComponentType(byte.class));
619 Assert.assertNull(TypeUtils.getArrayComponentType(short.class));
620 Assert.assertNull(TypeUtils.getArrayComponentType(int.class));
621 Assert.assertNull(TypeUtils.getArrayComponentType(char.class));
622 Assert.assertNull(TypeUtils.getArrayComponentType(long.class));
623 Assert.assertNull(TypeUtils.getArrayComponentType(float.class));
624 Assert.assertNull(TypeUtils.getArrayComponentType(double.class));
625 }
626
627 @Test
628 public void testGetArrayComponentType() throws Exception {
629 Method method = getClass().getMethod("dummyMethod", List.class, List.class, List.class,
630 List.class, List.class, List.class, List.class, List[].class, List[].class,
631 List[].class, List[].class, List[].class, List[].class, List[].class);
632
633 Type[] types = method.getGenericParameterTypes();
634
635 Assert.assertNull(TypeUtils.getArrayComponentType(types[0]));
636 Assert.assertNull(TypeUtils.getArrayComponentType(types[1]));
637 Assert.assertNull(TypeUtils.getArrayComponentType(types[2]));
638 Assert.assertNull(TypeUtils.getArrayComponentType(types[3]));
639 Assert.assertNull(TypeUtils.getArrayComponentType(types[4]));
640 Assert.assertNull(TypeUtils.getArrayComponentType(types[5]));
641 Assert.assertNull(TypeUtils.getArrayComponentType(types[6]));
642 Assert.assertEquals(types[0], TypeUtils.getArrayComponentType(types[7]));
643 Assert.assertEquals(types[1], TypeUtils.getArrayComponentType(types[8]));
644 Assert.assertEquals(types[2], TypeUtils.getArrayComponentType(types[9]));
645 Assert.assertEquals(types[3], TypeUtils.getArrayComponentType(types[10]));
646 Assert.assertEquals(types[4], TypeUtils.getArrayComponentType(types[11]));
647 Assert.assertEquals(types[5], TypeUtils.getArrayComponentType(types[12]));
648 Assert.assertEquals(types[6], TypeUtils.getArrayComponentType(types[13]));
649 }
650
651 public Iterable<? extends Map<Integer, ? extends Collection<?>>> iterable;
652
653 public static <G extends Comparable<G>> G stub() {
654 return null;
655 }
656
657 public static <G extends Comparable<? super G>> G stub2() {
658 return null;
659 }
660
661 public static <T extends Comparable<? extends T>> T stub3() {
662 return null;
663 }
664 }
665
666 class AAClass<T> {
667
668 public class BBClass<S> {
669 }
670 }
671
672 class AAAClass extends AAClass<String> {
673 public class BBBClass extends BBClass<String> {
674 }
675 }
676
677 @SuppressWarnings("rawtypes")
678 //raw types, where used, are used purposely
679 class AClass extends AAClass<String>.BBClass<Number> {
680
681 public AClass(AAClass<String> enclosingInstance) {
682 enclosingInstance.super();
683 }
684
685 public class BClass<T> {
686 }
687
688 public class CClass<T> extends BClass {
689 }
690
691 public class DClass<T> extends CClass<T> {
692 }
693
694 public class EClass<T> extends DClass {
695 }
696
697 public class FClass extends EClass<String> {
698 }
699
700 public class GClass<T extends BClass<? extends T> & AInterface<AInterface<? super T>>> {
701 }
702
703 public BClass<Number> bClass;
704
705 public CClass<? extends String> cClass;
706
707 public DClass<String> dClass;
708
709 public EClass<String> eClass;
710
711 public FClass fClass;
712
713 public GClass gClass;
714
715 public interface AInterface<T> {
716 }
717 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * @version $Id: Ambig.java 1088899 2011-04-05 05:31:27Z bayard $
20 */
21 public class Ambig implements Foo, Bar {
22 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * @version $Id: Bar.java 1088899 2011-04-05 05:31:27Z bayard $
20 */
21 public interface Bar {
22 public static final String VALUE = "bar";
23 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * @version $Id: Foo.java 1088899 2011-04-05 05:31:27Z bayard $
20 */
21 public interface Foo {
22 public static final String VALUE = "foo";
23 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * Class declaring a parameter variable.
20 * @version $Id: GenericParent.java 1088899 2011-04-05 05:31:27Z bayard $
21 */
22 public class GenericParent<T> {
23
24 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 import java.util.List;
19
20 /**
21 * Holds generic testbed types.
22 * @version $Id: GenericTypeHolder.java 1088899 2011-04-05 05:31:27Z bayard $
23 */
24 public class GenericTypeHolder {
25 public GenericParent<String> stringParent;
26 public GenericParent<Integer> integerParent;
27 public List<Foo> foos;
28 public GenericParent<Bar>[] barParents;
29 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * @version $Id: Parent.java 1088899 2011-04-05 05:31:27Z bayard $
20 */
21 class Parent implements Foo {
22 public String s = "s";
23 protected boolean b = false;
24 int i = 0;
25 @SuppressWarnings("unused")
26 private double d = 0.0;
27 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * @version $Id: PrivatelyShadowedChild.java 1088899 2011-04-05 05:31:27Z bayard $
20 */
21 @SuppressWarnings({ "unused", "hiding" }) // deliberate re-use of variable names
22 public class PrivatelyShadowedChild extends Parent {
23 private String s = "ss";
24 private boolean b = true;
25 private int i = 1;
26 private double d = 1.0;
27 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * @version $Id: PublicChild.java 1088899 2011-04-05 05:31:27Z bayard $
20 */
21 public class PublicChild extends Parent {
22 @SuppressWarnings("hiding") // deliberate reuse of variable name
23 static final String VALUE = "child";
24 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * @version $Id: PubliclyShadowedChild.java 1088899 2011-04-05 05:31:27Z bayard $
20 */
21 @SuppressWarnings("hiding") // deliberate re-use of variable names
22 public class PubliclyShadowedChild extends Parent {
23 public String s = "ss";
24 public boolean b = true;
25 public int i = 1;
26 public double d = 1.0;
27 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * @version $Id: StaticContainer.java 1088899 2011-04-05 05:31:27Z bayard $
20 */
21 public class StaticContainer {
22 public static final Object IMMUTABLE_PUBLIC = "public";
23 protected static final Object IMMUTABLE_PROTECTED = "protected";
24 static final Object IMMUTABLE_PACKAGE = "";
25 @SuppressWarnings("unused")
26 private static final Object IMMUTABLE_PRIVATE = "private";
27
28 public static Object mutablePublic;
29 protected static Object mutableProtected;
30 static Object mutablePackage;
31 private static Object mutablePrivate;
32
33 public static void reset() {
34 mutablePublic = null;
35 mutableProtected = null;
36 mutablePackage = null;
37 mutablePrivate = null;
38 }
39
40 public static Object getMutableProtected() {
41 return mutableProtected;
42 }
43
44 public static Object getMutablePackage() {
45 return mutablePackage;
46 }
47
48 public static Object getMutablePrivate() {
49 return mutablePrivate;
50 }
51 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * @version $Id: StaticContainerChild.java 1088899 2011-04-05 05:31:27Z bayard $
20 */
21 public class StaticContainerChild extends StaticContainer {
22
23 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.reflect.testbed;
17
18 /**
19 * {@link GenericParent} subclass that explicitly specifies <T> as {@link String}.
20 * @version $Id: StringParameterizedChild.java 1088899 2011-04-05 05:31:27Z bayard $
21 */
22 public class StringParameterizedChild extends GenericParent<String> {
23
24 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text;
18
19 import java.text.FieldPosition;
20 import java.text.Format;
21 import java.text.ParsePosition;
22 import java.text.SimpleDateFormat;
23 import java.util.Locale;
24
25 import junit.framework.TestCase;
26
27 /**
28 * Unit tests for {@link org.apache.commons.lang3.text.CompositeFormat}.
29 */
30 public class CompositeFormatTest extends TestCase {
31
32 /**
33 * Create a new test case with the specified name.
34 *
35 * @param name
36 * name
37 */
38 public CompositeFormatTest(String name) {
39 super(name);
40 }
41
42
43 /**
44 * Ensures that the parse/format separation is correctly maintained.
45 */
46 public void testCompositeFormat() {
47
48 Format parser = new Format() {
49 @Override
50 public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
51 throw new UnsupportedOperationException("Not implemented");
52 }
53
54 @Override
55 public Object parseObject(String source, ParsePosition pos) {
56 return null; // do nothing
57 }
58 };
59
60 Format formatter = new Format() {
61 @Override
62 public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
63 return null; // do nothing
64 }
65
66 @Override
67 public Object parseObject(String source, ParsePosition pos) {
68 throw new UnsupportedOperationException("Not implemented");
69 }
70 };
71
72 CompositeFormat composite = new CompositeFormat(parser, formatter);
73
74 composite.parseObject("", null);
75 composite.format(new Object(), new StringBuffer(), null);
76 assertEquals( "Parser get method incorrectly implemented", parser, composite.getParser() );
77 assertEquals( "Formatter get method incorrectly implemented", formatter, composite.getFormatter() );
78 }
79
80 public void testUsage() throws Exception {
81 Format f1 = new SimpleDateFormat("MMddyyyy", Locale.ENGLISH);
82 Format f2 = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH);
83 CompositeFormat c = new CompositeFormat(f1, f2);
84 String testString = "January 3, 2005";
85 assertEquals(testString, c.format(c.parseObject("01032005")));
86 assertEquals(testString, c.reformat("01032005"));
87 }
88
89 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import static org.apache.commons.lang3.JavaVersion.JAVA_1_4;
19
20 import java.text.ChoiceFormat;
21 import java.text.DateFormat;
22 import java.text.FieldPosition;
23 import java.text.Format;
24 import java.text.MessageFormat;
25 import java.text.NumberFormat;
26 import java.text.ParsePosition;
27 import java.util.Arrays;
28 import java.util.Calendar;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.Locale;
33 import java.util.Map;
34
35 import junit.framework.TestCase;
36
37 import org.apache.commons.lang3.SystemUtils;
38
39 /**
40 * Test case for {@link ExtendedMessageFormat}.
41 *
42 * @since 2.4
43 * @version $Id: ExtendedMessageFormatTest.java 1153490 2011-08-03 13:53:35Z ggregory $
44 */
45 public class ExtendedMessageFormatTest extends TestCase {
46
47 private final Map<String, FormatFactory> registry = new HashMap<String, FormatFactory>();
48
49 /**
50 * Create a new test case.
51 *
52 * @param name The name of the test
53 */
54 public ExtendedMessageFormatTest(String name) {
55 super(name);
56 }
57
58 @Override
59 protected void setUp() throws Exception {
60 super.setUp();
61 registry.put("lower", new LowerCaseFormatFactory());
62 registry.put("upper", new UpperCaseFormatFactory());
63 }
64
65 /**
66 * Test extended formats.
67 */
68 public void testExtendedFormats() {
69 String pattern = "Lower: {0,lower} Upper: {1,upper}";
70 ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
71 assertPatternsEqual("TOPATTERN", pattern, emf.toPattern());
72 assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "bar"}));
73 assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"Foo", "Bar"}));
74 assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "BAR"}));
75 assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "bar"}));
76 assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "BAR"}));
77 }
78
79 /**
80 * Test Bug LANG-477 - out of memory error with escaped quote
81 */
82 public void testEscapedQuote_LANG_477() {
83 String pattern = "it''s a {0,lower} 'test'!";
84 ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
85 assertEquals("it's a dummy test!", emf.format(new Object[] {"DUMMY"}));
86 }
87
88 /**
89 * Test extended and built in formats.
90 */
91 public void testExtendedAndBuiltInFormats() {
92 Calendar cal = Calendar.getInstance();
93 cal.set(2007, Calendar.JANUARY, 23, 18, 33, 05);
94 Object[] args = new Object[] {"John Doe", cal.getTime(), Double.valueOf("12345.67")};
95 String builtinsPattern = "DOB: {1,date,short} Salary: {2,number,currency}";
96 String extendedPattern = "Name: {0,upper} ";
97 String pattern = extendedPattern + builtinsPattern;
98
99 HashSet<Locale> testLocales = new HashSet<Locale>();
100 testLocales.addAll(Arrays.asList(DateFormat.getAvailableLocales()));
101 testLocales.retainAll(Arrays.asList(NumberFormat.getAvailableLocales()));
102 testLocales.add(null);
103
104 for (Locale locale : testLocales) {
105 MessageFormat builtins = createMessageFormat(builtinsPattern, locale);
106 String expectedPattern = extendedPattern + builtins.toPattern();
107 DateFormat df = null;
108 NumberFormat nf = null;
109 ExtendedMessageFormat emf = null;
110 if (locale == null) {
111 df = DateFormat.getDateInstance(DateFormat.SHORT);
112 nf = NumberFormat.getCurrencyInstance();
113 emf = new ExtendedMessageFormat(pattern, registry);
114 } else {
115 df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
116 nf = NumberFormat.getCurrencyInstance(locale);
117 emf = new ExtendedMessageFormat(pattern, locale, registry);
118 }
119 StringBuffer expected = new StringBuffer();
120 expected.append("Name: ");
121 expected.append(args[0].toString().toUpperCase());
122 expected.append(" DOB: ");
123 expected.append(df.format(args[1]));
124 expected.append(" Salary: ");
125 expected.append(nf.format(args[2]));
126 assertPatternsEqual("pattern comparison for locale " + locale, expectedPattern, emf.toPattern());
127 assertEquals(String.valueOf(locale), expected.toString(), emf.format(args));
128 }
129 }
130
131 // /**
132 // * Test extended formats with choice format.
133 // *
134 // * NOTE: FAILING - currently sub-formats not supported
135 // */
136 // public void testExtendedWithChoiceFormat() {
137 // String pattern = "Choice: {0,choice,1.0#{1,lower}|2.0#{1,upper}}";
138 // ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
139 // assertPatterns(null, pattern, emf.toPattern());
140 // try {
141 // assertEquals("one", emf.format(new Object[] {Integer.valueOf(1), "ONE"}));
142 // assertEquals("TWO", emf.format(new Object[] {Integer.valueOf(2), "two"}));
143 // } catch (IllegalArgumentException e) {
144 // // currently sub-formats not supported
145 // }
146 // }
147
148 // /**
149 // * Test mixed extended and built-in formats with choice format.
150 // *
151 // * NOTE: FAILING - currently sub-formats not supported
152 // */
153 // public void testExtendedAndBuiltInWithChoiceFormat() {
154 // String pattern = "Choice: {0,choice,1.0#{0} {1,lower} {2,number}|2.0#{0} {1,upper} {2,number,currency}}";
155 // Object[] lowArgs = new Object[] {Integer.valueOf(1), "Low", Double.valueOf("1234.56")};
156 // Object[] highArgs = new Object[] {Integer.valueOf(2), "High", Double.valueOf("9876.54")};
157 // Locale[] availableLocales = ChoiceFormat.getAvailableLocales();
158 // Locale[] testLocales = new Locale[availableLocales.length + 1];
159 // testLocales[0] = null;
160 // System.arraycopy(availableLocales, 0, testLocales, 1, availableLocales.length);
161 // for (int i = 0; i < testLocales.length; i++) {
162 // NumberFormat nf = null;
163 // NumberFormat cf = null;
164 // ExtendedMessageFormat emf = null;
165 // if (testLocales[i] == null) {
166 // nf = NumberFormat.getNumberInstance();
167 // cf = NumberFormat.getCurrencyInstance();
168 // emf = new ExtendedMessageFormat(pattern, registry);
169 // } else {
170 // nf = NumberFormat.getNumberInstance(testLocales[i]);
171 // cf = NumberFormat.getCurrencyInstance(testLocales[i]);
172 // emf = new ExtendedMessageFormat(pattern, testLocales[i], registry);
173 // }
174 // assertPatterns(null, pattern, emf.toPattern());
175 // try {
176 // String lowExpected = lowArgs[0] + " low " + nf.format(lowArgs[2]);
177 // String highExpected = highArgs[0] + " HIGH " + cf.format(highArgs[2]);
178 // assertEquals(lowExpected, emf.format(lowArgs));
179 // assertEquals(highExpected, emf.format(highArgs));
180 // } catch (IllegalArgumentException e) {
181 // // currently sub-formats not supported
182 // }
183 // }
184 // }
185
186 /**
187 * Test the built in choice format.
188 */
189 public void testBuiltInChoiceFormat() {
190 Object[] values = new Number[] {Integer.valueOf(1), Double.valueOf("2.2"), Double.valueOf("1234.5")};
191 String choicePattern = null;
192 Locale[] availableLocales = ChoiceFormat.getAvailableLocales();
193
194 choicePattern = "{0,choice,1#One|2#Two|3#Many {0,number}}";
195 for (Object value : values) {
196 checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
197 }
198
199 choicePattern = "{0,choice,1#''One''|2#\"Two\"|3#''{Many}'' {0,number}}";
200 for (Object value : values) {
201 checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
202 }
203 }
204
205 /**
206 * Test the built in date/time formats
207 */
208 public void testBuiltInDateTimeFormat() {
209 Calendar cal = Calendar.getInstance();
210 cal.set(2007, Calendar.JANUARY, 23, 18, 33, 05);
211 Object[] args = new Object[] {cal.getTime()};
212 Locale[] availableLocales = DateFormat.getAvailableLocales();
213
214 checkBuiltInFormat("1: {0,date,short}", args, availableLocales);
215 checkBuiltInFormat("2: {0,date,medium}", args, availableLocales);
216 checkBuiltInFormat("3: {0,date,long}", args, availableLocales);
217 checkBuiltInFormat("4: {0,date,full}", args, availableLocales);
218 checkBuiltInFormat("5: {0,date,d MMM yy}", args, availableLocales);
219 checkBuiltInFormat("6: {0,time,short}", args, availableLocales);
220 checkBuiltInFormat("7: {0,time,medium}", args, availableLocales);
221 checkBuiltInFormat("8: {0,time,long}", args, availableLocales);
222 checkBuiltInFormat("9: {0,time,full}", args, availableLocales);
223 checkBuiltInFormat("10: {0,time,HH:mm}", args, availableLocales);
224 checkBuiltInFormat("11: {0,date}", args, availableLocales);
225 checkBuiltInFormat("12: {0,time}", args, availableLocales);
226 }
227
228 public void testOverriddenBuiltinFormat() {
229 Calendar cal = Calendar.getInstance();
230 cal.set(2007, Calendar.JANUARY, 23);
231 Object[] args = new Object[] {cal.getTime()};
232 Locale[] availableLocales = DateFormat.getAvailableLocales();
233 Map<String, ? extends FormatFactory> registry = Collections.singletonMap("date", new OverrideShortDateFormatFactory());
234
235 //check the non-overridden builtins:
236 checkBuiltInFormat("1: {0,date}", registry, args, availableLocales);
237 checkBuiltInFormat("2: {0,date,medium}", registry, args, availableLocales);
238 checkBuiltInFormat("3: {0,date,long}", registry, args, availableLocales);
239 checkBuiltInFormat("4: {0,date,full}", registry, args, availableLocales);
240 checkBuiltInFormat("5: {0,date,d MMM yy}", registry, args, availableLocales);
241
242 //check the overridden format:
243 for (int i = -1; i < availableLocales.length; i++) {
244 Locale locale = i < 0 ? null : availableLocales[i];
245 MessageFormat dateDefault = createMessageFormat("{0,date}", locale);
246 String pattern = "{0,date,short}";
247 ExtendedMessageFormat dateShort = new ExtendedMessageFormat(pattern, locale, registry);
248 assertEquals("overridden date,short format", dateDefault.format(args), dateShort.format(args));
249 assertEquals("overridden date,short pattern", pattern, dateShort.toPattern());
250 }
251 }
252
253 /**
254 * Test the built in number formats.
255 */
256 public void testBuiltInNumberFormat() {
257 Object[] args = new Object[] {Double.valueOf("6543.21")};
258 Locale[] availableLocales = NumberFormat.getAvailableLocales();
259 checkBuiltInFormat("1: {0,number}", args, availableLocales);
260 checkBuiltInFormat("2: {0,number,integer}", args, availableLocales);
261 checkBuiltInFormat("3: {0,number,currency}", args, availableLocales);
262 checkBuiltInFormat("4: {0,number,percent}", args, availableLocales);
263 checkBuiltInFormat("5: {0,number,00000.000}", args, availableLocales);
264 }
265
266 /**
267 * Test equals() and hashcode.
268 */
269 public void testEqualsHashcode() {
270 Map<String, ? extends FormatFactory> registry = Collections.singletonMap("testfmt", new LowerCaseFormatFactory());
271 Map<String, ? extends FormatFactory> otherRegitry = Collections.singletonMap("testfmt", new UpperCaseFormatFactory());
272
273 String pattern = "Pattern: {0,testfmt}";
274 ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, Locale.US, registry);
275
276 ExtendedMessageFormat other = null;
277
278 // Same object
279 assertTrue("same, equals()", emf.equals(emf));
280 assertTrue("same, hashcode()", emf.hashCode() == emf.hashCode());
281
282 // Equal Object
283 other = new ExtendedMessageFormat(pattern, Locale.US, registry);
284 assertTrue("equal, equals()", emf.equals(other));
285 assertTrue("equal, hashcode()", emf.hashCode() == other.hashCode());
286
287 // Different Class
288 other = new OtherExtendedMessageFormat(pattern, Locale.US, registry);
289 assertFalse("class, equals()", emf.equals(other));
290 assertTrue("class, hashcode()", emf.hashCode() == other.hashCode()); // same hashcode
291
292 // Different pattern
293 other = new ExtendedMessageFormat("X" + pattern, Locale.US, registry);
294 assertFalse("pattern, equals()", emf.equals(other));
295 assertFalse("pattern, hashcode()", emf.hashCode() == other.hashCode());
296
297 // Different registry
298 other = new ExtendedMessageFormat(pattern, Locale.US, otherRegitry);
299 assertFalse("registry, equals()", emf.equals(other));
300 assertFalse("registry, hashcode()", emf.hashCode() == other.hashCode());
301
302 // Different Locale
303 other = new ExtendedMessageFormat(pattern, Locale.FRANCE, registry);
304 assertFalse("locale, equals()", emf.equals(other));
305 assertTrue("locale, hashcode()", emf.hashCode() == other.hashCode()); // same hashcode
306 }
307
308 /**
309 * Test a built in format for the specified Locales, plus <code>null</code> Locale.
310 * @param pattern MessageFormat pattern
311 * @param args MessageFormat arguments
312 * @param locales to test
313 */
314 private void checkBuiltInFormat(String pattern, Object[] args, Locale[] locales) {
315 checkBuiltInFormat(pattern, null, args, locales);
316 }
317
318 /**
319 * Test a built in format for the specified Locales, plus <code>null</code> Locale.
320 * @param pattern MessageFormat pattern
321 * @param registry FormatFactory registry to use
322 * @param args MessageFormat arguments
323 * @param locales to test
324 */
325 private void checkBuiltInFormat(String pattern, Map<String, ?> registry, Object[] args, Locale[] locales) {
326 checkBuiltInFormat(pattern, registry, args, (Locale) null);
327 for (Locale locale : locales) {
328 checkBuiltInFormat(pattern, registry, args, locale);
329 }
330 }
331
332 /**
333 * Create an ExtendedMessageFormat for the specified pattern and locale and check the
334 * formated output matches the expected result for the parameters.
335 * @param pattern string
336 * @param registry map
337 * @param args Object[]
338 * @param locale Locale
339 */
340 private void checkBuiltInFormat(String pattern, Map<String, ?> registry, Object[] args, Locale locale) {
341 StringBuffer buffer = new StringBuffer();
342 buffer.append("Pattern=[");
343 buffer.append(pattern);
344 buffer.append("], locale=[");
345 buffer.append(locale);
346 buffer.append("]");
347 MessageFormat mf = createMessageFormat(pattern, locale);
348 // System.out.println(buffer + ", result=[" + mf.format(args) +"]");
349 ExtendedMessageFormat emf = null;
350 if (locale == null) {
351 emf = new ExtendedMessageFormat(pattern);
352 } else {
353 emf = new ExtendedMessageFormat(pattern, locale);
354 }
355 assertEquals("format " + buffer.toString(), mf.format(args), emf.format(args));
356 assertPatternsEqual("toPattern " + buffer.toString(), mf.toPattern(), emf.toPattern());
357 }
358
359 //can't trust what MessageFormat does with toPattern() pre 1.4:
360 private void assertPatternsEqual(String message, String expected, String actual) {
361 if (SystemUtils.isJavaVersionAtLeast(JAVA_1_4)) {
362 assertEquals(message, expected, actual);
363 }
364 }
365
366 /**
367 * Replace MessageFormat(String, Locale) constructor (not available until JDK 1.4).
368 * @param pattern string
369 * @param locale Locale
370 * @return MessageFormat
371 */
372 private MessageFormat createMessageFormat(String pattern, Locale locale) {
373 MessageFormat result = new MessageFormat(pattern);
374 if (locale != null) {
375 result.setLocale(locale);
376 result.applyPattern(pattern);
377 }
378 return result;
379 }
380
381 // ------------------------ Test Formats ------------------------
382
383 /**
384 * {@link Format} implementation which converts to lower case.
385 */
386 private static class LowerCaseFormat extends Format {
387 @Override
388 public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
389 return toAppendTo.append(((String)obj).toLowerCase());
390 }
391 @Override
392 public Object parseObject(String source, ParsePosition pos) {throw new UnsupportedOperationException();}
393 }
394
395 /**
396 * {@link Format} implementation which converts to upper case.
397 */
398 private static class UpperCaseFormat extends Format {
399 @Override
400 public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
401 return toAppendTo.append(((String)obj).toUpperCase());
402 }
403 @Override
404 public Object parseObject(String source, ParsePosition pos) {throw new UnsupportedOperationException();}
405 }
406
407
408 // ------------------------ Test Format Factories ---------------
409 /**
410 * {@link FormatFactory} implementation for lower case format.
411 */
412 private static class LowerCaseFormatFactory implements FormatFactory {
413 private static final Format LOWER_INSTANCE = new LowerCaseFormat();
414 public Format getFormat(String name, String arguments, Locale locale) {
415 return LOWER_INSTANCE;
416 }
417 }
418 /**
419 * {@link FormatFactory} implementation for upper case format.
420 */
421 private static class UpperCaseFormatFactory implements FormatFactory {
422 private static final Format UPPER_INSTANCE = new UpperCaseFormat();
423 public Format getFormat(String name, String arguments, Locale locale) {
424 return UPPER_INSTANCE;
425 }
426 }
427 /**
428 * {@link FormatFactory} implementation to override date format "short" to "default".
429 */
430 private static class OverrideShortDateFormatFactory implements FormatFactory {
431 public Format getFormat(String name, String arguments, Locale locale) {
432 return !"short".equals(arguments) ? null
433 : locale == null ? DateFormat
434 .getDateInstance(DateFormat.DEFAULT) : DateFormat
435 .getDateInstance(DateFormat.DEFAULT, locale);
436 }
437 }
438
439 /**
440 * Alternative ExtendedMessageFormat impl.
441 */
442 private static class OtherExtendedMessageFormat extends ExtendedMessageFormat {
443 public OtherExtendedMessageFormat(String pattern, Locale locale,
444 Map<String, ? extends FormatFactory> registry) {
445 super(pattern, locale, registry);
446 }
447
448 }
449
450 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import static java.util.FormattableFlags.LEFT_JUSTIFY;
19 import static org.junit.Assert.assertEquals;
20
21 import java.util.Formatter;
22
23 import org.junit.Test;
24
25 /**
26 * Unit tests {@link FormattableUtils}.
27 *
28 * @version $Id: FormattableUtilsTest.java 1127546 2011-05-25 14:44:04Z scolebourne $
29 */
30 public class FormattableUtilsTest {
31
32 @Test
33 public void testDefaultAppend() {
34 assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1).toString());
35 assertEquals("fo", FormattableUtils.append("foo", new Formatter(), 0, -1, 2).toString());
36 assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1).toString());
37 assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1).toString());
38 assertEquals(" fo", FormattableUtils.append("foo", new Formatter(), 0, 3, 2).toString());
39 assertEquals(" fo", FormattableUtils.append("foo", new Formatter(), 0, 5, 2).toString());
40 assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1).toString());
41 assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1).toString());
42 assertEquals("fo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2).toString());
43 assertEquals("fo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2).toString());
44 }
45
46 @Test
47 public void testAlternatePadCharacter() {
48 char pad='_';
49 assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, pad).toString());
50 assertEquals("fo", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, pad).toString());
51 assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, pad).toString());
52 assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, pad).toString());
53 assertEquals("_fo", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, pad).toString());
54 assertEquals("___fo", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, pad).toString());
55 assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, pad).toString());
56 assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, pad).toString());
57 assertEquals("fo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, pad).toString());
58 assertEquals("fo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, pad).toString());
59 }
60
61 @Test
62 public void testEllipsis() {
63 assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, "*").toString());
64 assertEquals("f*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, "*").toString());
65 assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, "*").toString());
66 assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, "*").toString());
67 assertEquals(" f*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, "*").toString());
68 assertEquals(" f*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, "*").toString());
69 assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, "*").toString());
70 assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, "*").toString());
71 assertEquals("f* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, "*").toString());
72 assertEquals("f* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, "*").toString());
73
74 assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, "+*").toString());
75 assertEquals("+*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, "+*").toString());
76 assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, "+*").toString());
77 assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, "+*").toString());
78 assertEquals(" +*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, "+*").toString());
79 assertEquals(" +*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, "+*").toString());
80 assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, "+*").toString());
81 assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, "+*").toString());
82 assertEquals("+* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, "+*").toString());
83 assertEquals("+* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, "+*").toString());
84 }
85
86 @Test(expected=IllegalArgumentException.class)
87 public void testIllegalEllipsis() {
88 FormattableUtils.append("foo", new Formatter(), 0, -1, 1, "xx");
89 }
90
91 @Test
92 public void testAlternatePadCharAndEllipsis() {
93 assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, '_', "*").toString());
94 assertEquals("f*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, '_', "*").toString());
95 assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, '_', "*").toString());
96 assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, '_', "*").toString());
97 assertEquals("_f*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, '_', "*").toString());
98 assertEquals("___f*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, '_', "*").toString());
99 assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, '_', "*").toString());
100 assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, '_', "*").toString());
101 assertEquals("f*_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, '_', "*").toString());
102 assertEquals("f*___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, '_', "*").toString());
103
104 assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, '_', "+*").toString());
105 assertEquals("+*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, '_', "+*").toString());
106 assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, '_', "+*").toString());
107 assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, '_', "+*").toString());
108 assertEquals("_+*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, '_', "+*").toString());
109 assertEquals("___+*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, '_', "+*").toString());
110 assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, '_', "+*").toString());
111 assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, '_', "+*").toString());
112 assertEquals("+*_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, '_', "+*").toString());
113 assertEquals("+*___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, '_', "+*").toString());
114 }
115
116 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text;
18
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.Iterator;
23
24 import junit.framework.TestCase;
25
26 import org.apache.commons.lang3.SystemUtils;
27
28 /**
29 * Unit tests for {@link org.apache.commons.lang3.text.StrBuilder}.
30 *
31 * @version $Id: StrBuilderAppendInsertTest.java 1153484 2011-08-03 13:39:42Z ggregory $
32 */
33 public class StrBuilderAppendInsertTest extends TestCase {
34
35 /** The system line separator. */
36 private static final String SEP = SystemUtils.LINE_SEPARATOR;
37
38 /** Test subclass of Object, with a toString method. */
39 private static final Object FOO = new Object() {
40 @Override
41 public String toString() {
42 return "foo";
43 }
44 };
45
46 /**
47 * Create a new test case with the specified name.
48 *
49 * @param name the name
50 */
51 public StrBuilderAppendInsertTest(String name) {
52 super(name);
53 }
54
55 //-----------------------------------------------------------------------
56 public void testAppendNewLine() {
57 StrBuilder sb = new StrBuilder("---");
58 sb.appendNewLine().append("+++");
59 assertEquals("---" + SEP + "+++", sb.toString());
60
61 sb = new StrBuilder("---");
62 sb.setNewLineText("#").appendNewLine().setNewLineText(null).appendNewLine();
63 assertEquals("---#" + SEP, sb.toString());
64 }
65
66 //-----------------------------------------------------------------------
67 public void testAppendWithNullText() {
68 StrBuilder sb = new StrBuilder();
69 sb.setNullText("NULL");
70 assertEquals("", sb.toString());
71
72 sb.appendNull();
73 assertEquals("NULL", sb.toString());
74
75 sb.append((Object) null);
76 assertEquals("NULLNULL", sb.toString());
77
78 sb.append(FOO);
79 assertEquals("NULLNULLfoo", sb.toString());
80
81 sb.append((String) null);
82 assertEquals("NULLNULLfooNULL", sb.toString());
83
84 sb.append("");
85 assertEquals("NULLNULLfooNULL", sb.toString());
86
87 sb.append("bar");
88 assertEquals("NULLNULLfooNULLbar", sb.toString());
89
90 sb.append((StringBuffer) null);
91 assertEquals("NULLNULLfooNULLbarNULL", sb.toString());
92
93 sb.append(new StringBuffer("baz"));
94 assertEquals("NULLNULLfooNULLbarNULLbaz", sb.toString());
95 }
96
97 //-----------------------------------------------------------------------
98 public void testAppend_Object() {
99 StrBuilder sb = new StrBuilder();
100 sb.appendNull();
101 assertEquals("", sb.toString());
102
103 sb.append((Object) null);
104 assertEquals("", sb.toString());
105
106 sb.append(FOO);
107 assertEquals("foo", sb.toString());
108
109 sb.append((StringBuffer) null);
110 assertEquals("foo", sb.toString());
111
112 sb.append(new StringBuffer("baz"));
113 assertEquals("foobaz", sb.toString());
114
115 sb.append(new StrBuilder("yes"));
116 assertEquals("foobazyes", sb.toString());
117
118 sb.append((CharSequence) "Seq");
119 assertEquals("foobazyesSeq", sb.toString());
120 }
121
122 //-----------------------------------------------------------------------
123 public void testAppend_String() {
124 StrBuilder sb = new StrBuilder();
125 sb.setNullText("NULL").append((String) null);
126 assertEquals("NULL", sb.toString());
127
128 sb = new StrBuilder();
129 sb.append("foo");
130 assertEquals("foo", sb.toString());
131
132 sb.append("");
133 assertEquals("foo", sb.toString());
134
135 sb.append("bar");
136 assertEquals("foobar", sb.toString());
137 }
138
139 //-----------------------------------------------------------------------
140 public void testAppend_String_int_int() {
141 StrBuilder sb = new StrBuilder();
142 sb.setNullText("NULL").append((String) null, 0, 1);
143 assertEquals("NULL", sb.toString());
144
145 sb = new StrBuilder();
146 sb.append("foo", 0, 3);
147 assertEquals("foo", sb.toString());
148
149 try {
150 sb.append("bar", -1, 1);
151 fail("append(char[], -1,) expected IndexOutOfBoundsException");
152 } catch (IndexOutOfBoundsException e) {
153 // expected
154 }
155
156 try {
157 sb.append("bar", 3, 1);
158 fail("append(char[], 3,) expected IndexOutOfBoundsException");
159 } catch (IndexOutOfBoundsException e) {
160 // expected
161 }
162
163 try {
164 sb.append("bar", 1, -1);
165 fail("append(char[],, -1) expected IndexOutOfBoundsException");
166 } catch (IndexOutOfBoundsException e) {
167 // expected
168 }
169
170 try {
171 sb.append("bar", 1, 3);
172 fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
173 } catch (IndexOutOfBoundsException e) {
174 // expected
175 }
176
177 try {
178 sb.append("bar", -1, 3);
179 fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
180 } catch (IndexOutOfBoundsException e) {
181 // expected
182 }
183
184 try {
185 sb.append("bar", 4, 0);
186 fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
187 } catch (IndexOutOfBoundsException e) {
188 // expected
189 }
190
191 sb.append("bar", 3, 0);
192 assertEquals("foo", sb.toString());
193
194 sb.append("abcbardef", 3, 3);
195 assertEquals("foobar", sb.toString());
196
197 sb.append( (CharSequence)"abcbardef", 4, 3);
198 assertEquals("foobarard", sb.toString());
199 }
200
201 //-----------------------------------------------------------------------
202 public void testAppend_StringBuffer() {
203 StrBuilder sb = new StrBuilder();
204 sb.setNullText("NULL").append((StringBuffer) null);
205 assertEquals("NULL", sb.toString());
206
207 sb = new StrBuilder();
208 sb.append(new StringBuffer("foo"));
209 assertEquals("foo", sb.toString());
210
211 sb.append(new StringBuffer(""));
212 assertEquals("foo", sb.toString());
213
214 sb.append(new StringBuffer("bar"));
215 assertEquals("foobar", sb.toString());
216 }
217
218 //-----------------------------------------------------------------------
219 public void testAppend_StringBuffer_int_int() {
220 StrBuilder sb = new StrBuilder();
221 sb.setNullText("NULL").append((StringBuffer) null, 0, 1);
222 assertEquals("NULL", sb.toString());
223
224 sb = new StrBuilder();
225 sb.append(new StringBuffer("foo"), 0, 3);
226 assertEquals("foo", sb.toString());
227
228 try {
229 sb.append(new StringBuffer("bar"), -1, 1);
230 fail("append(char[], -1,) expected IndexOutOfBoundsException");
231 } catch (IndexOutOfBoundsException e) {
232 // expected
233 }
234
235 try {
236 sb.append(new StringBuffer("bar"), 3, 1);
237 fail("append(char[], 3,) expected IndexOutOfBoundsException");
238 } catch (IndexOutOfBoundsException e) {
239 // expected
240 }
241
242 try {
243 sb.append(new StringBuffer("bar"), 1, -1);
244 fail("append(char[],, -1) expected IndexOutOfBoundsException");
245 } catch (IndexOutOfBoundsException e) {
246 // expected
247 }
248
249 try {
250 sb.append(new StringBuffer("bar"), 1, 3);
251 fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
252 } catch (IndexOutOfBoundsException e) {
253 // expected
254 }
255
256 try {
257 sb.append(new StringBuffer("bar"), -1, 3);
258 fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
259 } catch (IndexOutOfBoundsException e) {
260 // expected
261 }
262
263 try {
264 sb.append(new StringBuffer("bar"), 4, 0);
265 fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
266 } catch (IndexOutOfBoundsException e) {
267 // expected
268 }
269
270 sb.append(new StringBuffer("bar"), 3, 0);
271 assertEquals("foo", sb.toString());
272
273 sb.append(new StringBuffer("abcbardef"), 3, 3);
274 assertEquals("foobar", sb.toString());
275 }
276
277 //-----------------------------------------------------------------------
278 public void testAppend_StrBuilder() {
279 StrBuilder sb = new StrBuilder();
280 sb.setNullText("NULL").append((StrBuilder) null);
281 assertEquals("NULL", sb.toString());
282
283 sb = new StrBuilder();
284 sb.append(new StrBuilder("foo"));
285 assertEquals("foo", sb.toString());
286
287 sb.append(new StrBuilder(""));
288 assertEquals("foo", sb.toString());
289
290 sb.append(new StrBuilder("bar"));
291 assertEquals("foobar", sb.toString());
292 }
293
294 //-----------------------------------------------------------------------
295 public void testAppend_StrBuilder_int_int() {
296 StrBuilder sb = new StrBuilder();
297 sb.setNullText("NULL").append((StrBuilder) null, 0, 1);
298 assertEquals("NULL", sb.toString());
299
300 sb = new StrBuilder();
301 sb.append(new StrBuilder("foo"), 0, 3);
302 assertEquals("foo", sb.toString());
303
304 try {
305 sb.append(new StrBuilder("bar"), -1, 1);
306 fail("append(char[], -1,) expected IndexOutOfBoundsException");
307 } catch (IndexOutOfBoundsException e) {
308 // expected
309 }
310
311 try {
312 sb.append(new StrBuilder("bar"), 3, 1);
313 fail("append(char[], 3,) expected IndexOutOfBoundsException");
314 } catch (IndexOutOfBoundsException e) {
315 // expected
316 }
317
318 try {
319 sb.append(new StrBuilder("bar"), 1, -1);
320 fail("append(char[],, -1) expected IndexOutOfBoundsException");
321 } catch (IndexOutOfBoundsException e) {
322 // expected
323 }
324
325 try {
326 sb.append(new StrBuilder("bar"), 1, 3);
327 fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
328 } catch (IndexOutOfBoundsException e) {
329 // expected
330 }
331
332 try {
333 sb.append(new StrBuilder("bar"), -1, 3);
334 fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
335 } catch (IndexOutOfBoundsException e) {
336 // expected
337 }
338
339 try {
340 sb.append(new StrBuilder("bar"), 4, 0);
341 fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
342 } catch (IndexOutOfBoundsException e) {
343 // expected
344 }
345
346 sb.append(new StrBuilder("bar"), 3, 0);
347 assertEquals("foo", sb.toString());
348
349 sb.append(new StrBuilder("abcbardef"), 3, 3);
350 assertEquals("foobar", sb.toString());
351 }
352
353 //-----------------------------------------------------------------------
354 public void testAppend_CharArray() {
355 StrBuilder sb = new StrBuilder();
356 sb.setNullText("NULL").append((char[]) null);
357 assertEquals("NULL", sb.toString());
358
359 sb = new StrBuilder();
360 sb.append(new char[0]);
361 assertEquals("", sb.toString());
362
363 sb.append(new char[]{'f', 'o', 'o'});
364 assertEquals("foo", sb.toString());
365 }
366
367 //-----------------------------------------------------------------------
368 public void testAppend_CharArray_int_int() {
369 StrBuilder sb = new StrBuilder();
370 sb.setNullText("NULL").append((char[]) null, 0, 1);
371 assertEquals("NULL", sb.toString());
372
373 sb = new StrBuilder();
374 sb.append(new char[]{'f', 'o', 'o'}, 0, 3);
375 assertEquals("foo", sb.toString());
376
377 try {
378 sb.append(new char[]{'b', 'a', 'r'}, -1, 1);
379 fail("append(char[], -1,) expected IndexOutOfBoundsException");
380 } catch (IndexOutOfBoundsException e) {
381 // expected
382 }
383
384 try {
385 sb.append(new char[]{'b', 'a', 'r'}, 3, 1);
386 fail("append(char[], 3,) expected IndexOutOfBoundsException");
387 } catch (IndexOutOfBoundsException e) {
388 // expected
389 }
390
391 try {
392 sb.append(new char[]{'b', 'a', 'r'}, 1, -1);
393 fail("append(char[],, -1) expected IndexOutOfBoundsException");
394 } catch (IndexOutOfBoundsException e) {
395 // expected
396 }
397
398 try {
399 sb.append(new char[]{'b', 'a', 'r'}, 1, 3);
400 fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
401 } catch (IndexOutOfBoundsException e) {
402 // expected
403 }
404
405 try {
406 sb.append(new char[]{'b', 'a', 'r'}, -1, 3);
407 fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
408 } catch (IndexOutOfBoundsException e) {
409 // expected
410 }
411
412 try {
413 sb.append(new char[]{'b', 'a', 'r'}, 4, 0);
414 fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
415 } catch (IndexOutOfBoundsException e) {
416 // expected
417 }
418
419 sb.append(new char[]{'b', 'a', 'r'}, 3, 0);
420 assertEquals("foo", sb.toString());
421
422 sb.append(new char[]{'a', 'b', 'c', 'b', 'a', 'r', 'd', 'e', 'f'}, 3, 3);
423 assertEquals("foobar", sb.toString());
424 }
425
426 //-----------------------------------------------------------------------
427 public void testAppend_Boolean() {
428 StrBuilder sb = new StrBuilder();
429 sb.append(true);
430 assertEquals("true", sb.toString());
431
432 sb.append(false);
433 assertEquals("truefalse", sb.toString());
434
435 sb.append('!');
436 assertEquals("truefalse!", sb.toString());
437 }
438
439 //-----------------------------------------------------------------------
440 public void testAppend_PrimitiveNumber() {
441 StrBuilder sb = new StrBuilder();
442 sb.append(0);
443 assertEquals("0", sb.toString());
444
445 sb.append(1L);
446 assertEquals("01", sb.toString());
447
448 sb.append(2.3f);
449 assertEquals("012.3", sb.toString());
450
451 sb.append(4.5d);
452 assertEquals("012.34.5", sb.toString());
453 }
454
455 //-----------------------------------------------------------------------
456 public void testAppendln_Object() {
457 StrBuilder sb = new StrBuilder();
458 sb.appendln((Object) null);
459 assertEquals("" + SEP, sb.toString());
460
461 sb.appendln(FOO);
462 assertEquals(SEP + "foo" + SEP, sb.toString());
463
464 sb.appendln(Integer.valueOf(6));
465 assertEquals(SEP + "foo" + SEP + "6" + SEP, sb.toString());
466 }
467
468 //-----------------------------------------------------------------------
469 public void testAppendln_String() {
470 final int[] count = new int[2];
471 StrBuilder sb = new StrBuilder() {
472 @Override
473 public StrBuilder append(String str) {
474 count[0]++;
475 return super.append(str);
476 }
477 @Override
478 public StrBuilder appendNewLine() {
479 count[1]++;
480 return super.appendNewLine();
481 }
482 };
483 sb.appendln("foo");
484 assertEquals("foo" + SEP, sb.toString());
485 assertEquals(2, count[0]); // appendNewLine() calls append(String)
486 assertEquals(1, count[1]);
487 }
488
489 //-----------------------------------------------------------------------
490 public void testAppendln_String_int_int() {
491 final int[] count = new int[2];
492 StrBuilder sb = new StrBuilder() {
493 @Override
494 public StrBuilder append(String str, int startIndex, int length) {
495 count[0]++;
496 return super.append(str, startIndex, length);
497 }
498 @Override
499 public StrBuilder appendNewLine() {
500 count[1]++;
501 return super.appendNewLine();
502 }
503 };
504 sb.appendln("foo", 0, 3);
505 assertEquals("foo" + SEP, sb.toString());
506 assertEquals(1, count[0]);
507 assertEquals(1, count[1]);
508 }
509
510 //-----------------------------------------------------------------------
511 public void testAppendln_StringBuffer() {
512 final int[] count = new int[2];
513 StrBuilder sb = new StrBuilder() {
514 @Override
515 public StrBuilder append(StringBuffer str) {
516 count[0]++;
517 return super.append(str);
518 }
519 @Override
520 public StrBuilder appendNewLine() {
521 count[1]++;
522 return super.appendNewLine();
523 }
524 };
525 sb.appendln(new StringBuffer("foo"));
526 assertEquals("foo" + SEP, sb.toString());
527 assertEquals(1, count[0]);
528 assertEquals(1, count[1]);
529 }
530
531 //-----------------------------------------------------------------------
532 public void testAppendln_StringBuffer_int_int() {
533 final int[] count = new int[2];
534 StrBuilder sb = new StrBuilder() {
535 @Override
536 public StrBuilder append(StringBuffer str, int startIndex, int length) {
537 count[0]++;
538 return super.append(str, startIndex, length);
539 }
540 @Override
541 public StrBuilder appendNewLine() {
542 count[1]++;
543 return super.appendNewLine();
544 }
545 };
546 sb.appendln(new StringBuffer("foo"), 0, 3);
547 assertEquals("foo" + SEP, sb.toString());
548 assertEquals(1, count[0]);
549 assertEquals(1, count[1]);
550 }
551
552 //-----------------------------------------------------------------------
553 public void testAppendln_StrBuilder() {
554 final int[] count = new int[2];
555 StrBuilder sb = new StrBuilder() {
556 @Override
557 public StrBuilder append(StrBuilder str) {
558 count[0]++;
559 return super.append(str);
560 }
561 @Override
562 public StrBuilder appendNewLine() {
563 count[1]++;
564 return super.appendNewLine();
565 }
566 };
567 sb.appendln(new StrBuilder("foo"));
568 assertEquals("foo" + SEP, sb.toString());
569 assertEquals(1, count[0]);
570 assertEquals(1, count[1]);
571 }
572
573 //-----------------------------------------------------------------------
574 public void testAppendln_StrBuilder_int_int() {
575 final int[] count = new int[2];
576 StrBuilder sb = new StrBuilder() {
577 @Override
578 public StrBuilder append(StrBuilder str, int startIndex, int length) {
579 count[0]++;
580 return super.append(str, startIndex, length);
581 }
582 @Override
583 public StrBuilder appendNewLine() {
584 count[1]++;
585 return super.appendNewLine();
586 }
587 };
588 sb.appendln(new StrBuilder("foo"), 0, 3);
589 assertEquals("foo" + SEP, sb.toString());
590 assertEquals(1, count[0]);
591 assertEquals(1, count[1]);
592 }
593
594 //-----------------------------------------------------------------------
595 public void testAppendln_CharArray() {
596 final int[] count = new int[2];
597 StrBuilder sb = new StrBuilder() {
598 @Override
599 public StrBuilder append(char[] str) {
600 count[0]++;
601 return super.append(str);
602 }
603 @Override
604 public StrBuilder appendNewLine() {
605 count[1]++;
606 return super.appendNewLine();
607 }
608 };
609 sb.appendln("foo".toCharArray());
610 assertEquals("foo" + SEP, sb.toString());
611 assertEquals(1, count[0]);
612 assertEquals(1, count[1]);
613 }
614
615 //-----------------------------------------------------------------------
616 public void testAppendln_CharArray_int_int() {
617 final int[] count = new int[2];
618 StrBuilder sb = new StrBuilder() {
619 @Override
620 public StrBuilder append(char[] str, int startIndex, int length) {
621 count[0]++;
622 return super.append(str, startIndex, length);
623 }
624 @Override
625 public StrBuilder appendNewLine() {
626 count[1]++;
627 return super.appendNewLine();
628 }
629 };
630 sb.appendln("foo".toCharArray(), 0, 3);
631 assertEquals("foo" + SEP, sb.toString());
632 assertEquals(1, count[0]);
633 assertEquals(1, count[1]);
634 }
635
636 //-----------------------------------------------------------------------
637 public void testAppendln_Boolean() {
638 StrBuilder sb = new StrBuilder();
639 sb.appendln(true);
640 assertEquals("true" + SEP, sb.toString());
641
642 sb.clear();
643 sb.appendln(false);
644 assertEquals("false" + SEP, sb.toString());
645 }
646
647 //-----------------------------------------------------------------------
648 public void testAppendln_PrimitiveNumber() {
649 StrBuilder sb = new StrBuilder();
650 sb.appendln(0);
651 assertEquals("0" + SEP, sb.toString());
652
653 sb.clear();
654 sb.appendln(1L);
655 assertEquals("1" + SEP, sb.toString());
656
657 sb.clear();
658 sb.appendln(2.3f);
659 assertEquals("2.3" + SEP, sb.toString());
660
661 sb.clear();
662 sb.appendln(4.5d);
663 assertEquals("4.5" + SEP, sb.toString());
664 }
665
666 //-----------------------------------------------------------------------
667 public void testAppendPadding() {
668 StrBuilder sb = new StrBuilder();
669 sb.append("foo");
670 assertEquals("foo", sb.toString());
671
672 sb.appendPadding(-1, '-');
673 assertEquals("foo", sb.toString());
674
675 sb.appendPadding(0, '-');
676 assertEquals("foo", sb.toString());
677
678 sb.appendPadding(1, '-');
679 assertEquals("foo-", sb.toString());
680
681 sb.appendPadding(16, '-');
682 assertEquals(20, sb.length());
683 // 12345678901234567890
684 assertEquals("foo-----------------", sb.toString());
685 }
686
687 //-----------------------------------------------------------------------
688 public void testAppendFixedWidthPadLeft() {
689 StrBuilder sb = new StrBuilder();
690 sb.appendFixedWidthPadLeft("foo", -1, '-');
691 assertEquals("", sb.toString());
692
693 sb.clear();
694 sb.appendFixedWidthPadLeft("foo", 0, '-');
695 assertEquals("", sb.toString());
696
697 sb.clear();
698 sb.appendFixedWidthPadLeft("foo", 1, '-');
699 assertEquals("o", sb.toString());
700
701 sb.clear();
702 sb.appendFixedWidthPadLeft("foo", 2, '-');
703 assertEquals("oo", sb.toString());
704
705 sb.clear();
706 sb.appendFixedWidthPadLeft("foo", 3, '-');
707 assertEquals("foo", sb.toString());
708
709 sb.clear();
710 sb.appendFixedWidthPadLeft("foo", 4, '-');
711 assertEquals("-foo", sb.toString());
712
713 sb.clear();
714 sb.appendFixedWidthPadLeft("foo", 10, '-');
715 assertEquals(10, sb.length());
716 // 1234567890
717 assertEquals("-------foo", sb.toString());
718
719 sb.clear();
720 sb.setNullText("null");
721 sb.appendFixedWidthPadLeft(null, 5, '-');
722 assertEquals("-null", sb.toString());
723 }
724
725 //-----------------------------------------------------------------------
726 public void testAppendFixedWidthPadLeft_int() {
727 StrBuilder sb = new StrBuilder();
728 sb.appendFixedWidthPadLeft(123, -1, '-');
729 assertEquals("", sb.toString());
730
731 sb.clear();
732 sb.appendFixedWidthPadLeft(123, 0, '-');
733 assertEquals("", sb.toString());
734
735 sb.clear();
736 sb.appendFixedWidthPadLeft(123, 1, '-');
737 assertEquals("3", sb.toString());
738
739 sb.clear();
740 sb.appendFixedWidthPadLeft(123, 2, '-');
741 assertEquals("23", sb.toString());
742
743 sb.clear();
744 sb.appendFixedWidthPadLeft(123, 3, '-');
745 assertEquals("123", sb.toString());
746
747 sb.clear();
748 sb.appendFixedWidthPadLeft(123, 4, '-');
749 assertEquals("-123", sb.toString());
750
751 sb.clear();
752 sb.appendFixedWidthPadLeft(123, 10, '-');
753 assertEquals(10, sb.length());
754 // 1234567890
755 assertEquals("-------123", sb.toString());
756 }
757
758 //-----------------------------------------------------------------------
759 public void testAppendFixedWidthPadRight() {
760 StrBuilder sb = new StrBuilder();
761 sb.appendFixedWidthPadRight("foo", -1, '-');
762 assertEquals("", sb.toString());
763
764 sb.clear();
765 sb.appendFixedWidthPadRight("foo", 0, '-');
766 assertEquals("", sb.toString());
767
768 sb.clear();
769 sb.appendFixedWidthPadRight("foo", 1, '-');
770 assertEquals("f", sb.toString());
771
772 sb.clear();
773 sb.appendFixedWidthPadRight("foo", 2, '-');
774 assertEquals("fo", sb.toString());
775
776 sb.clear();
777 sb.appendFixedWidthPadRight("foo", 3, '-');
778 assertEquals("foo", sb.toString());
779
780 sb.clear();
781 sb.appendFixedWidthPadRight("foo", 4, '-');
782 assertEquals("foo-", sb.toString());
783
784 sb.clear();
785 sb.appendFixedWidthPadRight("foo", 10, '-');
786 assertEquals(10, sb.length());
787 // 1234567890
788 assertEquals("foo-------", sb.toString());
789
790 sb.clear();
791 sb.setNullText("null");
792 sb.appendFixedWidthPadRight(null, 5, '-');
793 assertEquals("null-", sb.toString());
794 }
795
796 // See: http://issues.apache.org/jira/browse/LANG-299
797 public void testLang299() {
798 StrBuilder sb = new StrBuilder(1);
799 sb.appendFixedWidthPadRight("foo", 1, '-');
800 assertEquals("f", sb.toString());
801 }
802
803 //-----------------------------------------------------------------------
804 public void testAppendFixedWidthPadRight_int() {
805 StrBuilder sb = new StrBuilder();
806 sb.appendFixedWidthPadRight(123, -1, '-');
807 assertEquals("", sb.toString());
808
809 sb.clear();
810 sb.appendFixedWidthPadRight(123, 0, '-');
811 assertEquals("", sb.toString());
812
813 sb.clear();
814 sb.appendFixedWidthPadRight(123, 1, '-');
815 assertEquals("1", sb.toString());
816
817 sb.clear();
818 sb.appendFixedWidthPadRight(123, 2, '-');
819 assertEquals("12", sb.toString());
820
821 sb.clear();
822 sb.appendFixedWidthPadRight(123, 3, '-');
823 assertEquals("123", sb.toString());
824
825 sb.clear();
826 sb.appendFixedWidthPadRight(123, 4, '-');
827 assertEquals("123-", sb.toString());
828
829 sb.clear();
830 sb.appendFixedWidthPadRight(123, 10, '-');
831 assertEquals(10, sb.length());
832 // 1234567890
833 assertEquals("123-------", sb.toString());
834 }
835
836 //-----------------------------------------------------------------------
837 public void testAppendAll_Array() {
838 StrBuilder sb = new StrBuilder();
839 sb.appendAll((Object[]) null);
840 assertEquals("", sb.toString());
841
842 sb.clear();
843 sb.appendAll(new Object[0]);
844 assertEquals("", sb.toString());
845
846 sb.clear();
847 sb.appendAll(new Object[]{"foo", "bar", "baz"});
848 assertEquals("foobarbaz", sb.toString());
849 }
850
851 //-----------------------------------------------------------------------
852 public void testAppendAll_Collection() {
853 StrBuilder sb = new StrBuilder();
854 sb.appendAll((Collection<?>) null);
855 assertEquals("", sb.toString());
856
857 sb.clear();
858 sb.appendAll(Collections.EMPTY_LIST);
859 assertEquals("", sb.toString());
860
861 sb.clear();
862 sb.appendAll(Arrays.asList(new Object[]{"foo", "bar", "baz"}));
863 assertEquals("foobarbaz", sb.toString());
864 }
865
866 //-----------------------------------------------------------------------
867 public void testAppendAll_Iterator() {
868 StrBuilder sb = new StrBuilder();
869 sb.appendAll((Iterator<?>) null);
870 assertEquals("", sb.toString());
871
872 sb.clear();
873 sb.appendAll(Collections.EMPTY_LIST.iterator());
874 assertEquals("", sb.toString());
875
876 sb.clear();
877 sb.appendAll(Arrays.asList(new Object[]{"foo", "bar", "baz"}).iterator());
878 assertEquals("foobarbaz", sb.toString());
879 }
880
881 //-----------------------------------------------------------------------
882 public void testAppendWithSeparators_Array() {
883 StrBuilder sb = new StrBuilder();
884 sb.appendWithSeparators((Object[]) null, ",");
885 assertEquals("", sb.toString());
886
887 sb.clear();
888 sb.appendWithSeparators(new Object[0], ",");
889 assertEquals("", sb.toString());
890
891 sb.clear();
892 sb.appendWithSeparators(new Object[]{"foo", "bar", "baz"}, ",");
893 assertEquals("foo,bar,baz", sb.toString());
894
895 sb.clear();
896 sb.appendWithSeparators(new Object[]{"foo", "bar", "baz"}, null);
897 assertEquals("foobarbaz", sb.toString());
898
899 sb.clear();
900 sb.appendWithSeparators(new Object[]{"foo", null, "baz"}, ",");
901 assertEquals("foo,,baz", sb.toString());
902 }
903
904 //-----------------------------------------------------------------------
905 public void testAppendWithSeparators_Collection() {
906 StrBuilder sb = new StrBuilder();
907 sb.appendWithSeparators((Collection<?>) null, ",");
908 assertEquals("", sb.toString());
909
910 sb.clear();
911 sb.appendWithSeparators(Collections.EMPTY_LIST, ",");
912 assertEquals("", sb.toString());
913
914 sb.clear();
915 sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}), ",");
916 assertEquals("foo,bar,baz", sb.toString());
917
918 sb.clear();
919 sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}), null);
920 assertEquals("foobarbaz", sb.toString());
921
922 sb.clear();
923 sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, "baz"}), ",");
924 assertEquals("foo,,baz", sb.toString());
925 }
926
927 //-----------------------------------------------------------------------
928 public void testAppendWithSeparators_Iterator() {
929 StrBuilder sb = new StrBuilder();
930 sb.appendWithSeparators((Iterator<?>) null, ",");
931 assertEquals("", sb.toString());
932
933 sb.clear();
934 sb.appendWithSeparators(Collections.EMPTY_LIST.iterator(), ",");
935 assertEquals("", sb.toString());
936
937 sb.clear();
938 sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}).iterator(), ",");
939 assertEquals("foo,bar,baz", sb.toString());
940
941 sb.clear();
942 sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}).iterator(), null);
943 assertEquals("foobarbaz", sb.toString());
944
945 sb.clear();
946 sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, "baz"}).iterator(), ",");
947 assertEquals("foo,,baz", sb.toString());
948 }
949
950 //-----------------------------------------------------------------------
951 public void testAppendWithSeparatorsWithNullText() {
952 StrBuilder sb = new StrBuilder();
953 sb.setNullText("null");
954 sb.appendWithSeparators(new Object[]{"foo", null, "baz"}, ",");
955 assertEquals("foo,null,baz", sb.toString());
956
957 sb.clear();
958 sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, "baz"}), ",");
959 assertEquals("foo,null,baz", sb.toString());
960 }
961
962 //-----------------------------------------------------------------------
963 public void testAppendSeparator_String() {
964 StrBuilder sb = new StrBuilder();
965 sb.appendSeparator(","); // no effect
966 assertEquals("", sb.toString());
967 sb.append("foo");
968 assertEquals("foo", sb.toString());
969 sb.appendSeparator(",");
970 assertEquals("foo,", sb.toString());
971 }
972
973 //-----------------------------------------------------------------------
974 public void testAppendSeparator_String_String() {
975 StrBuilder sb = new StrBuilder();
976 final String startSeparator = "order by ";
977 final String standardSeparator = ",";
978 final String foo = "foo";
979 sb.appendSeparator(null, null);
980 assertEquals("", sb.toString());
981 sb.appendSeparator(standardSeparator, null);
982 assertEquals("", sb.toString());
983 sb.appendSeparator(standardSeparator, startSeparator);
984 assertEquals(startSeparator, sb.toString());
985 sb.appendSeparator(null, null);
986 assertEquals(startSeparator, sb.toString());
987 sb.appendSeparator(null, startSeparator);
988 assertEquals(startSeparator, sb.toString());
989 sb.append(foo);
990 assertEquals(startSeparator + foo, sb.toString());
991 sb.appendSeparator(standardSeparator, startSeparator);
992 assertEquals(startSeparator + foo + standardSeparator, sb.toString());
993 }
994
995 //-----------------------------------------------------------------------
996 public void testAppendSeparator_char() {
997 StrBuilder sb = new StrBuilder();
998 sb.appendSeparator(','); // no effect
999 assertEquals("", sb.toString());
1000 sb.append("foo");
1001 assertEquals("foo", sb.toString());
1002 sb.appendSeparator(',');
1003 assertEquals("foo,", sb.toString());
1004 }
1005 public void testAppendSeparator_char_char() {
1006 StrBuilder sb = new StrBuilder();
1007 final char startSeparator = ':';
1008 final char standardSeparator = ',';
1009 final String foo = "foo";
1010 sb.appendSeparator(standardSeparator, startSeparator); // no effect
1011 assertEquals(String.valueOf(startSeparator), sb.toString());
1012 sb.append(foo);
1013 assertEquals(String.valueOf(startSeparator) + foo, sb.toString());
1014 sb.appendSeparator(standardSeparator, startSeparator);
1015 assertEquals(String.valueOf(startSeparator) + foo + standardSeparator, sb.toString());
1016 }
1017
1018 //-----------------------------------------------------------------------
1019 public void testAppendSeparator_String_int() {
1020 StrBuilder sb = new StrBuilder();
1021 sb.appendSeparator(",", 0); // no effect
1022 assertEquals("", sb.toString());
1023 sb.append("foo");
1024 assertEquals("foo", sb.toString());
1025 sb.appendSeparator(",", 1);
1026 assertEquals("foo,", sb.toString());
1027
1028 sb.appendSeparator(",", -1); // no effect
1029 assertEquals("foo,", sb.toString());
1030 }
1031
1032 //-----------------------------------------------------------------------
1033 public void testAppendSeparator_char_int() {
1034 StrBuilder sb = new StrBuilder();
1035 sb.appendSeparator(',', 0); // no effect
1036 assertEquals("", sb.toString());
1037 sb.append("foo");
1038 assertEquals("foo", sb.toString());
1039 sb.appendSeparator(',', 1);
1040 assertEquals("foo,", sb.toString());
1041
1042 sb.appendSeparator(',', -1); // no effect
1043 assertEquals("foo,", sb.toString());
1044 }
1045
1046 //-----------------------------------------------------------------------
1047 public void testInsert() {
1048
1049 StrBuilder sb = new StrBuilder();
1050 sb.append("barbaz");
1051 assertEquals("barbaz", sb.toString());
1052
1053 try {
1054 sb.insert(-1, FOO);
1055 fail("insert(-1, Object) expected StringIndexOutOfBoundsException");
1056 } catch (IndexOutOfBoundsException e) {
1057 // expected
1058 }
1059
1060 try {
1061 sb.insert(7, FOO);
1062 fail("insert(7, Object) expected StringIndexOutOfBoundsException");
1063 } catch (IndexOutOfBoundsException e) {
1064 // expected
1065 }
1066
1067 sb.insert(0, (Object) null);
1068 assertEquals("barbaz", sb.toString());
1069
1070 sb.insert(0, FOO);
1071 assertEquals("foobarbaz", sb.toString());
1072
1073 sb.clear();
1074 sb.append("barbaz");
1075 assertEquals("barbaz", sb.toString());
1076
1077 try {
1078 sb.insert(-1, "foo");
1079 fail("insert(-1, String) expected StringIndexOutOfBoundsException");
1080 } catch (IndexOutOfBoundsException e) {
1081 // expected
1082 }
1083
1084 try {
1085 sb.insert(7, "foo");
1086 fail("insert(7, String) expected StringIndexOutOfBoundsException");
1087 } catch (IndexOutOfBoundsException e) {
1088 // expected
1089 }
1090
1091 sb.insert(0, (String) null);
1092 assertEquals("barbaz", sb.toString());
1093
1094 sb.insert(0, "foo");
1095 assertEquals("foobarbaz", sb.toString());
1096
1097 sb.clear();
1098 sb.append("barbaz");
1099 assertEquals("barbaz", sb.toString());
1100
1101 try {
1102 sb.insert(-1, new char[]{'f', 'o', 'o'});
1103 fail("insert(-1, char[]) expected StringIndexOutOfBoundsException");
1104 } catch (IndexOutOfBoundsException e) {
1105 // expected
1106 }
1107
1108 try {
1109 sb.insert(7, new char[]{'f', 'o', 'o'});
1110 fail("insert(7, char[]) expected StringIndexOutOfBoundsException");
1111 } catch (IndexOutOfBoundsException e) {
1112 // expected
1113 }
1114
1115 sb.insert(0, (char[]) null);
1116 assertEquals("barbaz", sb.toString());
1117
1118 sb.insert(0, new char[0]);
1119 assertEquals("barbaz", sb.toString());
1120
1121 sb.insert(0, new char[]{'f', 'o', 'o'});
1122 assertEquals("foobarbaz", sb.toString());
1123
1124 sb.clear();
1125 sb.append("barbaz");
1126 assertEquals("barbaz", sb.toString());
1127
1128 try {
1129 sb.insert(-1, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3);
1130 fail("insert(-1, char[], 3, 3) expected StringIndexOutOfBoundsException");
1131 } catch (IndexOutOfBoundsException e) {
1132 // expected
1133 }
1134
1135 try {
1136 sb.insert(7, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3);
1137 fail("insert(7, char[], 3, 3) expected StringIndexOutOfBoundsException");
1138 } catch (IndexOutOfBoundsException e) {
1139 // expected
1140 }
1141
1142 sb.insert(0, (char[]) null, 0, 0);
1143 assertEquals("barbaz", sb.toString());
1144
1145 sb.insert(0, new char[0], 0, 0);
1146 assertEquals("barbaz", sb.toString());
1147
1148 try {
1149 sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, -1, 3);
1150 fail("insert(0, char[], -1, 3) expected StringIndexOutOfBoundsException");
1151 } catch (IndexOutOfBoundsException e) {
1152 // expected
1153 }
1154
1155 try {
1156 sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 10, 3);
1157 fail("insert(0, char[], 10, 3) expected StringIndexOutOfBoundsException");
1158 } catch (IndexOutOfBoundsException e) {
1159 // expected
1160 }
1161
1162 try {
1163 sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, -1);
1164 fail("insert(0, char[], 0, -1) expected StringIndexOutOfBoundsException");
1165 } catch (IndexOutOfBoundsException e) {
1166 // expected
1167 }
1168
1169 try {
1170 sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, 10);
1171 fail("insert(0, char[], 0, 10) expected StringIndexOutOfBoundsException");
1172 } catch (IndexOutOfBoundsException e) {
1173 // expected
1174 }
1175
1176 sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, 0);
1177 assertEquals("barbaz", sb.toString());
1178
1179 sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3);
1180 assertEquals("foobarbaz", sb.toString());
1181
1182 sb.clear();
1183 sb.append("barbaz");
1184 assertEquals("barbaz", sb.toString());
1185
1186 try {
1187 sb.insert(-1, true);
1188 fail("insert(-1, boolean) expected StringIndexOutOfBoundsException");
1189 } catch (IndexOutOfBoundsException e) {
1190 // expected
1191 }
1192
1193 try {
1194 sb.insert(7, true);
1195 fail("insert(7, boolean) expected StringIndexOutOfBoundsException");
1196 } catch (IndexOutOfBoundsException e) {
1197 // expected
1198 }
1199
1200 sb.insert(0, true);
1201 assertEquals("truebarbaz", sb.toString());
1202
1203 sb.insert(0, false);
1204 assertEquals("falsetruebarbaz", sb.toString());
1205
1206 sb.clear();
1207 sb.append("barbaz");
1208 assertEquals("barbaz", sb.toString());
1209
1210 try {
1211 sb.insert(-1, '!');
1212 fail("insert(-1, char) expected StringIndexOutOfBoundsException");
1213 } catch (IndexOutOfBoundsException e) {
1214 // expected
1215 }
1216
1217 try {
1218 sb.insert(7, '!');
1219 fail("insert(7, char) expected StringIndexOutOfBoundsException");
1220 } catch (IndexOutOfBoundsException e) {
1221 // expected
1222 }
1223
1224 sb.insert(0, '!');
1225 assertEquals("!barbaz", sb.toString());
1226
1227 sb.clear();
1228 sb.append("barbaz");
1229 assertEquals("barbaz", sb.toString());
1230
1231 try {
1232 sb.insert(-1, 0);
1233 fail("insert(-1, int) expected StringIndexOutOfBoundsException");
1234 } catch (IndexOutOfBoundsException e) {
1235 // expected
1236 }
1237
1238 try {
1239 sb.insert(7, 0);
1240 fail("insert(7, int) expected StringIndexOutOfBoundsException");
1241 } catch (IndexOutOfBoundsException e) {
1242 // expected
1243 }
1244
1245 sb.insert(0, '0');
1246 assertEquals("0barbaz", sb.toString());
1247
1248 sb.clear();
1249 sb.append("barbaz");
1250 assertEquals("barbaz", sb.toString());
1251
1252 try {
1253 sb.insert(-1, 1L);
1254 fail("insert(-1, long) expected StringIndexOutOfBoundsException");
1255 } catch (IndexOutOfBoundsException e) {
1256 // expected
1257 }
1258
1259 try {
1260 sb.insert(7, 1L);
1261 fail("insert(7, long) expected StringIndexOutOfBoundsException");
1262 } catch (IndexOutOfBoundsException e) {
1263 // expected
1264 }
1265
1266 sb.insert(0, 1L);
1267 assertEquals("1barbaz", sb.toString());
1268
1269 sb.clear();
1270 sb.append("barbaz");
1271 assertEquals("barbaz", sb.toString());
1272
1273 try {
1274 sb.insert(-1, 2.3F);
1275 fail("insert(-1, float) expected StringIndexOutOfBoundsException");
1276 } catch (IndexOutOfBoundsException e) {
1277 // expected
1278 }
1279
1280 try {
1281 sb.insert(7, 2.3F);
1282 fail("insert(7, float) expected StringIndexOutOfBoundsException");
1283 } catch (IndexOutOfBoundsException e) {
1284 // expected
1285 }
1286
1287 sb.insert(0, 2.3F);
1288 assertEquals("2.3barbaz", sb.toString());
1289
1290 sb.clear();
1291 sb.append("barbaz");
1292 assertEquals("barbaz", sb.toString());
1293
1294 try {
1295 sb.insert(-1, 4.5D);
1296 fail("insert(-1, double) expected StringIndexOutOfBoundsException");
1297 } catch (IndexOutOfBoundsException e) {
1298 // expected
1299 }
1300
1301 try {
1302 sb.insert(7, 4.5D);
1303 fail("insert(7, double) expected StringIndexOutOfBoundsException");
1304 } catch (IndexOutOfBoundsException e) {
1305 // expected
1306 }
1307
1308 sb.insert(0, 4.5D);
1309 assertEquals("4.5barbaz", sb.toString());
1310 }
1311
1312 //-----------------------------------------------------------------------
1313 public void testInsertWithNullText() {
1314 StrBuilder sb = new StrBuilder();
1315 sb.setNullText("null");
1316 sb.append("barbaz");
1317 assertEquals("barbaz", sb.toString());
1318
1319 try {
1320 sb.insert(-1, FOO);
1321 fail("insert(-1, Object) expected StringIndexOutOfBoundsException");
1322 } catch (IndexOutOfBoundsException e) {
1323 // expected
1324 }
1325
1326 try {
1327 sb.insert(7, FOO);
1328 fail("insert(7, Object) expected StringIndexOutOfBoundsException");
1329 } catch (IndexOutOfBoundsException e) {
1330 // expected
1331 }
1332
1333 sb.insert(0, (Object) null);
1334 assertEquals("nullbarbaz", sb.toString());
1335
1336 sb.insert(0, FOO);
1337 assertEquals("foonullbarbaz", sb.toString());
1338
1339 sb.clear();
1340 sb.append("barbaz");
1341 assertEquals("barbaz", sb.toString());
1342
1343 try {
1344 sb.insert(-1, "foo");
1345 fail("insert(-1, String) expected StringIndexOutOfBoundsException");
1346 } catch (IndexOutOfBoundsException e) {
1347 // expected
1348 }
1349
1350 try {
1351 sb.insert(7, "foo");
1352 fail("insert(7, String) expected StringIndexOutOfBoundsException");
1353 } catch (IndexOutOfBoundsException e) {
1354 // expected
1355 }
1356
1357 sb.insert(0, (String) null);
1358 assertEquals("nullbarbaz", sb.toString());
1359
1360 sb.insert(0, "foo");
1361 assertEquals("foonullbarbaz", sb.toString());
1362
1363 sb.insert(0, (char[]) null);
1364 assertEquals("nullfoonullbarbaz", sb.toString());
1365
1366 sb.insert(0, (char[]) null, 0, 0);
1367 assertEquals("nullnullfoonullbarbaz", sb.toString());
1368 }
1369 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text;
18
19 import java.io.Reader;
20 import java.io.Writer;
21 import java.util.Arrays;
22
23 import junit.framework.TestCase;
24
25 import org.apache.commons.lang3.ArrayUtils;
26
27 /**
28 * Unit tests for {@link org.apache.commons.lang3.text.StrBuilder}.
29 *
30 * @version $Id: StrBuilderTest.java 1153484 2011-08-03 13:39:42Z ggregory $
31 */
32 public class StrBuilderTest extends TestCase {
33
34 /**
35 * Create a new test case with the specified name.
36 *
37 * @param name
38 * name
39 */
40 public StrBuilderTest(String name) {
41 super(name);
42 }
43
44 //-----------------------------------------------------------------------
45 public void testConstructors() {
46 StrBuilder sb0 = new StrBuilder();
47 assertEquals(32, sb0.capacity());
48 assertEquals(0, sb0.length());
49 assertEquals(0, sb0.size());
50
51 StrBuilder sb1 = new StrBuilder(32);
52 assertEquals(32, sb1.capacity());
53 assertEquals(0, sb1.length());
54 assertEquals(0, sb1.size());
55
56 StrBuilder sb2 = new StrBuilder(0);
57 assertEquals(32, sb2.capacity());
58 assertEquals(0, sb2.length());
59 assertEquals(0, sb2.size());
60
61 StrBuilder sb3 = new StrBuilder(-1);
62 assertEquals(32, sb3.capacity());
63 assertEquals(0, sb3.length());
64 assertEquals(0, sb3.size());
65
66 StrBuilder sb4 = new StrBuilder(1);
67 assertEquals(1, sb4.capacity());
68 assertEquals(0, sb4.length());
69 assertEquals(0, sb4.size());
70
71 StrBuilder sb5 = new StrBuilder((String) null);
72 assertEquals(32, sb5.capacity());
73 assertEquals(0, sb5.length());
74 assertEquals(0, sb5.size());
75
76 StrBuilder sb6 = new StrBuilder("");
77 assertEquals(32, sb6.capacity());
78 assertEquals(0, sb6.length());
79 assertEquals(0, sb6.size());
80
81 StrBuilder sb7 = new StrBuilder("foo");
82 assertEquals(35, sb7.capacity());
83 assertEquals(3, sb7.length());
84 assertEquals(3, sb7.size());
85 }
86
87 //-----------------------------------------------------------------------
88 public void testChaining() {
89 StrBuilder sb = new StrBuilder();
90 assertSame(sb, sb.setNewLineText(null));
91 assertSame(sb, sb.setNullText(null));
92 assertSame(sb, sb.setLength(1));
93 assertSame(sb, sb.setCharAt(0, 'a'));
94 assertSame(sb, sb.ensureCapacity(0));
95 assertSame(sb, sb.minimizeCapacity());
96 assertSame(sb, sb.clear());
97 assertSame(sb, sb.reverse());
98 assertSame(sb, sb.trim());
99 }
100
101 //-----------------------------------------------------------------------
102 public void testGetSetNewLineText() {
103 StrBuilder sb = new StrBuilder();
104 assertEquals(null, sb.getNewLineText());
105
106 sb.setNewLineText("#");
107 assertEquals("#", sb.getNewLineText());
108
109 sb.setNewLineText("");
110 assertEquals("", sb.getNewLineText());
111
112 sb.setNewLineText((String) null);
113 assertEquals(null, sb.getNewLineText());
114 }
115
116 //-----------------------------------------------------------------------
117 public void testGetSetNullText() {
118 StrBuilder sb = new StrBuilder();
119 assertEquals(null, sb.getNullText());
120
121 sb.setNullText("null");
122 assertEquals("null", sb.getNullText());
123
124 sb.setNullText("");
125 assertEquals(null, sb.getNullText());
126
127 sb.setNullText("NULL");
128 assertEquals("NULL", sb.getNullText());
129
130 sb.setNullText((String) null);
131 assertEquals(null, sb.getNullText());
132 }
133
134 //-----------------------------------------------------------------------
135 public void testCapacityAndLength() {
136 StrBuilder sb = new StrBuilder();
137 assertEquals(32, sb.capacity());
138 assertEquals(0, sb.length());
139 assertEquals(0, sb.size());
140 assertTrue(sb.isEmpty());
141
142 sb.minimizeCapacity();
143 assertEquals(0, sb.capacity());
144 assertEquals(0, sb.length());
145 assertEquals(0, sb.size());
146 assertTrue(sb.isEmpty());
147
148 sb.ensureCapacity(32);
149 assertTrue(sb.capacity() >= 32);
150 assertEquals(0, sb.length());
151 assertEquals(0, sb.size());
152 assertTrue(sb.isEmpty());
153
154 sb.append("foo");
155 assertTrue(sb.capacity() >= 32);
156 assertEquals(3, sb.length());
157 assertEquals(3, sb.size());
158 assertTrue(sb.isEmpty() == false);
159
160 sb.clear();
161 assertTrue(sb.capacity() >= 32);
162 assertEquals(0, sb.length());
163 assertEquals(0, sb.size());
164 assertTrue(sb.isEmpty());
165
166 sb.append("123456789012345678901234567890123");
167 assertTrue(sb.capacity() > 32);
168 assertEquals(33, sb.length());
169 assertEquals(33, sb.size());
170 assertTrue(sb.isEmpty() == false);
171
172 sb.ensureCapacity(16);
173 assertTrue(sb.capacity() > 16);
174 assertEquals(33, sb.length());
175 assertEquals(33, sb.size());
176 assertTrue(sb.isEmpty() == false);
177
178 sb.minimizeCapacity();
179 assertEquals(33, sb.capacity());
180 assertEquals(33, sb.length());
181 assertEquals(33, sb.size());
182 assertTrue(sb.isEmpty() == false);
183
184 try {
185 sb.setLength(-1);
186 fail("setLength(-1) expected StringIndexOutOfBoundsException");
187 } catch (IndexOutOfBoundsException e) {
188 // expected
189 }
190
191 sb.setLength(33);
192 assertEquals(33, sb.capacity());
193 assertEquals(33, sb.length());
194 assertEquals(33, sb.size());
195 assertTrue(sb.isEmpty() == false);
196
197 sb.setLength(16);
198 assertTrue(sb.capacity() >= 16);
199 assertEquals(16, sb.length());
200 assertEquals(16, sb.size());
201 assertEquals("1234567890123456", sb.toString());
202 assertTrue(sb.isEmpty() == false);
203
204 sb.setLength(32);
205 assertTrue(sb.capacity() >= 32);
206 assertEquals(32, sb.length());
207 assertEquals(32, sb.size());
208 assertEquals("1234567890123456\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sb.toString());
209 assertTrue(sb.isEmpty() == false);
210
211 sb.setLength(0);
212 assertTrue(sb.capacity() >= 32);
213 assertEquals(0, sb.length());
214 assertEquals(0, sb.size());
215 assertTrue(sb.isEmpty());
216 }
217
218 //-----------------------------------------------------------------------
219 public void testLength() {
220 StrBuilder sb = new StrBuilder();
221 assertEquals(0, sb.length());
222
223 sb.append("Hello");
224 assertEquals(5, sb.length());
225 }
226
227 public void testSetLength() {
228 StrBuilder sb = new StrBuilder();
229 sb.append("Hello");
230 sb.setLength(2); // shorten
231 assertEquals("He", sb.toString());
232 sb.setLength(2); // no change
233 assertEquals("He", sb.toString());
234 sb.setLength(3); // lengthen
235 assertEquals("He\0", sb.toString());
236
237 try {
238 sb.setLength(-1);
239 fail("setLength(-1) expected StringIndexOutOfBoundsException");
240 } catch (IndexOutOfBoundsException e) {
241 // expected
242 }
243 }
244
245 //-----------------------------------------------------------------------
246 public void testCapacity() {
247 StrBuilder sb = new StrBuilder();
248 assertEquals(sb.buffer.length, sb.capacity());
249
250 sb.append("HelloWorldHelloWorldHelloWorldHelloWorld");
251 assertEquals(sb.buffer.length, sb.capacity());
252 }
253
254 public void testEnsureCapacity() {
255 StrBuilder sb = new StrBuilder();
256 sb.ensureCapacity(2);
257 assertEquals(true, sb.capacity() >= 2);
258
259 sb.ensureCapacity(-1);
260 assertEquals(true, sb.capacity() >= 0);
261
262 sb.append("HelloWorld");
263 sb.ensureCapacity(40);
264 assertEquals(true, sb.capacity() >= 40);
265 }
266
267 public void testMinimizeCapacity() {
268 StrBuilder sb = new StrBuilder();
269 sb.minimizeCapacity();
270 assertEquals(0, sb.capacity());
271
272 sb.append("HelloWorld");
273 sb.minimizeCapacity();
274 assertEquals(10, sb.capacity());
275 }
276
277 //-----------------------------------------------------------------------
278 public void testSize() {
279 StrBuilder sb = new StrBuilder();
280 assertEquals(0, sb.size());
281
282 sb.append("Hello");
283 assertEquals(5, sb.size());
284 }
285
286 public void testIsEmpty() {
287 StrBuilder sb = new StrBuilder();
288 assertEquals(true, sb.isEmpty());
289
290 sb.append("Hello");
291 assertEquals(false, sb.isEmpty());
292
293 sb.clear();
294 assertEquals(true, sb.isEmpty());
295 }
296
297 public void testClear() {
298 StrBuilder sb = new StrBuilder();
299 sb.append("Hello");
300 sb.clear();
301 assertEquals(0, sb.length());
302 assertEquals(true, sb.buffer.length >= 5);
303 }
304
305 //-----------------------------------------------------------------------
306 public void testCharAt() {
307 StrBuilder sb = new StrBuilder();
308 try {
309 sb.charAt(0);
310 fail("charAt(0) expected IndexOutOfBoundsException");
311 } catch (IndexOutOfBoundsException e) {
312 // expected
313 }
314 try {
315 sb.charAt(-1);
316 fail("charAt(-1) expected IndexOutOfBoundsException");
317 } catch (IndexOutOfBoundsException e) {
318 // expected
319 }
320 sb.append("foo");
321 assertEquals('f', sb.charAt(0));
322 assertEquals('o', sb.charAt(1));
323 assertEquals('o', sb.charAt(2));
324 try {
325 sb.charAt(-1);
326 fail("charAt(-1) expected IndexOutOfBoundsException");
327 } catch (IndexOutOfBoundsException e) {
328 // expected
329 }
330 try {
331 sb.charAt(3);
332 fail("charAt(3) expected IndexOutOfBoundsException");
333 } catch (IndexOutOfBoundsException e) {
334 // expected
335 }
336 }
337
338 //-----------------------------------------------------------------------
339 public void testSetCharAt() {
340 StrBuilder sb = new StrBuilder();
341 try {
342 sb.setCharAt(0, 'f');
343 fail("setCharAt(0,) expected IndexOutOfBoundsException");
344 } catch (IndexOutOfBoundsException e) {
345 // expected
346 }
347 try {
348 sb.setCharAt(-1, 'f');
349 fail("setCharAt(-1,) expected IndexOutOfBoundsException");
350 } catch (IndexOutOfBoundsException e) {
351 // expected
352 }
353 sb.append("foo");
354 sb.setCharAt(0, 'b');
355 sb.setCharAt(1, 'a');
356 sb.setCharAt(2, 'r');
357 try {
358 sb.setCharAt(3, '!');
359 fail("setCharAt(3,) expected IndexOutOfBoundsException");
360 } catch (IndexOutOfBoundsException e) {
361 // expected
362 }
363 assertEquals("bar", sb.toString());
364 }
365
366 //-----------------------------------------------------------------------
367 public void testDeleteCharAt() {
368 StrBuilder sb = new StrBuilder("abc");
369 sb.deleteCharAt(0);
370 assertEquals("bc", sb.toString());
371
372 try {
373 sb.deleteCharAt(1000);
374 fail("Expected IndexOutOfBoundsException");
375 } catch (IndexOutOfBoundsException e) {}
376 }
377
378 //-----------------------------------------------------------------------
379 public void testToCharArray() {
380 StrBuilder sb = new StrBuilder();
381 assertEquals(ArrayUtils.EMPTY_CHAR_ARRAY, sb.toCharArray());
382
383 char[] a = sb.toCharArray();
384 assertNotNull("toCharArray() result is null", a);
385 assertEquals("toCharArray() result is too large", 0, a.length);
386
387 sb.append("junit");
388 a = sb.toCharArray();
389 assertEquals("toCharArray() result incorrect length", 5, a.length);
390 assertTrue("toCharArray() result does not match", Arrays.equals("junit".toCharArray(), a));
391 }
392
393 public void testToCharArrayIntInt() {
394 StrBuilder sb = new StrBuilder();
395 assertEquals(ArrayUtils.EMPTY_CHAR_ARRAY, sb.toCharArray(0, 0));
396
397 sb.append("junit");
398 char[] a = sb.toCharArray(0, 20); // too large test
399 assertEquals("toCharArray(int,int) result incorrect length", 5, a.length);
400 assertTrue("toCharArray(int,int) result does not match", Arrays.equals("junit".toCharArray(), a));
401
402 a = sb.toCharArray(0, 4);
403 assertEquals("toCharArray(int,int) result incorrect length", 4, a.length);
404 assertTrue("toCharArray(int,int) result does not match", Arrays.equals("juni".toCharArray(), a));
405
406 a = sb.toCharArray(0, 4);
407 assertEquals("toCharArray(int,int) result incorrect length", 4, a.length);
408 assertTrue("toCharArray(int,int) result does not match", Arrays.equals("juni".toCharArray(), a));
409
410 a = sb.toCharArray(0, 1);
411 assertNotNull("toCharArray(int,int) result is null", a);
412
413 try {
414 sb.toCharArray(-1, 5);
415 fail("no string index out of bound on -1");
416 } catch (IndexOutOfBoundsException e) {
417 }
418
419 try {
420 sb.toCharArray(6, 5);
421 fail("no string index out of bound on -1");
422 } catch (IndexOutOfBoundsException e) {
423 }
424 }
425
426 public void testGetChars ( ) {
427 StrBuilder sb = new StrBuilder();
428
429 char[] input = new char[10];
430 char[] a = sb.getChars(input);
431 assertSame (input, a);
432 assertTrue(Arrays.equals(new char[10], a));
433
434 sb.append("junit");
435 a = sb.getChars(input);
436 assertSame(input, a);
437 assertTrue(Arrays.equals(new char[] {'j','u','n','i','t',0,0,0,0,0},a));
438
439 a = sb.getChars(null);
440 assertNotSame(input,a);
441 assertEquals(5,a.length);
442 assertTrue(Arrays.equals("junit".toCharArray(),a));
443
444 input = new char[5];
445 a = sb.getChars(input);
446 assertSame(input, a);
447
448 input = new char[4];
449 a = sb.getChars(input);
450 assertNotSame(input, a);
451 }
452
453 public void testGetCharsIntIntCharArrayInt( ) {
454 StrBuilder sb = new StrBuilder();
455
456 sb.append("junit");
457 char[] a = new char[5];
458 sb.getChars(0,5,a,0);
459 assertTrue(Arrays.equals(new char[] {'j','u','n','i','t'},a));
460
461 a = new char[5];
462 sb.getChars(0,2,a,3);
463 assertTrue(Arrays.equals(new char[] {0,0,0,'j','u'},a));
464
465 try {
466 sb.getChars(-1,0,a,0);
467 fail("no exception");
468 }
469 catch (IndexOutOfBoundsException e) {
470 }
471
472 try {
473 sb.getChars(0,-1,a,0);
474 fail("no exception");
475 }
476 catch (IndexOutOfBoundsException e) {
477 }
478
479 try {
480 sb.getChars(0,20,a,0);
481 fail("no exception");
482 }
483 catch (IndexOutOfBoundsException e) {
484 }
485
486 try {
487 sb.getChars(4,2,a,0);
488 fail("no exception");
489 }
490 catch (IndexOutOfBoundsException e) {
491 }
492 }
493
494 //-----------------------------------------------------------------------
495 public void testDeleteIntInt() {
496 StrBuilder sb = new StrBuilder("abc");
497 sb.delete(0, 1);
498 assertEquals("bc", sb.toString());
499 sb.delete(1, 2);
500 assertEquals("b", sb.toString());
501 sb.delete(0, 1);
502 assertEquals("", sb.toString());
503 sb.delete(0, 1000);
504 assertEquals("", sb.toString());
505
506 try {
507 sb.delete(1, 2);
508 fail("Expected IndexOutOfBoundsException");
509 } catch (IndexOutOfBoundsException e) {}
510 try {
511 sb.delete(-1, 1);
512 fail("Expected IndexOutOfBoundsException");
513 } catch (IndexOutOfBoundsException e) {}
514
515 sb = new StrBuilder("anything");
516 try {
517 sb.delete(2, 1);
518 fail("Expected IndexOutOfBoundsException");
519 } catch (IndexOutOfBoundsException e) {}
520 }
521
522 //-----------------------------------------------------------------------
523 public void testDeleteAll_char() {
524 StrBuilder sb = new StrBuilder("abcbccba");
525 sb.deleteAll('X');
526 assertEquals("abcbccba", sb.toString());
527 sb.deleteAll('a');
528 assertEquals("bcbccb", sb.toString());
529 sb.deleteAll('c');
530 assertEquals("bbb", sb.toString());
531 sb.deleteAll('b');
532 assertEquals("", sb.toString());
533
534 sb = new StrBuilder("");
535 sb.deleteAll('b');
536 assertEquals("", sb.toString());
537 }
538
539 public void testDeleteFirst_char() {
540 StrBuilder sb = new StrBuilder("abcba");
541 sb.deleteFirst('X');
542 assertEquals("abcba", sb.toString());
543 sb.deleteFirst('a');
544 assertEquals("bcba", sb.toString());
545 sb.deleteFirst('c');
546 assertEquals("bba", sb.toString());
547 sb.deleteFirst('b');
548 assertEquals("ba", sb.toString());
549
550 sb = new StrBuilder("");
551 sb.deleteFirst('b');
552 assertEquals("", sb.toString());
553 }
554
555 // -----------------------------------------------------------------------
556 public void testDeleteAll_String() {
557 StrBuilder sb = new StrBuilder("abcbccba");
558 sb.deleteAll((String) null);
559 assertEquals("abcbccba", sb.toString());
560 sb.deleteAll("");
561 assertEquals("abcbccba", sb.toString());
562
563 sb.deleteAll("X");
564 assertEquals("abcbccba", sb.toString());
565 sb.deleteAll("a");
566 assertEquals("bcbccb", sb.toString());
567 sb.deleteAll("c");
568 assertEquals("bbb", sb.toString());
569 sb.deleteAll("b");
570 assertEquals("", sb.toString());
571
572 sb = new StrBuilder("abcbccba");
573 sb.deleteAll("bc");
574 assertEquals("acba", sb.toString());
575
576 sb = new StrBuilder("");
577 sb.deleteAll("bc");
578 assertEquals("", sb.toString());
579 }
580
581 public void testDeleteFirst_String() {
582 StrBuilder sb = new StrBuilder("abcbccba");
583 sb.deleteFirst((String) null);
584 assertEquals("abcbccba", sb.toString());
585 sb.deleteFirst("");
586 assertEquals("abcbccba", sb.toString());
587
588 sb.deleteFirst("X");
589 assertEquals("abcbccba", sb.toString());
590 sb.deleteFirst("a");
591 assertEquals("bcbccba", sb.toString());
592 sb.deleteFirst("c");
593 assertEquals("bbccba", sb.toString());
594 sb.deleteFirst("b");
595 assertEquals("bccba", sb.toString());
596
597 sb = new StrBuilder("abcbccba");
598 sb.deleteFirst("bc");
599 assertEquals("abccba", sb.toString());
600
601 sb = new StrBuilder("");
602 sb.deleteFirst("bc");
603 assertEquals("", sb.toString());
604 }
605
606 // -----------------------------------------------------------------------
607 public void testDeleteAll_StrMatcher() {
608 StrBuilder sb = new StrBuilder("A0xA1A2yA3");
609 sb.deleteAll((StrMatcher) null);
610 assertEquals("A0xA1A2yA3", sb.toString());
611 sb.deleteAll(A_NUMBER_MATCHER);
612 assertEquals("xy", sb.toString());
613
614 sb = new StrBuilder("Ax1");
615 sb.deleteAll(A_NUMBER_MATCHER);
616 assertEquals("Ax1", sb.toString());
617
618 sb = new StrBuilder("");
619 sb.deleteAll(A_NUMBER_MATCHER);
620 assertEquals("", sb.toString());
621 }
622
623 public void testDeleteFirst_StrMatcher() {
624 StrBuilder sb = new StrBuilder("A0xA1A2yA3");
625 sb.deleteFirst((StrMatcher) null);
626 assertEquals("A0xA1A2yA3", sb.toString());
627 sb.deleteFirst(A_NUMBER_MATCHER);
628 assertEquals("xA1A2yA3", sb.toString());
629
630 sb = new StrBuilder("Ax1");
631 sb.deleteFirst(A_NUMBER_MATCHER);
632 assertEquals("Ax1", sb.toString());
633
634 sb = new StrBuilder("");
635 sb.deleteFirst(A_NUMBER_MATCHER);
636 assertEquals("", sb.toString());
637 }
638
639 // -----------------------------------------------------------------------
640 public void testReplace_int_int_String() {
641 StrBuilder sb = new StrBuilder("abc");
642 sb.replace(0, 1, "d");
643 assertEquals("dbc", sb.toString());
644 sb.replace(0, 1, "aaa");
645 assertEquals("aaabc", sb.toString());
646 sb.replace(0, 3, "");
647 assertEquals("bc", sb.toString());
648 sb.replace(1, 2, (String) null);
649 assertEquals("b", sb.toString());
650 sb.replace(1, 1000, "text");
651 assertEquals("btext", sb.toString());
652 sb.replace(0, 1000, "text");
653 assertEquals("text", sb.toString());
654
655 sb = new StrBuilder("atext");
656 sb.replace(1, 1, "ny");
657 assertEquals("anytext", sb.toString());
658 try {
659 sb.replace(2, 1, "anything");
660 fail("Expected IndexOutOfBoundsException");
661 } catch (IndexOutOfBoundsException e) {}
662
663 sb = new StrBuilder();
664 try {
665 sb.replace(1, 2, "anything");
666 fail("Expected IndexOutOfBoundsException");
667 } catch (IndexOutOfBoundsException e) {}
668 try {
669 sb.replace(-1, 1, "anything");
670 fail("Expected IndexOutOfBoundsException");
671 } catch (IndexOutOfBoundsException e) {}
672 }
673
674 //-----------------------------------------------------------------------
675 public void testReplaceAll_char_char() {
676 StrBuilder sb = new StrBuilder("abcbccba");
677 sb.replaceAll('x', 'y');
678 assertEquals("abcbccba", sb.toString());
679 sb.replaceAll('a', 'd');
680 assertEquals("dbcbccbd", sb.toString());
681 sb.replaceAll('b', 'e');
682 assertEquals("dececced", sb.toString());
683 sb.replaceAll('c', 'f');
684 assertEquals("defeffed", sb.toString());
685 sb.replaceAll('d', 'd');
686 assertEquals("defeffed", sb.toString());
687 }
688
689 //-----------------------------------------------------------------------
690 public void testReplaceFirst_char_char() {
691 StrBuilder sb = new StrBuilder("abcbccba");
692 sb.replaceFirst('x', 'y');
693 assertEquals("abcbccba", sb.toString());
694 sb.replaceFirst('a', 'd');
695 assertEquals("dbcbccba", sb.toString());
696 sb.replaceFirst('b', 'e');
697 assertEquals("decbccba", sb.toString());
698 sb.replaceFirst('c', 'f');
699 assertEquals("defbccba", sb.toString());
700 sb.replaceFirst('d', 'd');
701 assertEquals("defbccba", sb.toString());
702 }
703
704 //-----------------------------------------------------------------------
705 public void testReplaceAll_String_String() {
706 StrBuilder sb = new StrBuilder("abcbccba");
707 sb.replaceAll((String) null, null);
708 assertEquals("abcbccba", sb.toString());
709 sb.replaceAll((String) null, "anything");
710 assertEquals("abcbccba", sb.toString());
711 sb.replaceAll("", null);
712 assertEquals("abcbccba", sb.toString());
713 sb.replaceAll("", "anything");
714 assertEquals("abcbccba", sb.toString());
715
716 sb.replaceAll("x", "y");
717 assertEquals("abcbccba", sb.toString());
718 sb.replaceAll("a", "d");
719 assertEquals("dbcbccbd", sb.toString());
720 sb.replaceAll("d", null);
721 assertEquals("bcbccb", sb.toString());
722 sb.replaceAll("cb", "-");
723 assertEquals("b-c-", sb.toString());
724
725 sb = new StrBuilder("abcba");
726 sb.replaceAll("b", "xbx");
727 assertEquals("axbxcxbxa", sb.toString());
728
729 sb = new StrBuilder("bb");
730 sb.replaceAll("b", "xbx");
731 assertEquals("xbxxbx", sb.toString());
732 }
733
734 public void testReplaceFirst_String_String() {
735 StrBuilder sb = new StrBuilder("abcbccba");
736 sb.replaceFirst((String) null, null);
737 assertEquals("abcbccba", sb.toString());
738 sb.replaceFirst((String) null, "anything");
739 assertEquals("abcbccba", sb.toString());
740 sb.replaceFirst("", null);
741 assertEquals("abcbccba", sb.toString());
742 sb.replaceFirst("", "anything");
743 assertEquals("abcbccba", sb.toString());
744
745 sb.replaceFirst("x", "y");
746 assertEquals("abcbccba", sb.toString());
747 sb.replaceFirst("a", "d");
748 assertEquals("dbcbccba", sb.toString());
749 sb.replaceFirst("d", null);
750 assertEquals("bcbccba", sb.toString());
751 sb.replaceFirst("cb", "-");
752 assertEquals("b-ccba", sb.toString());
753
754 sb = new StrBuilder("abcba");
755 sb.replaceFirst("b", "xbx");
756 assertEquals("axbxcba", sb.toString());
757
758 sb = new StrBuilder("bb");
759 sb.replaceFirst("b", "xbx");
760 assertEquals("xbxb", sb.toString());
761 }
762
763 //-----------------------------------------------------------------------
764 public void testReplaceAll_StrMatcher_String() {
765 StrBuilder sb = new StrBuilder("abcbccba");
766 sb.replaceAll((StrMatcher) null, null);
767 assertEquals("abcbccba", sb.toString());
768 sb.replaceAll((StrMatcher) null, "anything");
769 assertEquals("abcbccba", sb.toString());
770 sb.replaceAll(StrMatcher.noneMatcher(), null);
771 assertEquals("abcbccba", sb.toString());
772 sb.replaceAll(StrMatcher.noneMatcher(), "anything");
773 assertEquals("abcbccba", sb.toString());
774
775 sb.replaceAll(StrMatcher.charMatcher('x'), "y");
776 assertEquals("abcbccba", sb.toString());
777 sb.replaceAll(StrMatcher.charMatcher('a'), "d");
778 assertEquals("dbcbccbd", sb.toString());
779 sb.replaceAll(StrMatcher.charMatcher('d'), null);
780 assertEquals("bcbccb", sb.toString());
781 sb.replaceAll(StrMatcher.stringMatcher("cb"), "-");
782 assertEquals("b-c-", sb.toString());
783
784 sb = new StrBuilder("abcba");
785 sb.replaceAll(StrMatcher.charMatcher('b'), "xbx");
786 assertEquals("axbxcxbxa", sb.toString());
787
788 sb = new StrBuilder("bb");
789 sb.replaceAll(StrMatcher.charMatcher('b'), "xbx");
790 assertEquals("xbxxbx", sb.toString());
791
792 sb = new StrBuilder("A1-A2A3-A4");
793 sb.replaceAll(A_NUMBER_MATCHER, "***");
794 assertEquals("***-******-***", sb.toString());
795 }
796
797 public void testReplaceFirst_StrMatcher_String() {
798 StrBuilder sb = new StrBuilder("abcbccba");
799 sb.replaceFirst((StrMatcher) null, null);
800 assertEquals("abcbccba", sb.toString());
801 sb.replaceFirst((StrMatcher) null, "anything");
802 assertEquals("abcbccba", sb.toString());
803 sb.replaceFirst(StrMatcher.noneMatcher(), null);
804 assertEquals("abcbccba", sb.toString());
805 sb.replaceFirst(StrMatcher.noneMatcher(), "anything");
806 assertEquals("abcbccba", sb.toString());
807
808 sb.replaceFirst(StrMatcher.charMatcher('x'), "y");
809 assertEquals("abcbccba", sb.toString());
810 sb.replaceFirst(StrMatcher.charMatcher('a'), "d");
811 assertEquals("dbcbccba", sb.toString());
812 sb.replaceFirst(StrMatcher.charMatcher('d'), null);
813 assertEquals("bcbccba", sb.toString());
814 sb.replaceFirst(StrMatcher.stringMatcher("cb"), "-");
815 assertEquals("b-ccba", sb.toString());
816
817 sb = new StrBuilder("abcba");
818 sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx");
819 assertEquals("axbxcba", sb.toString());
820
821 sb = new StrBuilder("bb");
822 sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx");
823 assertEquals("xbxb", sb.toString());
824
825 sb = new StrBuilder("A1-A2A3-A4");
826 sb.replaceFirst(A_NUMBER_MATCHER, "***");
827 assertEquals("***-A2A3-A4", sb.toString());
828 }
829
830 //-----------------------------------------------------------------------
831 public void testReplace_StrMatcher_String_int_int_int_VaryMatcher() {
832 StrBuilder sb = new StrBuilder("abcbccba");
833 sb.replace((StrMatcher) null, "x", 0, sb.length(), -1);
834 assertEquals("abcbccba", sb.toString());
835
836 sb.replace(StrMatcher.charMatcher('a'), "x", 0, sb.length(), -1);
837 assertEquals("xbcbccbx", sb.toString());
838
839 sb.replace(StrMatcher.stringMatcher("cb"), "x", 0, sb.length(), -1);
840 assertEquals("xbxcxx", sb.toString());
841
842 sb = new StrBuilder("A1-A2A3-A4");
843 sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
844 assertEquals("***-******-***", sb.toString());
845
846 sb = new StrBuilder();
847 sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
848 assertEquals("", sb.toString());
849 }
850
851 public void testReplace_StrMatcher_String_int_int_int_VaryReplace() {
852 StrBuilder sb = new StrBuilder("abcbccba");
853 sb.replace(StrMatcher.stringMatcher("cb"), "cb", 0, sb.length(), -1);
854 assertEquals("abcbccba", sb.toString());
855
856 sb = new StrBuilder("abcbccba");
857 sb.replace(StrMatcher.stringMatcher("cb"), "-", 0, sb.length(), -1);
858 assertEquals("ab-c-a", sb.toString());
859
860 sb = new StrBuilder("abcbccba");
861 sb.replace(StrMatcher.stringMatcher("cb"), "+++", 0, sb.length(), -1);
862 assertEquals("ab+++c+++a", sb.toString());
863
864 sb = new StrBuilder("abcbccba");
865 sb.replace(StrMatcher.stringMatcher("cb"), "", 0, sb.length(), -1);
866 assertEquals("abca", sb.toString());
867
868 sb = new StrBuilder("abcbccba");
869 sb.replace(StrMatcher.stringMatcher("cb"), null, 0, sb.length(), -1);
870 assertEquals("abca", sb.toString());
871 }
872
873 public void testReplace_StrMatcher_String_int_int_int_VaryStartIndex() {
874 StrBuilder sb = new StrBuilder("aaxaaaayaa");
875 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, sb.length(), -1);
876 assertEquals("-x--y-", sb.toString());
877
878 sb = new StrBuilder("aaxaaaayaa");
879 sb.replace(StrMatcher.stringMatcher("aa"), "-", 1, sb.length(), -1);
880 assertEquals("aax--y-", sb.toString());
881
882 sb = new StrBuilder("aaxaaaayaa");
883 sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, sb.length(), -1);
884 assertEquals("aax--y-", sb.toString());
885
886 sb = new StrBuilder("aaxaaaayaa");
887 sb.replace(StrMatcher.stringMatcher("aa"), "-", 3, sb.length(), -1);
888 assertEquals("aax--y-", sb.toString());
889
890 sb = new StrBuilder("aaxaaaayaa");
891 sb.replace(StrMatcher.stringMatcher("aa"), "-", 4, sb.length(), -1);
892 assertEquals("aaxa-ay-", sb.toString());
893
894 sb = new StrBuilder("aaxaaaayaa");
895 sb.replace(StrMatcher.stringMatcher("aa"), "-", 5, sb.length(), -1);
896 assertEquals("aaxaa-y-", sb.toString());
897
898 sb = new StrBuilder("aaxaaaayaa");
899 sb.replace(StrMatcher.stringMatcher("aa"), "-", 6, sb.length(), -1);
900 assertEquals("aaxaaaay-", sb.toString());
901
902 sb = new StrBuilder("aaxaaaayaa");
903 sb.replace(StrMatcher.stringMatcher("aa"), "-", 7, sb.length(), -1);
904 assertEquals("aaxaaaay-", sb.toString());
905
906 sb = new StrBuilder("aaxaaaayaa");
907 sb.replace(StrMatcher.stringMatcher("aa"), "-", 8, sb.length(), -1);
908 assertEquals("aaxaaaay-", sb.toString());
909
910 sb = new StrBuilder("aaxaaaayaa");
911 sb.replace(StrMatcher.stringMatcher("aa"), "-", 9, sb.length(), -1);
912 assertEquals("aaxaaaayaa", sb.toString());
913
914 sb = new StrBuilder("aaxaaaayaa");
915 sb.replace(StrMatcher.stringMatcher("aa"), "-", 10, sb.length(), -1);
916 assertEquals("aaxaaaayaa", sb.toString());
917
918 sb = new StrBuilder("aaxaaaayaa");
919 try {
920 sb.replace(StrMatcher.stringMatcher("aa"), "-", 11, sb.length(), -1);
921 fail();
922 } catch (IndexOutOfBoundsException ex) {}
923 assertEquals("aaxaaaayaa", sb.toString());
924
925 sb = new StrBuilder("aaxaaaayaa");
926 try {
927 sb.replace(StrMatcher.stringMatcher("aa"), "-", -1, sb.length(), -1);
928 fail();
929 } catch (IndexOutOfBoundsException ex) {}
930 assertEquals("aaxaaaayaa", sb.toString());
931 }
932
933 public void testReplace_StrMatcher_String_int_int_int_VaryEndIndex() {
934 StrBuilder sb = new StrBuilder("aaxaaaayaa");
935 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 0, -1);
936 assertEquals("aaxaaaayaa", sb.toString());
937
938 sb = new StrBuilder("aaxaaaayaa");
939 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 2, -1);
940 assertEquals("-xaaaayaa", sb.toString());
941
942 sb = new StrBuilder("aaxaaaayaa");
943 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 3, -1);
944 assertEquals("-xaaaayaa", sb.toString());
945
946 sb = new StrBuilder("aaxaaaayaa");
947 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 4, -1);
948 assertEquals("-xaaaayaa", sb.toString());
949
950 sb = new StrBuilder("aaxaaaayaa");
951 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 5, -1);
952 assertEquals("-x-aayaa", sb.toString());
953
954 sb = new StrBuilder("aaxaaaayaa");
955 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 6, -1);
956 assertEquals("-x-aayaa", sb.toString());
957
958 sb = new StrBuilder("aaxaaaayaa");
959 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 7, -1);
960 assertEquals("-x--yaa", sb.toString());
961
962 sb = new StrBuilder("aaxaaaayaa");
963 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 8, -1);
964 assertEquals("-x--yaa", sb.toString());
965
966 sb = new StrBuilder("aaxaaaayaa");
967 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 9, -1);
968 assertEquals("-x--yaa", sb.toString());
969
970 sb = new StrBuilder("aaxaaaayaa");
971 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1);
972 assertEquals("-x--y-", sb.toString());
973
974 sb = new StrBuilder("aaxaaaayaa");
975 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 1000, -1);
976 assertEquals("-x--y-", sb.toString());
977
978 sb = new StrBuilder("aaxaaaayaa");
979 try {
980 sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, 1, -1);
981 fail();
982 } catch (IndexOutOfBoundsException ex) {}
983 assertEquals("aaxaaaayaa", sb.toString());
984 }
985
986 public void testReplace_StrMatcher_String_int_int_int_VaryCount() {
987 StrBuilder sb = new StrBuilder("aaxaaaayaa");
988 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1);
989 assertEquals("-x--y-", sb.toString());
990
991 sb = new StrBuilder("aaxaaaayaa");
992 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 0);
993 assertEquals("aaxaaaayaa", sb.toString());
994
995 sb = new StrBuilder("aaxaaaayaa");
996 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 1);
997 assertEquals("-xaaaayaa", sb.toString());
998
999 sb = new StrBuilder("aaxaaaayaa");
1000 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 2);
1001 assertEquals("-x-aayaa", sb.toString());
1002
1003 sb = new StrBuilder("aaxaaaayaa");
1004 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 3);
1005 assertEquals("-x--yaa", sb.toString());
1006
1007 sb = new StrBuilder("aaxaaaayaa");
1008 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 4);
1009 assertEquals("-x--y-", sb.toString());
1010
1011 sb = new StrBuilder("aaxaaaayaa");
1012 sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 5);
1013 assertEquals("-x--y-", sb.toString());
1014 }
1015
1016 //-----------------------------------------------------------------------
1017 public void testReverse() {
1018 StrBuilder sb = new StrBuilder();
1019 assertEquals("", sb.reverse().toString());
1020
1021 sb.clear().append(true);
1022 assertEquals("eurt", sb.reverse().toString());
1023 assertEquals("true", sb.reverse().toString());
1024 }
1025
1026 //-----------------------------------------------------------------------
1027 public void testTrim() {
1028 StrBuilder sb = new StrBuilder();
1029 assertEquals("", sb.reverse().toString());
1030
1031 sb.clear().append(" \u0000 ");
1032 assertEquals("", sb.trim().toString());
1033
1034 sb.clear().append(" \u0000 a b c");
1035 assertEquals("a b c", sb.trim().toString());
1036
1037 sb.clear().append("a b c \u0000 ");
1038 assertEquals("a b c", sb.trim().toString());
1039
1040 sb.clear().append(" \u0000 a b c \u0000 ");
1041 assertEquals("a b c", sb.trim().toString());
1042
1043 sb.clear().append("a b c");
1044 assertEquals("a b c", sb.trim().toString());
1045 }
1046
1047 //-----------------------------------------------------------------------
1048 public void testStartsWith() {
1049 StrBuilder sb = new StrBuilder();
1050 assertFalse(sb.startsWith("a"));
1051 assertFalse(sb.startsWith(null));
1052 assertTrue(sb.startsWith(""));
1053 sb.append("abc");
1054 assertTrue(sb.startsWith("a"));
1055 assertTrue(sb.startsWith("ab"));
1056 assertTrue(sb.startsWith("abc"));
1057 assertFalse(sb.startsWith("cba"));
1058 }
1059
1060 public void testEndsWith() {
1061 StrBuilder sb = new StrBuilder();
1062 assertFalse(sb.endsWith("a"));
1063 assertFalse(sb.endsWith("c"));
1064 assertTrue(sb.endsWith(""));
1065 assertFalse(sb.endsWith(null));
1066 sb.append("abc");
1067 assertTrue(sb.endsWith("c"));
1068 assertTrue(sb.endsWith("bc"));
1069 assertTrue(sb.endsWith("abc"));
1070 assertFalse(sb.endsWith("cba"));
1071 assertFalse(sb.endsWith("abcd"));
1072 assertFalse(sb.endsWith(" abc"));
1073 assertFalse(sb.endsWith("abc "));
1074 }
1075
1076 //-----------------------------------------------------------------------
1077 public void testSubSequenceIntInt() {
1078 StrBuilder sb = new StrBuilder ("hello goodbye");
1079 // Start index is negative
1080 try {
1081 sb.subSequence(-1, 5);
1082 fail();
1083 } catch (IndexOutOfBoundsException e) {}
1084
1085 // End index is negative
1086 try {
1087 sb.subSequence(2, -1);
1088 fail();
1089 } catch (IndexOutOfBoundsException e) {}
1090
1091 // End index greater than length()
1092 try {
1093 sb.subSequence(2, sb.length() + 1);
1094 fail();
1095 } catch (IndexOutOfBoundsException e) {}
1096
1097 // Start index greater then end index
1098 try {
1099 sb.subSequence(3, 2);
1100 fail();
1101 } catch (IndexOutOfBoundsException e) {}
1102
1103 // Normal cases
1104 assertEquals ("hello", sb.subSequence(0, 5));
1105 assertEquals ("hello goodbye".subSequence(0, 6), sb.subSequence(0, 6));
1106 assertEquals ("goodbye", sb.subSequence(6, 13));
1107 assertEquals ("hello goodbye".subSequence(6,13), sb.subSequence(6, 13));
1108 }
1109
1110 public void testSubstringInt() {
1111 StrBuilder sb = new StrBuilder ("hello goodbye");
1112 assertEquals ("goodbye", sb.substring(6));
1113 assertEquals ("hello goodbye".substring(6), sb.substring(6));
1114 assertEquals ("hello goodbye", sb.substring(0));
1115 assertEquals ("hello goodbye".substring(0), sb.substring(0));
1116 try {
1117 sb.substring(-1);
1118 fail ();
1119 } catch (IndexOutOfBoundsException e) {}
1120
1121 try {
1122 sb.substring(15);
1123 fail ();
1124 } catch (IndexOutOfBoundsException e) {}
1125
1126 }
1127
1128 public void testSubstringIntInt() {
1129 StrBuilder sb = new StrBuilder ("hello goodbye");
1130 assertEquals ("hello", sb.substring(0, 5));
1131 assertEquals ("hello goodbye".substring(0, 6), sb.substring(0, 6));
1132
1133 assertEquals ("goodbye", sb.substring(6, 13));
1134 assertEquals ("hello goodbye".substring(6,13), sb.substring(6, 13));
1135
1136 assertEquals ("goodbye", sb.substring(6, 20));
1137
1138 try {
1139 sb.substring(-1, 5);
1140 fail();
1141 } catch (IndexOutOfBoundsException e) {}
1142
1143 try {
1144 sb.substring(15, 20);
1145 fail();
1146 } catch (IndexOutOfBoundsException e) {}
1147 }
1148
1149 // -----------------------------------------------------------------------
1150 public void testMidString() {
1151 StrBuilder sb = new StrBuilder("hello goodbye hello");
1152 assertEquals("goodbye", sb.midString(6, 7));
1153 assertEquals("hello", sb.midString(0, 5));
1154 assertEquals("hello", sb.midString(-5, 5));
1155 assertEquals("", sb.midString(0, -1));
1156 assertEquals("", sb.midString(20, 2));
1157 assertEquals("hello", sb.midString(14, 22));
1158 }
1159
1160 public void testRightString() {
1161 StrBuilder sb = new StrBuilder("left right");
1162 assertEquals("right", sb.rightString(5));
1163 assertEquals("", sb.rightString(0));
1164 assertEquals("", sb.rightString(-5));
1165 assertEquals("left right", sb.rightString(15));
1166 }
1167
1168 public void testLeftString() {
1169 StrBuilder sb = new StrBuilder("left right");
1170 assertEquals("left", sb.leftString(4));
1171 assertEquals("", sb.leftString(0));
1172 assertEquals("", sb.leftString(-5));
1173 assertEquals("left right", sb.leftString(15));
1174 }
1175
1176 // -----------------------------------------------------------------------
1177 public void testContains_char() {
1178 StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
1179 assertEquals(true, sb.contains('a'));
1180 assertEquals(true, sb.contains('o'));
1181 assertEquals(true, sb.contains('z'));
1182 assertEquals(false, sb.contains('1'));
1183 }
1184
1185 public void testContains_String() {
1186 StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
1187 assertEquals(true, sb.contains("a"));
1188 assertEquals(true, sb.contains("pq"));
1189 assertEquals(true, sb.contains("z"));
1190 assertEquals(false, sb.contains("zyx"));
1191 assertEquals(false, sb.contains((String) null));
1192 }
1193
1194 public void testContains_StrMatcher() {
1195 StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
1196 assertEquals(true, sb.contains(StrMatcher.charMatcher('a')));
1197 assertEquals(true, sb.contains(StrMatcher.stringMatcher("pq")));
1198 assertEquals(true, sb.contains(StrMatcher.charMatcher('z')));
1199 assertEquals(false, sb.contains(StrMatcher.stringMatcher("zy")));
1200 assertEquals(false, sb.contains((StrMatcher) null));
1201
1202 sb = new StrBuilder();
1203 assertEquals(false, sb.contains(A_NUMBER_MATCHER));
1204 sb.append("B A1 C");
1205 assertEquals(true, sb.contains(A_NUMBER_MATCHER));
1206 }
1207
1208 // -----------------------------------------------------------------------
1209 public void testIndexOf_char() {
1210 StrBuilder sb = new StrBuilder("abab");
1211 assertEquals(0, sb.indexOf('a'));
1212
1213 // should work like String#indexOf
1214 assertEquals("abab".indexOf('a'), sb.indexOf('a'));
1215
1216 assertEquals(1, sb.indexOf('b'));
1217 assertEquals("abab".indexOf('b'), sb.indexOf('b'));
1218
1219 assertEquals(-1, sb.indexOf('z'));
1220 }
1221
1222 public void testIndexOf_char_int() {
1223 StrBuilder sb = new StrBuilder("abab");
1224 assertEquals(0, sb.indexOf('a', -1));
1225 assertEquals(0, sb.indexOf('a', 0));
1226 assertEquals(2, sb.indexOf('a', 1));
1227 assertEquals(-1, sb.indexOf('a', 4));
1228 assertEquals(-1, sb.indexOf('a', 5));
1229
1230 // should work like String#indexOf
1231 assertEquals("abab".indexOf('a', 1), sb.indexOf('a', 1));
1232
1233 assertEquals(3, sb.indexOf('b', 2));
1234 assertEquals("abab".indexOf('b', 2), sb.indexOf('b', 2));
1235
1236 assertEquals(-1, sb.indexOf('z', 2));
1237
1238 sb = new StrBuilder("xyzabc");
1239 assertEquals(2, sb.indexOf('z', 0));
1240 assertEquals(-1, sb.indexOf('z', 3));
1241 }
1242
1243 public void testLastIndexOf_char() {
1244 StrBuilder sb = new StrBuilder("abab");
1245
1246 assertEquals (2, sb.lastIndexOf('a'));
1247 //should work like String#lastIndexOf
1248 assertEquals ("abab".lastIndexOf('a'), sb.lastIndexOf('a'));
1249
1250 assertEquals(3, sb.lastIndexOf('b'));
1251 assertEquals ("abab".lastIndexOf('b'), sb.lastIndexOf('b'));
1252
1253 assertEquals (-1, sb.lastIndexOf('z'));
1254 }
1255
1256 public void testLastIndexOf_char_int() {
1257 StrBuilder sb = new StrBuilder("abab");
1258 assertEquals(-1, sb.lastIndexOf('a', -1));
1259 assertEquals(0, sb.lastIndexOf('a', 0));
1260 assertEquals(0, sb.lastIndexOf('a', 1));
1261
1262 // should work like String#lastIndexOf
1263 assertEquals("abab".lastIndexOf('a', 1), sb.lastIndexOf('a', 1));
1264
1265 assertEquals(1, sb.lastIndexOf('b', 2));
1266 assertEquals("abab".lastIndexOf('b', 2), sb.lastIndexOf('b', 2));
1267
1268 assertEquals(-1, sb.lastIndexOf('z', 2));
1269
1270 sb = new StrBuilder("xyzabc");
1271 assertEquals(2, sb.lastIndexOf('z', sb.length()));
1272 assertEquals(-1, sb.lastIndexOf('z', 1));
1273 }
1274
1275 // -----------------------------------------------------------------------
1276 public void testIndexOf_String() {
1277 StrBuilder sb = new StrBuilder("abab");
1278
1279 assertEquals(0, sb.indexOf("a"));
1280 //should work like String#indexOf
1281 assertEquals("abab".indexOf("a"), sb.indexOf("a"));
1282
1283 assertEquals(0, sb.indexOf("ab"));
1284 //should work like String#indexOf
1285 assertEquals("abab".indexOf("ab"), sb.indexOf("ab"));
1286
1287 assertEquals(1, sb.indexOf("b"));
1288 assertEquals("abab".indexOf("b"), sb.indexOf("b"));
1289
1290 assertEquals(1, sb.indexOf("ba"));
1291 assertEquals("abab".indexOf("ba"), sb.indexOf("ba"));
1292
1293 assertEquals(-1, sb.indexOf("z"));
1294
1295 assertEquals(-1, sb.indexOf((String) null));
1296 }
1297
1298 public void testIndexOf_String_int() {
1299 StrBuilder sb = new StrBuilder("abab");
1300 assertEquals(0, sb.indexOf("a", -1));
1301 assertEquals(0, sb.indexOf("a", 0));
1302 assertEquals(2, sb.indexOf("a", 1));
1303 assertEquals(2, sb.indexOf("a", 2));
1304 assertEquals(-1, sb.indexOf("a", 3));
1305 assertEquals(-1, sb.indexOf("a", 4));
1306 assertEquals(-1, sb.indexOf("a", 5));
1307
1308 assertEquals(-1, sb.indexOf("abcdef", 0));
1309 assertEquals(0, sb.indexOf("", 0));
1310 assertEquals(1, sb.indexOf("", 1));
1311
1312 //should work like String#indexOf
1313 assertEquals ("abab".indexOf("a", 1), sb.indexOf("a", 1));
1314
1315 assertEquals(2, sb.indexOf("ab", 1));
1316 //should work like String#indexOf
1317 assertEquals("abab".indexOf("ab", 1), sb.indexOf("ab", 1));
1318
1319 assertEquals(3, sb.indexOf("b", 2));
1320 assertEquals("abab".indexOf("b", 2), sb.indexOf("b", 2));
1321
1322 assertEquals(1, sb.indexOf("ba", 1));
1323 assertEquals("abab".indexOf("ba", 2), sb.indexOf("ba", 2));
1324
1325 assertEquals(-1, sb.indexOf("z", 2));
1326
1327 sb = new StrBuilder("xyzabc");
1328 assertEquals(2, sb.indexOf("za", 0));
1329 assertEquals(-1, sb.indexOf("za", 3));
1330
1331 assertEquals(-1, sb.indexOf((String) null, 2));
1332 }
1333
1334 public void testLastIndexOf_String() {
1335 StrBuilder sb = new StrBuilder("abab");
1336
1337 assertEquals(2, sb.lastIndexOf("a"));
1338 //should work like String#lastIndexOf
1339 assertEquals("abab".lastIndexOf("a"), sb.lastIndexOf("a"));
1340
1341 assertEquals(2, sb.lastIndexOf("ab"));
1342 //should work like String#lastIndexOf
1343 assertEquals("abab".lastIndexOf("ab"), sb.lastIndexOf("ab"));
1344
1345 assertEquals(3, sb.lastIndexOf("b"));
1346 assertEquals("abab".lastIndexOf("b"), sb.lastIndexOf("b"));
1347
1348 assertEquals(1, sb.lastIndexOf("ba"));
1349 assertEquals("abab".lastIndexOf("ba"), sb.lastIndexOf("ba"));
1350
1351 assertEquals(-1, sb.lastIndexOf("z"));
1352
1353 assertEquals(-1, sb.lastIndexOf((String) null));
1354 }
1355
1356 public void testLastIndexOf_String_int() {
1357 StrBuilder sb = new StrBuilder("abab");
1358 assertEquals(-1, sb.lastIndexOf("a", -1));
1359 assertEquals(0, sb.lastIndexOf("a", 0));
1360 assertEquals(0, sb.lastIndexOf("a", 1));
1361 assertEquals(2, sb.lastIndexOf("a", 2));
1362 assertEquals(2, sb.lastIndexOf("a", 3));
1363 assertEquals(2, sb.lastIndexOf("a", 4));
1364 assertEquals(2, sb.lastIndexOf("a", 5));
1365
1366 assertEquals(-1, sb.lastIndexOf("abcdef", 3));
1367 assertEquals("abab".lastIndexOf("", 3), sb.lastIndexOf("", 3));
1368 assertEquals("abab".lastIndexOf("", 1), sb.lastIndexOf("", 1));
1369
1370 //should work like String#lastIndexOf
1371 assertEquals("abab".lastIndexOf("a", 1), sb.lastIndexOf("a", 1));
1372
1373 assertEquals(0, sb.lastIndexOf("ab", 1));
1374 //should work like String#lastIndexOf
1375 assertEquals("abab".lastIndexOf("ab", 1), sb.lastIndexOf("ab", 1));
1376
1377 assertEquals(1, sb.lastIndexOf("b", 2));
1378 assertEquals("abab".lastIndexOf("b", 2), sb.lastIndexOf("b", 2));
1379
1380 assertEquals(1, sb.lastIndexOf("ba", 2));
1381 assertEquals("abab".lastIndexOf("ba", 2), sb.lastIndexOf("ba", 2));
1382
1383 assertEquals(-1, sb.lastIndexOf("z", 2));
1384
1385 sb = new StrBuilder("xyzabc");
1386 assertEquals(2, sb.lastIndexOf("za", sb.length()));
1387 assertEquals(-1, sb.lastIndexOf("za", 1));
1388
1389 assertEquals(-1, sb.lastIndexOf((String) null, 2));
1390 }
1391
1392 // -----------------------------------------------------------------------
1393 public void testIndexOf_StrMatcher() {
1394 StrBuilder sb = new StrBuilder();
1395 assertEquals(-1, sb.indexOf((StrMatcher) null));
1396 assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a')));
1397
1398 sb.append("ab bd");
1399 assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a')));
1400 assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b')));
1401 assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher()));
1402 assertEquals(4, sb.indexOf(StrMatcher.charMatcher('d')));
1403 assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher()));
1404 assertEquals(-1, sb.indexOf((StrMatcher) null));
1405
1406 sb.append(" A1 junction");
1407 assertEquals(6, sb.indexOf(A_NUMBER_MATCHER));
1408 }
1409
1410 public void testIndexOf_StrMatcher_int() {
1411 StrBuilder sb = new StrBuilder();
1412 assertEquals(-1, sb.indexOf((StrMatcher) null, 2));
1413 assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2));
1414 assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 0));
1415
1416 sb.append("ab bd");
1417 assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), -2));
1418 assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), 0));
1419 assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2));
1420 assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 20));
1421
1422 assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), -1));
1423 assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 0));
1424 assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 1));
1425 assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 2));
1426 assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 3));
1427 assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 4));
1428 assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 5));
1429 assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 6));
1430
1431 assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), -2));
1432 assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 0));
1433 assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 2));
1434 assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 4));
1435 assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 20));
1436
1437 assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher(), 0));
1438 assertEquals(-1, sb.indexOf((StrMatcher) null, 0));
1439
1440 sb.append(" A1 junction with A2");
1441 assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 5));
1442 assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 6));
1443 assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 7));
1444 assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 22));
1445 assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 23));
1446 assertEquals(-1, sb.indexOf(A_NUMBER_MATCHER, 24));
1447 }
1448
1449 public void testLastIndexOf_StrMatcher() {
1450 StrBuilder sb = new StrBuilder();
1451 assertEquals(-1, sb.lastIndexOf((StrMatcher) null));
1452 assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a')));
1453
1454 sb.append("ab bd");
1455 assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a')));
1456 assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b')));
1457 assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher()));
1458 assertEquals(4, sb.lastIndexOf(StrMatcher.charMatcher('d')));
1459 assertEquals(-1, sb.lastIndexOf(StrMatcher.noneMatcher()));
1460 assertEquals(-1, sb.lastIndexOf((StrMatcher) null));
1461
1462 sb.append(" A1 junction");
1463 assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER));
1464 }
1465
1466 public void testLastIndexOf_StrMatcher_int() {
1467 StrBuilder sb = new StrBuilder();
1468 assertEquals(-1, sb.lastIndexOf((StrMatcher) null, 2));
1469 assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2));
1470 assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0));
1471 assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -1));
1472
1473 sb.append("ab bd");
1474 assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -2));
1475 assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0));
1476 assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2));
1477 assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 20));
1478
1479 assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('b'), -1));
1480 assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 0));
1481 assertEquals(1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 1));
1482 assertEquals(1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 2));
1483 assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 3));
1484 assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 4));
1485 assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 5));
1486 assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 6));
1487
1488 assertEquals(-1, sb.lastIndexOf(StrMatcher.spaceMatcher(), -2));
1489 assertEquals(-1, sb.lastIndexOf(StrMatcher.spaceMatcher(), 0));
1490 assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 2));
1491 assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 4));
1492 assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 20));
1493
1494 assertEquals(-1, sb.lastIndexOf(StrMatcher.noneMatcher(), 0));
1495 assertEquals(-1, sb.lastIndexOf((StrMatcher) null, 0));
1496
1497 sb.append(" A1 junction with A2");
1498 assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 5));
1499 assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 6)); // A matches, 1 is outside bounds
1500 assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 7));
1501 assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 22));
1502 assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 23)); // A matches, 2 is outside bounds
1503 assertEquals(23, sb.lastIndexOf(A_NUMBER_MATCHER, 24));
1504 }
1505
1506 static final StrMatcher A_NUMBER_MATCHER = new StrMatcher() {
1507 @Override
1508 public int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd) {
1509 if (buffer[pos] == 'A') {
1510 pos++;
1511 if (pos < bufferEnd && buffer[pos] >= '0' && buffer[pos] <= '9') {
1512 return 2;
1513 }
1514 }
1515 return 0;
1516 }
1517 };
1518
1519 //-----------------------------------------------------------------------
1520 public void testAsTokenizer() throws Exception {
1521 // from Javadoc
1522 StrBuilder b = new StrBuilder();
1523 b.append("a b ");
1524 StrTokenizer t = b.asTokenizer();
1525
1526 String[] tokens1 = t.getTokenArray();
1527 assertEquals(2, tokens1.length);
1528 assertEquals("a", tokens1[0]);
1529 assertEquals("b", tokens1[1]);
1530 assertEquals(2, t.size());
1531
1532 b.append("c d ");
1533 String[] tokens2 = t.getTokenArray();
1534 assertEquals(2, tokens2.length);
1535 assertEquals("a", tokens2[0]);
1536 assertEquals("b", tokens2[1]);
1537 assertEquals(2, t.size());
1538 assertEquals("a", t.next());
1539 assertEquals("b", t.next());
1540
1541 t.reset();
1542 String[] tokens3 = t.getTokenArray();
1543 assertEquals(4, tokens3.length);
1544 assertEquals("a", tokens3[0]);
1545 assertEquals("b", tokens3[1]);
1546 assertEquals("c", tokens3[2]);
1547 assertEquals("d", tokens3[3]);
1548 assertEquals(4, t.size());
1549 assertEquals("a", t.next());
1550 assertEquals("b", t.next());
1551 assertEquals("c", t.next());
1552 assertEquals("d", t.next());
1553
1554 assertEquals("a b c d ", t.getContent());
1555 }
1556
1557 // -----------------------------------------------------------------------
1558 public void testAsReader() throws Exception {
1559 StrBuilder sb = new StrBuilder("some text");
1560 Reader reader = sb.asReader();
1561 assertEquals(true, reader.ready());
1562 char[] buf = new char[40];
1563 assertEquals(9, reader.read(buf));
1564 assertEquals("some text", new String(buf, 0, 9));
1565
1566 assertEquals(-1, reader.read());
1567 assertEquals(false, reader.ready());
1568 assertEquals(0, reader.skip(2));
1569 assertEquals(0, reader.skip(-1));
1570
1571 assertEquals(true, reader.markSupported());
1572 reader = sb.asReader();
1573 assertEquals('s', reader.read());
1574 reader.mark(-1);
1575 char[] array = new char[3];
1576 assertEquals(3, reader.read(array, 0, 3));
1577 assertEquals('o', array[0]);
1578 assertEquals('m', array[1]);
1579 assertEquals('e', array[2]);
1580 reader.reset();
1581 assertEquals(1, reader.read(array, 1, 1));
1582 assertEquals('o', array[0]);
1583 assertEquals('o', array[1]);
1584 assertEquals('e', array[2]);
1585 assertEquals(2, reader.skip(2));
1586 assertEquals(' ', reader.read());
1587
1588 assertEquals(true, reader.ready());
1589 reader.close();
1590 assertEquals(true, reader.ready());
1591
1592 reader = sb.asReader();
1593 array = new char[3];
1594 try {
1595 reader.read(array, -1, 0);
1596 fail();
1597 } catch (IndexOutOfBoundsException ex) {}
1598 try {
1599 reader.read(array, 0, -1);
1600 fail();
1601 } catch (IndexOutOfBoundsException ex) {}
1602 try {
1603 reader.read(array, 100, 1);
1604 fail();
1605 } catch (IndexOutOfBoundsException ex) {}
1606 try {
1607 reader.read(array, 0, 100);
1608 fail();
1609 } catch (IndexOutOfBoundsException ex) {}
1610 try {
1611 reader.read(array, Integer.MAX_VALUE, Integer.MAX_VALUE);
1612 fail();
1613 } catch (IndexOutOfBoundsException ex) {}
1614
1615 assertEquals(0, reader.read(array, 0, 0));
1616 assertEquals(0, array[0]);
1617 assertEquals(0, array[1]);
1618 assertEquals(0, array[2]);
1619
1620 reader.skip(9);
1621 assertEquals(-1, reader.read(array, 0, 1));
1622
1623 reader.reset();
1624 array = new char[30];
1625 assertEquals(9, reader.read(array, 0, 30));
1626 }
1627
1628 //-----------------------------------------------------------------------
1629 public void testAsWriter() throws Exception {
1630 StrBuilder sb = new StrBuilder("base");
1631 Writer writer = sb.asWriter();
1632
1633 writer.write('l');
1634 assertEquals("basel", sb.toString());
1635
1636 writer.write(new char[] {'i', 'n'});
1637 assertEquals("baselin", sb.toString());
1638
1639 writer.write(new char[] {'n', 'e', 'r'}, 1, 2);
1640 assertEquals("baseliner", sb.toString());
1641
1642 writer.write(" rout");
1643 assertEquals("baseliner rout", sb.toString());
1644
1645 writer.write("ping that server", 1, 3);
1646 assertEquals("baseliner routing", sb.toString());
1647
1648 writer.flush(); // no effect
1649 assertEquals("baseliner routing", sb.toString());
1650
1651 writer.close(); // no effect
1652 assertEquals("baseliner routing", sb.toString());
1653
1654 writer.write(" hi"); // works after close
1655 assertEquals("baseliner routing hi", sb.toString());
1656
1657 sb.setLength(4); // mix and match
1658 writer.write('d');
1659 assertEquals("based", sb.toString());
1660 }
1661
1662 //-----------------------------------------------------------------------
1663 public void testEqualsIgnoreCase() {
1664 StrBuilder sb1 = new StrBuilder();
1665 StrBuilder sb2 = new StrBuilder();
1666 assertEquals(true, sb1.equalsIgnoreCase(sb1));
1667 assertEquals(true, sb1.equalsIgnoreCase(sb2));
1668 assertEquals(true, sb2.equalsIgnoreCase(sb2));
1669
1670 sb1.append("abc");
1671 assertEquals(false, sb1.equalsIgnoreCase(sb2));
1672
1673 sb2.append("ABC");
1674 assertEquals(true, sb1.equalsIgnoreCase(sb2));
1675
1676 sb2.clear().append("abc");
1677 assertEquals(true, sb1.equalsIgnoreCase(sb2));
1678 assertEquals(true, sb1.equalsIgnoreCase(sb1));
1679 assertEquals(true, sb2.equalsIgnoreCase(sb2));
1680
1681 sb2.clear().append("aBc");
1682 assertEquals(true, sb1.equalsIgnoreCase(sb2));
1683 }
1684
1685 //-----------------------------------------------------------------------
1686 public void testEquals() {
1687 StrBuilder sb1 = new StrBuilder();
1688 StrBuilder sb2 = new StrBuilder();
1689 assertEquals(true, sb1.equals(sb2));
1690 assertEquals(true, sb1.equals(sb1));
1691 assertEquals(true, sb2.equals(sb2));
1692 assertEquals(true, sb1.equals((Object) sb2));
1693
1694 sb1.append("abc");
1695 assertEquals(false, sb1.equals(sb2));
1696 assertEquals(false, sb1.equals((Object) sb2));
1697
1698 sb2.append("ABC");
1699 assertEquals(false, sb1.equals(sb2));
1700 assertEquals(false, sb1.equals((Object) sb2));
1701
1702 sb2.clear().append("abc");
1703 assertEquals(true, sb1.equals(sb2));
1704 assertEquals(true, sb1.equals((Object) sb2));
1705
1706 assertEquals(false, sb1.equals(Integer.valueOf(1)));
1707 assertEquals(false, sb1.equals("abc"));
1708 }
1709
1710 //-----------------------------------------------------------------------
1711 public void testHashCode() {
1712 StrBuilder sb = new StrBuilder();
1713 int hc1a = sb.hashCode();
1714 int hc1b = sb.hashCode();
1715 assertEquals(0, hc1a);
1716 assertEquals(hc1a, hc1b);
1717
1718 sb.append("abc");
1719 int hc2a = sb.hashCode();
1720 int hc2b = sb.hashCode();
1721 assertEquals(true, hc2a != 0);
1722 assertEquals(hc2a, hc2b);
1723 }
1724
1725 //-----------------------------------------------------------------------
1726 public void testToString() {
1727 StrBuilder sb = new StrBuilder("abc");
1728 assertEquals("abc", sb.toString());
1729 }
1730
1731 //-----------------------------------------------------------------------
1732 public void testToStringBuffer() {
1733 StrBuilder sb = new StrBuilder();
1734 assertEquals(new StringBuffer().toString(), sb.toStringBuffer().toString());
1735
1736 sb.append("junit");
1737 assertEquals(new StringBuffer("junit").toString(), sb.toStringBuffer().toString());
1738 }
1739
1740 //-----------------------------------------------------------------------
1741 public void testLang294() {
1742 StrBuilder sb = new StrBuilder("\n%BLAH%\nDo more stuff\neven more stuff\n%BLAH%\n");
1743 sb.deleteAll("\n%BLAH%");
1744 assertEquals("\nDo more stuff\neven more stuff\n", sb.toString());
1745 }
1746
1747 public void testIndexOfLang294() {
1748 StrBuilder sb = new StrBuilder("onetwothree");
1749 sb.deleteFirst("three");
1750 assertEquals(-1, sb.indexOf("three"));
1751 }
1752
1753 //-----------------------------------------------------------------------
1754 public void testLang295() {
1755 StrBuilder sb = new StrBuilder("onetwothree");
1756 sb.deleteFirst("three");
1757 assertFalse( "The contains(char) method is looking beyond the end of the string", sb.contains('h'));
1758 assertEquals( "The indexOf(char) method is looking beyond the end of the string", -1, sb.indexOf('h'));
1759 }
1760
1761 //-----------------------------------------------------------------------
1762 public void testLang412Right() {
1763 StrBuilder sb = new StrBuilder();
1764 sb.appendFixedWidthPadRight(null, 10, '*');
1765 assertEquals( "Failed to invoke appendFixedWidthPadRight correctly", "**********", sb.toString());
1766 }
1767
1768 public void testLang412Left() {
1769 StrBuilder sb = new StrBuilder();
1770 sb.appendFixedWidthPadLeft(null, 10, '*');
1771 assertEquals( "Failed to invoke appendFixedWidthPadLeft correctly", "**********", sb.toString());
1772 }
1773
1774 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text;
18
19 import java.util.HashMap;
20 import java.util.Map;
21
22 import junit.framework.TestCase;
23
24 /**
25 * Test class for StrLookup.
26 *
27 * @version $Id: StrLookupTest.java 1153484 2011-08-03 13:39:42Z ggregory $
28 */
29 public class StrLookupTest extends TestCase {
30
31 //-----------------------------------------------------------------------
32 public void testNoneLookup() {
33 assertEquals(null, StrLookup.noneLookup().lookup(null));
34 assertEquals(null, StrLookup.noneLookup().lookup(""));
35 assertEquals(null, StrLookup.noneLookup().lookup("any"));
36 }
37
38 public void testSystemProperiesLookup() {
39 assertEquals(System.getProperty("os.name"), StrLookup.systemPropertiesLookup().lookup("os.name"));
40 assertEquals(null, StrLookup.systemPropertiesLookup().lookup(""));
41 assertEquals(null, StrLookup.systemPropertiesLookup().lookup("other"));
42 try {
43 StrLookup.systemPropertiesLookup().lookup(null);
44 fail();
45 } catch (NullPointerException ex) {
46 // expected
47 }
48 }
49
50 public void testMapLookup() {
51 Map<String, Object> map = new HashMap<String, Object>();
52 map.put("key", "value");
53 map.put("number", Integer.valueOf(2));
54 assertEquals("value", StrLookup.mapLookup(map).lookup("key"));
55 assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
56 assertEquals(null, StrLookup.mapLookup(map).lookup(null));
57 assertEquals(null, StrLookup.mapLookup(map).lookup(""));
58 assertEquals(null, StrLookup.mapLookup(map).lookup("other"));
59 }
60
61 public void testMapLookup_nullMap() {
62 Map<String, ?> map = null;
63 assertEquals(null, StrLookup.mapLookup(map).lookup(null));
64 assertEquals(null, StrLookup.mapLookup(map).lookup(""));
65 assertEquals(null, StrLookup.mapLookup(map).lookup("any"));
66 }
67
68 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text;
18
19 import junit.framework.TestCase;
20
21 /**
22 * Unit tests for {@link org.apache.commons.lang3.text.StrMatcher}.
23 *
24 * @version $Id: StrMatcherTest.java 892118 2009-12-18 03:39:13Z sebb $
25 */
26 public class StrMatcherTest extends TestCase {
27
28 private static final char[] BUFFER1 = "0,1\t2 3\n\r\f\u0000'\"".toCharArray();
29
30 private static final char[] BUFFER2 = "abcdef".toCharArray();
31
32 /**
33 * Create a new test case with the specified name.
34 *
35 * @param name the name
36 */
37 public StrMatcherTest(String name) {
38 super(name);
39 }
40
41 //-----------------------------------------------------------------------
42 public void testCommaMatcher() {
43 StrMatcher matcher = StrMatcher.commaMatcher();
44 assertSame(matcher, StrMatcher.commaMatcher());
45 assertEquals(0, matcher.isMatch(BUFFER1, 0));
46 assertEquals(1, matcher.isMatch(BUFFER1, 1));
47 assertEquals(0, matcher.isMatch(BUFFER1, 2));
48 }
49
50 //-----------------------------------------------------------------------
51 public void testTabMatcher() {
52 StrMatcher matcher = StrMatcher.tabMatcher();
53 assertSame(matcher, StrMatcher.tabMatcher());
54 assertEquals(0, matcher.isMatch(BUFFER1, 2));
55 assertEquals(1, matcher.isMatch(BUFFER1, 3));
56 assertEquals(0, matcher.isMatch(BUFFER1, 4));
57 }
58
59 //-----------------------------------------------------------------------
60 public void testSpaceMatcher() {
61 StrMatcher matcher = StrMatcher.spaceMatcher();
62 assertSame(matcher, StrMatcher.spaceMatcher());
63 assertEquals(0, matcher.isMatch(BUFFER1, 4));
64 assertEquals(1, matcher.isMatch(BUFFER1, 5));
65 assertEquals(0, matcher.isMatch(BUFFER1, 6));
66 }
67
68 //-----------------------------------------------------------------------
69 public void testSplitMatcher() {
70 StrMatcher matcher = StrMatcher.splitMatcher();
71 assertSame(matcher, StrMatcher.splitMatcher());
72 assertEquals(0, matcher.isMatch(BUFFER1, 2));
73 assertEquals(1, matcher.isMatch(BUFFER1, 3));
74 assertEquals(0, matcher.isMatch(BUFFER1, 4));
75 assertEquals(1, matcher.isMatch(BUFFER1, 5));
76 assertEquals(0, matcher.isMatch(BUFFER1, 6));
77 assertEquals(1, matcher.isMatch(BUFFER1, 7));
78 assertEquals(1, matcher.isMatch(BUFFER1, 8));
79 assertEquals(1, matcher.isMatch(BUFFER1, 9));
80 assertEquals(0, matcher.isMatch(BUFFER1, 10));
81 }
82
83 //-----------------------------------------------------------------------
84 public void testTrimMatcher() {
85 StrMatcher matcher = StrMatcher.trimMatcher();
86 assertSame(matcher, StrMatcher.trimMatcher());
87 assertEquals(0, matcher.isMatch(BUFFER1, 2));
88 assertEquals(1, matcher.isMatch(BUFFER1, 3));
89 assertEquals(0, matcher.isMatch(BUFFER1, 4));
90 assertEquals(1, matcher.isMatch(BUFFER1, 5));
91 assertEquals(0, matcher.isMatch(BUFFER1, 6));
92 assertEquals(1, matcher.isMatch(BUFFER1, 7));
93 assertEquals(1, matcher.isMatch(BUFFER1, 8));
94 assertEquals(1, matcher.isMatch(BUFFER1, 9));
95 assertEquals(1, matcher.isMatch(BUFFER1, 10));
96 }
97
98 //-----------------------------------------------------------------------
99 public void testSingleQuoteMatcher() {
100 StrMatcher matcher = StrMatcher.singleQuoteMatcher();
101 assertSame(matcher, StrMatcher.singleQuoteMatcher());
102 assertEquals(0, matcher.isMatch(BUFFER1, 10));
103 assertEquals(1, matcher.isMatch(BUFFER1, 11));
104 assertEquals(0, matcher.isMatch(BUFFER1, 12));
105 }
106
107 //-----------------------------------------------------------------------
108 public void testDoubleQuoteMatcher() {
109 StrMatcher matcher = StrMatcher.doubleQuoteMatcher();
110 assertSame(matcher, StrMatcher.doubleQuoteMatcher());
111 assertEquals(0, matcher.isMatch(BUFFER1, 11));
112 assertEquals(1, matcher.isMatch(BUFFER1, 12));
113 }
114
115 //-----------------------------------------------------------------------
116 public void testQuoteMatcher() {
117 StrMatcher matcher = StrMatcher.quoteMatcher();
118 assertSame(matcher, StrMatcher.quoteMatcher());
119 assertEquals(0, matcher.isMatch(BUFFER1, 10));
120 assertEquals(1, matcher.isMatch(BUFFER1, 11));
121 assertEquals(1, matcher.isMatch(BUFFER1, 12));
122 }
123
124 //-----------------------------------------------------------------------
125 public void testNoneMatcher() {
126 StrMatcher matcher = StrMatcher.noneMatcher();
127 assertSame(matcher, StrMatcher.noneMatcher());
128 assertEquals(0, matcher.isMatch(BUFFER1, 0));
129 assertEquals(0, matcher.isMatch(BUFFER1, 1));
130 assertEquals(0, matcher.isMatch(BUFFER1, 2));
131 assertEquals(0, matcher.isMatch(BUFFER1, 3));
132 assertEquals(0, matcher.isMatch(BUFFER1, 4));
133 assertEquals(0, matcher.isMatch(BUFFER1, 5));
134 assertEquals(0, matcher.isMatch(BUFFER1, 6));
135 assertEquals(0, matcher.isMatch(BUFFER1, 7));
136 assertEquals(0, matcher.isMatch(BUFFER1, 8));
137 assertEquals(0, matcher.isMatch(BUFFER1, 9));
138 assertEquals(0, matcher.isMatch(BUFFER1, 10));
139 assertEquals(0, matcher.isMatch(BUFFER1, 11));
140 assertEquals(0, matcher.isMatch(BUFFER1, 12));
141 }
142
143 //-----------------------------------------------------------------------
144 public void testCharMatcher_char() {
145 StrMatcher matcher = StrMatcher.charMatcher('c');
146 assertEquals(0, matcher.isMatch(BUFFER2, 0));
147 assertEquals(0, matcher.isMatch(BUFFER2, 1));
148 assertEquals(1, matcher.isMatch(BUFFER2, 2));
149 assertEquals(0, matcher.isMatch(BUFFER2, 3));
150 assertEquals(0, matcher.isMatch(BUFFER2, 4));
151 assertEquals(0, matcher.isMatch(BUFFER2, 5));
152 }
153
154 //-----------------------------------------------------------------------
155 public void testCharSetMatcher_String() {
156 StrMatcher matcher = StrMatcher.charSetMatcher("ace");
157 assertEquals(1, matcher.isMatch(BUFFER2, 0));
158 assertEquals(0, matcher.isMatch(BUFFER2, 1));
159 assertEquals(1, matcher.isMatch(BUFFER2, 2));
160 assertEquals(0, matcher.isMatch(BUFFER2, 3));
161 assertEquals(1, matcher.isMatch(BUFFER2, 4));
162 assertEquals(0, matcher.isMatch(BUFFER2, 5));
163 assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher(""));
164 assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher((String) null));
165 assertTrue(StrMatcher.charSetMatcher("a") instanceof StrMatcher.CharMatcher);
166 }
167
168 //-----------------------------------------------------------------------
169 public void testCharSetMatcher_charArray() {
170 StrMatcher matcher = StrMatcher.charSetMatcher("ace".toCharArray());
171 assertEquals(1, matcher.isMatch(BUFFER2, 0));
172 assertEquals(0, matcher.isMatch(BUFFER2, 1));
173 assertEquals(1, matcher.isMatch(BUFFER2, 2));
174 assertEquals(0, matcher.isMatch(BUFFER2, 3));
175 assertEquals(1, matcher.isMatch(BUFFER2, 4));
176 assertEquals(0, matcher.isMatch(BUFFER2, 5));
177 assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher(new char[0]));
178 assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher((char[]) null));
179 assertTrue(StrMatcher.charSetMatcher("a".toCharArray()) instanceof StrMatcher.CharMatcher);
180 }
181
182 //-----------------------------------------------------------------------
183 public void testStringMatcher_String() {
184 StrMatcher matcher = StrMatcher.stringMatcher("bc");
185 assertEquals(0, matcher.isMatch(BUFFER2, 0));
186 assertEquals(2, matcher.isMatch(BUFFER2, 1));
187 assertEquals(0, matcher.isMatch(BUFFER2, 2));
188 assertEquals(0, matcher.isMatch(BUFFER2, 3));
189 assertEquals(0, matcher.isMatch(BUFFER2, 4));
190 assertEquals(0, matcher.isMatch(BUFFER2, 5));
191 assertSame(StrMatcher.noneMatcher(), StrMatcher.stringMatcher(""));
192 assertSame(StrMatcher.noneMatcher(), StrMatcher.stringMatcher((String) null));
193 }
194
195 //-----------------------------------------------------------------------
196 public void testMatcherIndices() {
197 // remember that the API contract is tight for the isMatch() method
198 // all the onus is on the caller, so invalid inputs are not
199 // the concern of StrMatcher, and are not bugs
200 StrMatcher matcher = StrMatcher.stringMatcher("bc");
201 assertEquals(2, matcher.isMatch(BUFFER2, 1, 1, BUFFER2.length));
202 assertEquals(2, matcher.isMatch(BUFFER2, 1, 0, 3));
203 assertEquals(0, matcher.isMatch(BUFFER2, 1, 0, 2));
204 }
205
206 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text;
18
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.Properties;
22
23 import junit.framework.TestCase;
24
25 import org.apache.commons.lang3.mutable.MutableObject;
26
27 /**
28 * Test class for StrSubstitutor.
29 *
30 * @version $Id: StrSubstitutorTest.java 1088899 2011-04-05 05:31:27Z bayard $
31 */
32 public class StrSubstitutorTest extends TestCase {
33
34 private Map<String, String> values;
35
36 @Override
37 protected void setUp() throws Exception {
38 super.setUp();
39 values = new HashMap<String, String>();
40 values.put("animal", "quick brown fox");
41 values.put("target", "lazy dog");
42 }
43
44 @Override
45 protected void tearDown() throws Exception {
46 super.tearDown();
47 values = null;
48 }
49
50 //-----------------------------------------------------------------------
51 /**
52 * Tests simple key replace.
53 */
54 public void testReplaceSimple() {
55 doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
56 }
57
58 /**
59 * Tests simple key replace.
60 */
61 public void testReplaceSolo() {
62 doTestReplace("quick brown fox", "${animal}", false);
63 }
64
65 /**
66 * Tests replace with no variables.
67 */
68 public void testReplaceNoVariables() {
69 doTestNoReplace("The balloon arrived.");
70 }
71
72 /**
73 * Tests replace with null.
74 */
75 public void testReplaceNull() {
76 doTestNoReplace(null);
77 }
78
79 /**
80 * Tests replace with null.
81 */
82 public void testReplaceEmpty() {
83 doTestNoReplace("");
84 }
85
86 /**
87 * Tests key replace changing map after initialization (not recommended).
88 */
89 public void testReplaceChangedMap() {
90 StrSubstitutor sub = new StrSubstitutor(values);
91 values.put("target", "moon");
92 assertEquals("The quick brown fox jumps over the moon.", sub.replace("The ${animal} jumps over the ${target}."));
93 }
94
95 /**
96 * Tests unknown key replace.
97 */
98 public void testReplaceUnknownKey() {
99 doTestReplace("The ${person} jumps over the lazy dog.", "The ${person} jumps over the ${target}.", true);
100 }
101
102 /**
103 * Tests adjacent keys.
104 */
105 public void testReplaceAdjacentAtStart() {
106 values.put("code", "GBP");
107 values.put("amount", "12.50");
108 StrSubstitutor sub = new StrSubstitutor(values);
109 assertEquals("GBP12.50 charged", sub.replace("${code}${amount} charged"));
110 }
111
112 /**
113 * Tests adjacent keys.
114 */
115 public void testReplaceAdjacentAtEnd() {
116 values.put("code", "GBP");
117 values.put("amount", "12.50");
118 StrSubstitutor sub = new StrSubstitutor(values);
119 assertEquals("Amount is GBP12.50", sub.replace("Amount is ${code}${amount}"));
120 }
121
122 /**
123 * Tests simple recursive replace.
124 */
125 public void testReplaceRecursive() {
126 values.put("animal", "${critter}");
127 values.put("target", "${pet}");
128 values.put("pet", "${petCharacteristic} dog");
129 values.put("petCharacteristic", "lazy");
130 values.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
131 values.put("critterSpeed", "quick");
132 values.put("critterColor", "brown");
133 values.put("critterType", "fox");
134 doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
135 }
136
137 /**
138 * Tests escaping.
139 */
140 public void testReplaceEscaping() {
141 doTestReplace("The ${animal} jumps over the lazy dog.", "The $${animal} jumps over the ${target}.", true);
142 }
143
144 /**
145 * Tests escaping.
146 */
147 public void testReplaceSoloEscaping() {
148 doTestReplace("${animal}", "$${animal}", false);
149 }
150
151 /**
152 * Tests complex escaping.
153 */
154 public void testReplaceComplexEscaping() {
155 doTestReplace("The ${quick brown fox} jumps over the lazy dog.", "The $${${animal}} jumps over the ${target}.", true);
156 }
157
158 /**
159 * Tests when no prefix or suffix.
160 */
161 public void testReplaceNoPefixNoSuffix() {
162 doTestReplace("The animal jumps over the lazy dog.", "The animal jumps over the ${target}.", true);
163 }
164
165 /**
166 * Tests when no incomplete prefix.
167 */
168 public void testReplaceIncompletePefix() {
169 doTestReplace("The {animal} jumps over the lazy dog.", "The {animal} jumps over the ${target}.", true);
170 }
171
172 /**
173 * Tests when prefix but no suffix.
174 */
175 public void testReplacePrefixNoSuffix() {
176 doTestReplace("The ${animal jumps over the ${target} lazy dog.", "The ${animal jumps over the ${target} ${target}.", true);
177 }
178
179 /**
180 * Tests when suffix but no prefix.
181 */
182 public void testReplaceNoPrefixSuffix() {
183 doTestReplace("The animal} jumps over the lazy dog.", "The animal} jumps over the ${target}.", true);
184 }
185
186 /**
187 * Tests when no variable name.
188 */
189 public void testReplaceEmptyKeys() {
190 doTestReplace("The ${} jumps over the lazy dog.", "The ${} jumps over the ${target}.", true);
191 }
192
193 /**
194 * Tests replace creates output same as input.
195 */
196 public void testReplaceToIdentical() {
197 values.put("animal", "$${${thing}}");
198 values.put("thing", "animal");
199 doTestReplace("The ${animal} jumps.", "The ${animal} jumps.", true);
200 }
201
202 /**
203 * Tests a cyclic replace operation.
204 * The cycle should be detected and cause an exception to be thrown.
205 */
206 public void testCyclicReplacement() {
207 Map<String, String> map = new HashMap<String, String>();
208 map.put("animal", "${critter}");
209 map.put("target", "${pet}");
210 map.put("pet", "${petCharacteristic} dog");
211 map.put("petCharacteristic", "lazy");
212 map.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
213 map.put("critterSpeed", "quick");
214 map.put("critterColor", "brown");
215 map.put("critterType", "${animal}");
216 StrSubstitutor sub = new StrSubstitutor(map);
217 try {
218 sub.replace("The ${animal} jumps over the ${target}.");
219 fail("Cyclic replacement was not detected!");
220 } catch (IllegalStateException ex) {
221 // expected
222 }
223 }
224
225 /**
226 * Tests interpolation with weird boundary patterns.
227 */
228 public void testReplaceWeirdPattens() {
229 doTestNoReplace("");
230 doTestNoReplace("${}");
231 doTestNoReplace("${ }");
232 doTestNoReplace("${\t}");
233 doTestNoReplace("${\n}");
234 doTestNoReplace("${\b}");
235 doTestNoReplace("${");
236 doTestNoReplace("$}");
237 doTestNoReplace("}");
238 doTestNoReplace("${}$");
239 doTestNoReplace("${${");
240 doTestNoReplace("${${}}");
241 doTestNoReplace("${$${}}");
242 doTestNoReplace("${$$${}}");
243 doTestNoReplace("${$$${$}}");
244 doTestNoReplace("${${}}");
245 doTestNoReplace("${${ }}");
246 }
247
248 /**
249 * Tests simple key replace.
250 */
251 public void testReplacePartialString_noReplace() {
252 StrSubstitutor sub = new StrSubstitutor();
253 assertEquals("${animal} jumps", sub.replace("The ${animal} jumps over the ${target}.", 4, 15));
254 }
255
256 /**
257 * Tests whether a variable can be replaced in a variable name.
258 */
259 public void testReplaceInVariable() {
260 values.put("animal.1", "fox");
261 values.put("animal.2", "mouse");
262 values.put("species", "2");
263 StrSubstitutor sub = new StrSubstitutor(values);
264 sub.setEnableSubstitutionInVariables(true);
265 assertEquals(
266 "Wrong result (1)",
267 "The mouse jumps over the lazy dog.",
268 sub.replace("The ${animal.${species}} jumps over the ${target}."));
269 values.put("species", "1");
270 assertEquals(
271 "Wrong result (2)",
272 "The fox jumps over the lazy dog.",
273 sub.replace("The ${animal.${species}} jumps over the ${target}."));
274 }
275
276 /**
277 * Tests whether substitution in variable names is disabled per default.
278 */
279 public void testReplaceInVariableDisabled() {
280 values.put("animal.1", "fox");
281 values.put("animal.2", "mouse");
282 values.put("species", "2");
283 StrSubstitutor sub = new StrSubstitutor(values);
284 assertEquals(
285 "Wrong result",
286 "The ${animal.${species}} jumps over the lazy dog.",
287 sub.replace("The ${animal.${species}} jumps over the ${target}."));
288 }
289
290 /**
291 * Tests complex and recursive substitution in variable names.
292 */
293 public void testReplaceInVariableRecursive() {
294 values.put("animal.2", "brown fox");
295 values.put("animal.1", "white mouse");
296 values.put("color", "white");
297 values.put("species.white", "1");
298 values.put("species.brown", "2");
299 StrSubstitutor sub = new StrSubstitutor(values);
300 sub.setEnableSubstitutionInVariables(true);
301 assertEquals(
302 "Wrong result",
303 "The white mouse jumps over the lazy dog.",
304 sub.replace("The ${animal.${species.${color}}} jumps over the ${target}."));
305 }
306
307 //-----------------------------------------------------------------------
308 /**
309 * Tests protected.
310 */
311 public void testResolveVariable() {
312 final StrBuilder builder = new StrBuilder("Hi ${name}!");
313 Map<String, String> map = new HashMap<String, String>();
314 map.put("name", "commons");
315 StrSubstitutor sub = new StrSubstitutor(map) {
316 @Override
317 protected String resolveVariable(String variableName, StrBuilder buf, int startPos, int endPos) {
318 assertEquals("name", variableName);
319 assertSame(builder, buf);
320 assertEquals(3, startPos);
321 assertEquals(10, endPos);
322 return "jakarta";
323 }
324 };
325 sub.replaceIn(builder);
326 assertEquals("Hi jakarta!", builder.toString());
327 }
328
329 //-----------------------------------------------------------------------
330 /**
331 * Tests constructor.
332 */
333 public void testConstructorNoArgs() {
334 StrSubstitutor sub = new StrSubstitutor();
335 assertEquals("Hi ${name}", sub.replace("Hi ${name}"));
336 }
337
338 /**
339 * Tests constructor.
340 */
341 public void testConstructorMapPrefixSuffix() {
342 Map<String, String> map = new HashMap<String, String>();
343 map.put("name", "commons");
344 StrSubstitutor sub = new StrSubstitutor(map, "<", ">");
345 assertEquals("Hi < commons", sub.replace("Hi $< <name>"));
346 }
347
348 /**
349 * Tests constructor.
350 */
351 public void testConstructorMapFull() {
352 Map<String, String> map = new HashMap<String, String>();
353 map.put("name", "commons");
354 StrSubstitutor sub = new StrSubstitutor(map, "<", ">", '!');
355 assertEquals("Hi < commons", sub.replace("Hi !< <name>"));
356 }
357
358 //-----------------------------------------------------------------------
359 /**
360 * Tests get set.
361 */
362 public void testGetSetEscape() {
363 StrSubstitutor sub = new StrSubstitutor();
364 assertEquals('$', sub.getEscapeChar());
365 sub.setEscapeChar('<');
366 assertEquals('<', sub.getEscapeChar());
367 }
368
369 /**
370 * Tests get set.
371 */
372 public void testGetSetPrefix() {
373 StrSubstitutor sub = new StrSubstitutor();
374 assertEquals(true, sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
375 sub.setVariablePrefix('<');
376 assertEquals(true, sub.getVariablePrefixMatcher() instanceof StrMatcher.CharMatcher);
377
378 sub.setVariablePrefix("<<");
379 assertEquals(true, sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
380 try {
381 sub.setVariablePrefix((String) null);
382 fail();
383 } catch (IllegalArgumentException ex) {
384 // expected
385 }
386 assertEquals(true, sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
387
388 StrMatcher matcher = StrMatcher.commaMatcher();
389 sub.setVariablePrefixMatcher(matcher);
390 assertSame(matcher, sub.getVariablePrefixMatcher());
391 try {
392 sub.setVariablePrefixMatcher((StrMatcher) null);
393 fail();
394 } catch (IllegalArgumentException ex) {
395 // expected
396 }
397 assertSame(matcher, sub.getVariablePrefixMatcher());
398 }
399
400 /**
401 * Tests get set.
402 */
403 public void testGetSetSuffix() {
404 StrSubstitutor sub = new StrSubstitutor();
405 assertEquals(true, sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
406 sub.setVariableSuffix('<');
407 assertEquals(true, sub.getVariableSuffixMatcher() instanceof StrMatcher.CharMatcher);
408
409 sub.setVariableSuffix("<<");
410 assertEquals(true, sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
411 try {
412 sub.setVariableSuffix((String) null);
413 fail();
414 } catch (IllegalArgumentException ex) {
415 // expected
416 }
417 assertEquals(true, sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
418
419 StrMatcher matcher = StrMatcher.commaMatcher();
420 sub.setVariableSuffixMatcher(matcher);
421 assertSame(matcher, sub.getVariableSuffixMatcher());
422 try {
423 sub.setVariableSuffixMatcher((StrMatcher) null);
424 fail();
425 } catch (IllegalArgumentException ex) {
426 // expected
427 }
428 assertSame(matcher, sub.getVariableSuffixMatcher());
429 }
430
431 //-----------------------------------------------------------------------
432 /**
433 * Tests static.
434 */
435 public void testStaticReplace() {
436 Map<String, String> map = new HashMap<String, String>();
437 map.put("name", "commons");
438 assertEquals("Hi commons!", StrSubstitutor.replace("Hi ${name}!", map));
439 }
440
441 /**
442 * Tests static.
443 */
444 public void testStaticReplacePrefixSuffix() {
445 Map<String, String> map = new HashMap<String, String>();
446 map.put("name", "commons");
447 assertEquals("Hi commons!", StrSubstitutor.replace("Hi <name>!", map, "<", ">"));
448 }
449
450 /**
451 * Tests interpolation with system properties.
452 */
453 public void testStaticReplaceSystemProperties() {
454 StrBuilder buf = new StrBuilder();
455 buf.append("Hi ").append(System.getProperty("user.name"));
456 buf.append(", you are working with ");
457 buf.append(System.getProperty("os.name"));
458 buf.append(", your home directory is ");
459 buf.append(System.getProperty("user.home")).append('.');
460 assertEquals(buf.toString(), StrSubstitutor.replaceSystemProperties("Hi ${user.name}, you are "
461 + "working with ${os.name}, your home "
462 + "directory is ${user.home}."));
463 }
464
465 /**
466 * Test the replace of a properties object
467 */
468 public void testSubstitutetDefaultProperties(){
469 String org = "${doesnotwork}";
470 System.setProperty("doesnotwork", "It work's!");
471
472 // create a new Properties object with the System.getProperties as default
473 Properties props = new Properties(System.getProperties());
474
475 assertEquals("It work's!",StrSubstitutor.replace(org, props));
476 }
477
478 //-----------------------------------------------------------------------
479 private void doTestReplace(String expectedResult, String replaceTemplate, boolean substring) {
480 String expectedShortResult = expectedResult.substring(1, expectedResult.length() - 1);
481 StrSubstitutor sub = new StrSubstitutor(values);
482
483 // replace using String
484 assertEquals(expectedResult, sub.replace(replaceTemplate));
485 if (substring) {
486 assertEquals(expectedShortResult, sub.replace(replaceTemplate, 1, replaceTemplate.length() - 2));
487 }
488
489 // replace using char[]
490 char[] chars = replaceTemplate.toCharArray();
491 assertEquals(expectedResult, sub.replace(chars));
492 if (substring) {
493 assertEquals(expectedShortResult, sub.replace(chars, 1, chars.length - 2));
494 }
495
496 // replace using StringBuffer
497 StringBuffer buf = new StringBuffer(replaceTemplate);
498 assertEquals(expectedResult, sub.replace(buf));
499 if (substring) {
500 assertEquals(expectedShortResult, sub.replace(buf, 1, buf.length() - 2));
501 }
502
503 // replace using StrBuilder
504 StrBuilder bld = new StrBuilder(replaceTemplate);
505 assertEquals(expectedResult, sub.replace(bld));
506 if (substring) {
507 assertEquals(expectedShortResult, sub.replace(bld, 1, bld.length() - 2));
508 }
509
510 // replace using object
511 MutableObject<String> obj = new MutableObject<String>(replaceTemplate); // toString returns template
512 assertEquals(expectedResult, sub.replace(obj));
513
514 // replace in StringBuffer
515 buf = new StringBuffer(replaceTemplate);
516 assertEquals(true, sub.replaceIn(buf));
517 assertEquals(expectedResult, buf.toString());
518 if (substring) {
519 buf = new StringBuffer(replaceTemplate);
520 assertEquals(true, sub.replaceIn(buf, 1, buf.length() - 2));
521 assertEquals(expectedResult, buf.toString()); // expect full result as remainder is untouched
522 }
523
524 // replace in StrBuilder
525 bld = new StrBuilder(replaceTemplate);
526 assertEquals(true, sub.replaceIn(bld));
527 assertEquals(expectedResult, bld.toString());
528 if (substring) {
529 bld = new StrBuilder(replaceTemplate);
530 assertEquals(true, sub.replaceIn(bld, 1, bld.length() - 2));
531 assertEquals(expectedResult, bld.toString()); // expect full result as remainder is untouched
532 }
533 }
534
535 private void doTestNoReplace(String replaceTemplate) {
536 StrSubstitutor sub = new StrSubstitutor(values);
537
538 if (replaceTemplate == null) {
539 assertEquals(null, sub.replace((String) null));
540 assertEquals(null, sub.replace((String) null, 0, 100));
541 assertEquals(null, sub.replace((char[]) null));
542 assertEquals(null, sub.replace((char[]) null, 0, 100));
543 assertEquals(null, sub.replace((StringBuffer) null));
544 assertEquals(null, sub.replace((StringBuffer) null, 0, 100));
545 assertEquals(null, sub.replace((StrBuilder) null));
546 assertEquals(null, sub.replace((StrBuilder) null, 0, 100));
547 assertEquals(null, sub.replace((Object) null));
548 assertEquals(false, sub.replaceIn((StringBuffer) null));
549 assertEquals(false, sub.replaceIn((StringBuffer) null, 0, 100));
550 assertEquals(false, sub.replaceIn((StrBuilder) null));
551 assertEquals(false, sub.replaceIn((StrBuilder) null, 0, 100));
552 } else {
553 assertEquals(replaceTemplate, sub.replace(replaceTemplate));
554 StrBuilder bld = new StrBuilder(replaceTemplate);
555 assertEquals(false, sub.replaceIn(bld));
556 assertEquals(replaceTemplate, bld.toString());
557 }
558 }
559
560 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text;
18
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.NoSuchElementException;
23
24 import junit.framework.TestCase;
25
26 import org.apache.commons.lang3.ArrayUtils;
27 import org.apache.commons.lang3.ObjectUtils;
28
29 /**
30 * Unit test for Tokenizer.
31 *
32 */
33 public class StrTokenizerTest extends TestCase {
34
35 private static final String CSV_SIMPLE_FIXTURE = "A,b,c";
36
37 private static final String TSV_SIMPLE_FIXTURE = "A\tb\tc";
38
39 /**
40 * JUnit constructor.
41 *
42 * @param name
43 */
44 public StrTokenizerTest(String name) {
45 super(name);
46 }
47
48 private void checkClone(StrTokenizer tokenizer) {
49 assertFalse(StrTokenizer.getCSVInstance() == tokenizer);
50 assertFalse(StrTokenizer.getTSVInstance() == tokenizer);
51 }
52
53 // -----------------------------------------------------------------------
54 public void test1() {
55
56 String input = "a;b;c;\"d;\"\"e\";f; ; ; ";
57 StrTokenizer tok = new StrTokenizer(input);
58 tok.setDelimiterChar(';');
59 tok.setQuoteChar('"');
60 tok.setIgnoredMatcher(StrMatcher.trimMatcher());
61 tok.setIgnoreEmptyTokens(false);
62 String tokens[] = tok.getTokenArray();
63
64 String expected[] = new String[]{"a", "b", "c", "d;\"e", "f", "", "", "",};
65
66 assertEquals(ArrayUtils.toString(tokens), expected.length, tokens.length);
67 for (int i = 0; i < expected.length; i++) {
68 assertTrue("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
69 ObjectUtils.equals(expected[i], tokens[i]));
70 }
71
72 }
73
74 public void test2() {
75
76 String input = "a;b;c ;\"d;\"\"e\";f; ; ;";
77 StrTokenizer tok = new StrTokenizer(input);
78 tok.setDelimiterChar(';');
79 tok.setQuoteChar('"');
80 tok.setIgnoredMatcher(StrMatcher.noneMatcher());
81 tok.setIgnoreEmptyTokens(false);
82 String tokens[] = tok.getTokenArray();
83
84 String expected[] = new String[]{"a", "b", "c ", "d;\"e", "f", " ", " ", "",};
85
86 assertEquals(ArrayUtils.toString(tokens), expected.length, tokens.length);
87 for (int i = 0; i < expected.length; i++) {
88 assertTrue("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
89 ObjectUtils.equals(expected[i], tokens[i]));
90 }
91
92 }
93
94 public void test3() {
95
96 String input = "a;b; c;\"d;\"\"e\";f; ; ;";
97 StrTokenizer tok = new StrTokenizer(input);
98 tok.setDelimiterChar(';');
99 tok.setQuoteChar('"');
100 tok.setIgnoredMatcher(StrMatcher.noneMatcher());
101 tok.setIgnoreEmptyTokens(false);
102 String tokens[] = tok.getTokenArray();
103
104 String expected[] = new String[]{"a", "b", " c", "d;\"e", "f", " ", " ", "",};
105
106 assertEquals(ArrayUtils.toString(tokens), expected.length, tokens.length);
107 for (int i = 0; i < expected.length; i++) {
108 assertTrue("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
109 ObjectUtils.equals(expected[i], tokens[i]));
110 }
111
112 }
113
114 public void test4() {
115
116 String input = "a;b; c;\"d;\"\"e\";f; ; ;";
117 StrTokenizer tok = new StrTokenizer(input);
118 tok.setDelimiterChar(';');
119 tok.setQuoteChar('"');
120 tok.setIgnoredMatcher(StrMatcher.trimMatcher());
121 tok.setIgnoreEmptyTokens(true);
122 String tokens[] = tok.getTokenArray();
123
124 String expected[] = new String[]{"a", "b", "c", "d;\"e", "f",};
125
126 assertEquals(ArrayUtils.toString(tokens), expected.length, tokens.length);
127 for (int i = 0; i < expected.length; i++) {
128 assertTrue("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
129 ObjectUtils.equals(expected[i], tokens[i]));
130 }
131
132 }
133
134 public void test5() {
135
136 String input = "a;b; c;\"d;\"\"e\";f; ; ;";
137 StrTokenizer tok = new StrTokenizer(input);
138 tok.setDelimiterChar(';');
139 tok.setQuoteChar('"');
140 tok.setIgnoredMatcher(StrMatcher.trimMatcher());
141 tok.setIgnoreEmptyTokens(false);
142 tok.setEmptyTokenAsNull(true);
143 String tokens[] = tok.getTokenArray();
144
145 String expected[] = new String[]{"a", "b", "c", "d;\"e", "f", null, null, null,};
146
147 assertEquals(ArrayUtils.toString(tokens), expected.length, tokens.length);
148 for (int i = 0; i < expected.length; i++) {
149 assertTrue("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
150 ObjectUtils.equals(expected[i], tokens[i]));
151 }
152
153 }
154
155 public void test6() {
156
157 String input = "a;b; c;\"d;\"\"e\";f; ; ;";
158 StrTokenizer tok = new StrTokenizer(input);
159 tok.setDelimiterChar(';');
160 tok.setQuoteChar('"');
161 tok.setIgnoredMatcher(StrMatcher.trimMatcher());
162 tok.setIgnoreEmptyTokens(false);
163 // tok.setTreatingEmptyAsNull(true);
164 String tokens[] = tok.getTokenArray();
165
166 String expected[] = new String[]{"a", "b", " c", "d;\"e", "f", null, null, null,};
167
168 int nextCount = 0;
169 while (tok.hasNext()) {
170 tok.next();
171 nextCount++;
172 }
173
174 int prevCount = 0;
175 while (tok.hasPrevious()) {
176 tok.previous();
177 prevCount++;
178 }
179
180 assertEquals(ArrayUtils.toString(tokens), expected.length, tokens.length);
181
182 assertTrue("could not cycle through entire token list" + " using the 'hasNext' and 'next' methods",
183 nextCount == expected.length);
184
185 assertTrue("could not cycle through entire token list" + " using the 'hasPrevious' and 'previous' methods",
186 prevCount == expected.length);
187
188 }
189
190 public void test7() {
191
192 String input = "a b c \"d e\" f ";
193 StrTokenizer tok = new StrTokenizer(input);
194 tok.setDelimiterMatcher(StrMatcher.spaceMatcher());
195 tok.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
196 tok.setIgnoredMatcher(StrMatcher.noneMatcher());
197 tok.setIgnoreEmptyTokens(false);
198 String tokens[] = tok.getTokenArray();
199
200 String expected[] = new String[]{"a", "", "", "b", "c", "d e", "f", "",};
201
202 assertEquals(ArrayUtils.toString(tokens), expected.length, tokens.length);
203 for (int i = 0; i < expected.length; i++) {
204 assertTrue("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
205 ObjectUtils.equals(expected[i], tokens[i]));
206 }
207
208 }
209
210 public void test8() {
211
212 String input = "a b c \"d e\" f ";
213 StrTokenizer tok = new StrTokenizer(input);
214 tok.setDelimiterMatcher(StrMatcher.spaceMatcher());
215 tok.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
216 tok.setIgnoredMatcher(StrMatcher.noneMatcher());
217 tok.setIgnoreEmptyTokens(true);
218 String tokens[] = tok.getTokenArray();
219
220 String expected[] = new String[]{"a", "b", "c", "d e", "f",};
221
222 assertEquals(ArrayUtils.toString(tokens), expected.length, tokens.length);
223 for (int i = 0; i < expected.length; i++) {
224 assertTrue("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
225 ObjectUtils.equals(expected[i], tokens[i]));
226 }
227
228 }
229
230 public void testBasic1() {
231 String input = "a b c";
232 StrTokenizer tok = new StrTokenizer(input);
233 assertEquals("a", tok.next());
234 assertEquals("b", tok.next());
235 assertEquals("c", tok.next());
236 assertEquals(false, tok.hasNext());
237 }
238
239 public void testBasic2() {
240 String input = "a \nb\fc";
241 StrTokenizer tok = new StrTokenizer(input);
242 assertEquals("a", tok.next());
243 assertEquals("b", tok.next());
244 assertEquals("c", tok.next());
245 assertEquals(false, tok.hasNext());
246 }
247
248 public void testBasic3() {
249 String input = "a \nb\u0001\fc";
250 StrTokenizer tok = new StrTokenizer(input);
251 assertEquals("a", tok.next());
252 assertEquals("b\u0001", tok.next());
253 assertEquals("c", tok.next());
254 assertEquals(false, tok.hasNext());
255 }
256
257 public void testBasic4() {
258 String input = "a \"b\" c";
259 StrTokenizer tok = new StrTokenizer(input);
260 assertEquals("a", tok.next());
261 assertEquals("\"b\"", tok.next());
262 assertEquals("c", tok.next());
263 assertEquals(false, tok.hasNext());
264 }
265
266 public void testBasic5() {
267 String input = "a:b':c";
268 StrTokenizer tok = new StrTokenizer(input, ':', '\'');
269 assertEquals("a", tok.next());
270 assertEquals("b'", tok.next());
271 assertEquals("c", tok.next());
272 assertEquals(false, tok.hasNext());
273 }
274
275 public void testBasicDelim1() {
276 String input = "a:b:c";
277 StrTokenizer tok = new StrTokenizer(input, ':');
278 assertEquals("a", tok.next());
279 assertEquals("b", tok.next());
280 assertEquals("c", tok.next());
281 assertEquals(false, tok.hasNext());
282 }
283
284 public void testBasicDelim2() {
285 String input = "a:b:c";
286 StrTokenizer tok = new StrTokenizer(input, ',');
287 assertEquals("a:b:c", tok.next());
288 assertEquals(false, tok.hasNext());
289 }
290
291 public void testBasicEmpty1() {
292 String input = "a b c";
293 StrTokenizer tok = new StrTokenizer(input);
294 tok.setIgnoreEmptyTokens(false);
295 assertEquals("a", tok.next());
296 assertEquals("", tok.next());
297 assertEquals("b", tok.next());
298 assertEquals("c", tok.next());
299 assertEquals(false, tok.hasNext());
300 }
301
302 public void testBasicEmpty2() {
303 String input = "a b c";
304 StrTokenizer tok = new StrTokenizer(input);
305 tok.setIgnoreEmptyTokens(false);
306 tok.setEmptyTokenAsNull(true);
307 assertEquals("a", tok.next());
308 assertEquals(null, tok.next());
309 assertEquals("b", tok.next());
310 assertEquals("c", tok.next());
311 assertEquals(false, tok.hasNext());
312 }
313
314 public void testBasicQuoted1() {
315 String input = "a 'b' c";
316 StrTokenizer tok = new StrTokenizer(input, ' ', '\'');
317 assertEquals("a", tok.next());
318 assertEquals("b", tok.next());
319 assertEquals("c", tok.next());
320 assertEquals(false, tok.hasNext());
321 }
322
323 public void testBasicQuoted2() {
324 String input = "a:'b':";
325 StrTokenizer tok = new StrTokenizer(input, ':', '\'');
326 tok.setIgnoreEmptyTokens(false);
327 tok.setEmptyTokenAsNull(true);
328 assertEquals("a", tok.next());
329 assertEquals("b", tok.next());
330 assertEquals(null, tok.next());
331 assertEquals(false, tok.hasNext());
332 }
333
334 public void testBasicQuoted3() {
335 String input = "a:'b''c'";
336 StrTokenizer tok = new StrTokenizer(input, ':', '\'');
337 tok.setIgnoreEmptyTokens(false);
338 tok.setEmptyTokenAsNull(true);
339 assertEquals("a", tok.next());
340 assertEquals("b'c", tok.next());
341 assertEquals(false, tok.hasNext());
342 }
343
344 public void testBasicQuoted4() {
345 String input = "a: 'b' 'c' :d";
346 StrTokenizer tok = new StrTokenizer(input, ':', '\'');
347 tok.setTrimmerMatcher(StrMatcher.trimMatcher());
348 tok.setIgnoreEmptyTokens(false);
349 tok.setEmptyTokenAsNull(true);
350 assertEquals("a", tok.next());
351 assertEquals("b c", tok.next());
352 assertEquals("d", tok.next());
353 assertEquals(false, tok.hasNext());
354 }
355
356 public void testBasicQuoted5() {
357 String input = "a: 'b'x'c' :d";
358 StrTokenizer tok = new StrTokenizer(input, ':', '\'');
359 tok.setTrimmerMatcher(StrMatcher.trimMatcher());
360 tok.setIgnoreEmptyTokens(false);
361 tok.setEmptyTokenAsNull(true);
362 assertEquals("a", tok.next());
363 assertEquals("bxc", tok.next());
364 assertEquals("d", tok.next());
365 assertEquals(false, tok.hasNext());
366 }
367
368 public void testBasicQuoted6() {
369 String input = "a:'b'\"c':d";
370 StrTokenizer tok = new StrTokenizer(input, ':');
371 tok.setQuoteMatcher(StrMatcher.quoteMatcher());
372 assertEquals("a", tok.next());
373 assertEquals("b\"c:d", tok.next());
374 assertEquals(false, tok.hasNext());
375 }
376
377 public void testBasicQuoted7() {
378 String input = "a:\"There's a reason here\":b";
379 StrTokenizer tok = new StrTokenizer(input, ':');
380 tok.setQuoteMatcher(StrMatcher.quoteMatcher());
381 assertEquals("a", tok.next());
382 assertEquals("There's a reason here", tok.next());
383 assertEquals("b", tok.next());
384 assertEquals(false, tok.hasNext());
385 }
386
387 public void testBasicQuotedTrimmed1() {
388 String input = "a: 'b' :";
389 StrTokenizer tok = new StrTokenizer(input, ':', '\'');
390 tok.setTrimmerMatcher(StrMatcher.trimMatcher());
391 tok.setIgnoreEmptyTokens(false);
392 tok.setEmptyTokenAsNull(true);
393 assertEquals("a", tok.next());
394 assertEquals("b", tok.next());
395 assertEquals(null, tok.next());
396 assertEquals(false, tok.hasNext());
397 }
398
399 public void testBasicTrimmed1() {
400 String input = "a: b : ";
401 StrTokenizer tok = new StrTokenizer(input, ':');
402 tok.setTrimmerMatcher(StrMatcher.trimMatcher());
403 tok.setIgnoreEmptyTokens(false);
404 tok.setEmptyTokenAsNull(true);
405 assertEquals("a", tok.next());
406 assertEquals("b", tok.next());
407 assertEquals(null, tok.next());
408 assertEquals(false, tok.hasNext());
409 }
410
411 public void testBasicTrimmed2() {
412 String input = "a: b :";
413 StrTokenizer tok = new StrTokenizer(input, ':');
414 tok.setTrimmerMatcher(StrMatcher.stringMatcher(" "));
415 tok.setIgnoreEmptyTokens(false);
416 tok.setEmptyTokenAsNull(true);
417 assertEquals("a", tok.next());
418 assertEquals("b", tok.next());
419 assertEquals(null, tok.next());
420 assertEquals(false, tok.hasNext());
421 }
422
423 public void testBasicIgnoreTrimmed1() {
424 String input = "a: bIGNOREc : ";
425 StrTokenizer tok = new StrTokenizer(input, ':');
426 tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
427 tok.setTrimmerMatcher(StrMatcher.trimMatcher());
428 tok.setIgnoreEmptyTokens(false);
429 tok.setEmptyTokenAsNull(true);
430 assertEquals("a", tok.next());
431 assertEquals("bc", tok.next());
432 assertEquals(null, tok.next());
433 assertEquals(false, tok.hasNext());
434 }
435
436 public void testBasicIgnoreTrimmed2() {
437 String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
438 StrTokenizer tok = new StrTokenizer(input, ':');
439 tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
440 tok.setTrimmerMatcher(StrMatcher.trimMatcher());
441 tok.setIgnoreEmptyTokens(false);
442 tok.setEmptyTokenAsNull(true);
443 assertEquals("a", tok.next());
444 assertEquals("bc", tok.next());
445 assertEquals(null, tok.next());
446 assertEquals(false, tok.hasNext());
447 }
448
449 public void testBasicIgnoreTrimmed3() {
450 String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
451 StrTokenizer tok = new StrTokenizer(input, ':');
452 tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
453 tok.setIgnoreEmptyTokens(false);
454 tok.setEmptyTokenAsNull(true);
455 assertEquals("a", tok.next());
456 assertEquals(" bc ", tok.next());
457 assertEquals(" ", tok.next());
458 assertEquals(false, tok.hasNext());
459 }
460
461 public void testBasicIgnoreTrimmed4() {
462 String input = "IGNOREaIGNORE: IGNORE 'bIGNOREc'IGNORE'd' IGNORE : IGNORE ";
463 StrTokenizer tok = new StrTokenizer(input, ':', '\'');
464 tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
465 tok.setTrimmerMatcher(StrMatcher.trimMatcher());
466 tok.setIgnoreEmptyTokens(false);
467 tok.setEmptyTokenAsNull(true);
468 assertEquals("a", tok.next());
469 assertEquals("bIGNOREcd", tok.next());
470 assertEquals(null, tok.next());
471 assertEquals(false, tok.hasNext());
472 }
473
474 //-----------------------------------------------------------------------
475 public void testListArray() {
476 String input = "a b c";
477 StrTokenizer tok = new StrTokenizer(input);
478 String[] array = tok.getTokenArray();
479 List<?> list = tok.getTokenList();
480
481 assertEquals(Arrays.asList(array), list);
482 assertEquals(3, list.size());
483 }
484
485 //-----------------------------------------------------------------------
486 public void testCSV(String data) {
487 this.testXSVAbc(StrTokenizer.getCSVInstance(data));
488 this.testXSVAbc(StrTokenizer.getCSVInstance(data.toCharArray()));
489 }
490
491 public void testCSVEmpty() {
492 this.testEmpty(StrTokenizer.getCSVInstance());
493 this.testEmpty(StrTokenizer.getCSVInstance(""));
494 }
495
496 public void testCSVSimple() {
497 this.testCSV(CSV_SIMPLE_FIXTURE);
498 }
499
500 public void testCSVSimpleNeedsTrim() {
501 this.testCSV(" " + CSV_SIMPLE_FIXTURE);
502 this.testCSV(" \n\t " + CSV_SIMPLE_FIXTURE);
503 this.testCSV(" \n " + CSV_SIMPLE_FIXTURE + "\n\n\r");
504 }
505
506 void testEmpty(StrTokenizer tokenizer) {
507 this.checkClone(tokenizer);
508 assertEquals(false, tokenizer.hasNext());
509 assertEquals(false, tokenizer.hasPrevious());
510 assertEquals(null, tokenizer.nextToken());
511 assertEquals(0, tokenizer.size());
512 try {
513 tokenizer.next();
514 fail();
515 } catch (NoSuchElementException ex) {}
516 }
517
518 public void testGetContent() {
519 String input = "a b c \"d e\" f ";
520 StrTokenizer tok = new StrTokenizer(input);
521 assertEquals(input, tok.getContent());
522
523 tok = new StrTokenizer(input.toCharArray());
524 assertEquals(input, tok.getContent());
525
526 tok = new StrTokenizer();
527 assertEquals(null, tok.getContent());
528 }
529
530 //-----------------------------------------------------------------------
531 public void testChaining() {
532 StrTokenizer tok = new StrTokenizer();
533 assertEquals(tok, tok.reset());
534 assertEquals(tok, tok.reset(""));
535 assertEquals(tok, tok.reset(new char[0]));
536 assertEquals(tok, tok.setDelimiterChar(' '));
537 assertEquals(tok, tok.setDelimiterString(" "));
538 assertEquals(tok, tok.setDelimiterMatcher(null));
539 assertEquals(tok, tok.setQuoteChar(' '));
540 assertEquals(tok, tok.setQuoteMatcher(null));
541 assertEquals(tok, tok.setIgnoredChar(' '));
542 assertEquals(tok, tok.setIgnoredMatcher(null));
543 assertEquals(tok, tok.setTrimmerMatcher(null));
544 assertEquals(tok, tok.setEmptyTokenAsNull(false));
545 assertEquals(tok, tok.setIgnoreEmptyTokens(false));
546 }
547
548 /**
549 * Tests that the {@link StrTokenizer#clone()} clone method catches {@link CloneNotSupportedException} and returns
550 * <code>null</code>.
551 */
552 public void testCloneNotSupportedException() {
553 Object notCloned = (new StrTokenizer() {
554 @Override
555 Object cloneReset() throws CloneNotSupportedException {
556 throw new CloneNotSupportedException("test");
557 }
558 }).clone();
559 assertNull(notCloned);
560 }
561
562 public void testCloneNull() {
563 StrTokenizer tokenizer = new StrTokenizer((char[]) null);
564 // Start sanity check
565 assertEquals(null, tokenizer.nextToken());
566 tokenizer.reset();
567 assertEquals(null, tokenizer.nextToken());
568 // End sanity check
569 StrTokenizer clonedTokenizer = (StrTokenizer) tokenizer.clone();
570 tokenizer.reset();
571 assertEquals(null, tokenizer.nextToken());
572 assertEquals(null, clonedTokenizer.nextToken());
573 }
574
575 public void testCloneReset() {
576 char[] input = new char[]{'a'};
577 StrTokenizer tokenizer = new StrTokenizer(input);
578 // Start sanity check
579 assertEquals("a", tokenizer.nextToken());
580 tokenizer.reset(input);
581 assertEquals("a", tokenizer.nextToken());
582 // End sanity check
583 StrTokenizer clonedTokenizer = (StrTokenizer) tokenizer.clone();
584 input[0] = 'b';
585 tokenizer.reset(input);
586 assertEquals("b", tokenizer.nextToken());
587 assertEquals("a", clonedTokenizer.nextToken());
588 }
589
590 // -----------------------------------------------------------------------
591 public void testConstructor_String() {
592 StrTokenizer tok = new StrTokenizer("a b");
593 assertEquals("a", tok.next());
594 assertEquals("b", tok.next());
595 assertEquals(false, tok.hasNext());
596
597 tok = new StrTokenizer("");
598 assertEquals(false, tok.hasNext());
599
600 tok = new StrTokenizer((String) null);
601 assertEquals(false, tok.hasNext());
602 }
603
604 //-----------------------------------------------------------------------
605 public void testConstructor_String_char() {
606 StrTokenizer tok = new StrTokenizer("a b", ' ');
607 assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
608 assertEquals("a", tok.next());
609 assertEquals("b", tok.next());
610 assertEquals(false, tok.hasNext());
611
612 tok = new StrTokenizer("", ' ');
613 assertEquals(false, tok.hasNext());
614
615 tok = new StrTokenizer((String) null, ' ');
616 assertEquals(false, tok.hasNext());
617 }
618
619 //-----------------------------------------------------------------------
620 public void testConstructor_String_char_char() {
621 StrTokenizer tok = new StrTokenizer("a b", ' ', '"');
622 assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
623 assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1));
624 assertEquals("a", tok.next());
625 assertEquals("b", tok.next());
626 assertEquals(false, tok.hasNext());
627
628 tok = new StrTokenizer("", ' ', '"');
629 assertEquals(false, tok.hasNext());
630
631 tok = new StrTokenizer((String) null, ' ', '"');
632 assertEquals(false, tok.hasNext());
633 }
634
635 //-----------------------------------------------------------------------
636 public void testConstructor_charArray() {
637 StrTokenizer tok = new StrTokenizer("a b".toCharArray());
638 assertEquals("a", tok.next());
639 assertEquals("b", tok.next());
640 assertEquals(false, tok.hasNext());
641
642 tok = new StrTokenizer(new char[0]);
643 assertEquals(false, tok.hasNext());
644
645 tok = new StrTokenizer((char[]) null);
646 assertEquals(false, tok.hasNext());
647 }
648
649 //-----------------------------------------------------------------------
650 public void testConstructor_charArray_char() {
651 StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ');
652 assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
653 assertEquals("a", tok.next());
654 assertEquals("b", tok.next());
655 assertEquals(false, tok.hasNext());
656
657 tok = new StrTokenizer(new char[0], ' ');
658 assertEquals(false, tok.hasNext());
659
660 tok = new StrTokenizer((char[]) null, ' ');
661 assertEquals(false, tok.hasNext());
662 }
663
664 //-----------------------------------------------------------------------
665 public void testConstructor_charArray_char_char() {
666 StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ', '"');
667 assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
668 assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1));
669 assertEquals("a", tok.next());
670 assertEquals("b", tok.next());
671 assertEquals(false, tok.hasNext());
672
673 tok = new StrTokenizer(new char[0], ' ', '"');
674 assertEquals(false, tok.hasNext());
675
676 tok = new StrTokenizer((char[]) null, ' ', '"');
677 assertEquals(false, tok.hasNext());
678 }
679
680 //-----------------------------------------------------------------------
681 public void testReset() {
682 StrTokenizer tok = new StrTokenizer("a b c");
683 assertEquals("a", tok.next());
684 assertEquals("b", tok.next());
685 assertEquals("c", tok.next());
686 assertEquals(false, tok.hasNext());
687
688 tok.reset();
689 assertEquals("a", tok.next());
690 assertEquals("b", tok.next());
691 assertEquals("c", tok.next());
692 assertEquals(false, tok.hasNext());
693 }
694
695 //-----------------------------------------------------------------------
696 public void testReset_String() {
697 StrTokenizer tok = new StrTokenizer("x x x");
698 tok.reset("d e");
699 assertEquals("d", tok.next());
700 assertEquals("e", tok.next());
701 assertEquals(false, tok.hasNext());
702
703 tok.reset((String) null);
704 assertEquals(false, tok.hasNext());
705 }
706
707 //-----------------------------------------------------------------------
708 public void testReset_charArray() {
709 StrTokenizer tok = new StrTokenizer("x x x");
710
711 char[] array = new char[] {'a', 'b', 'c'};
712 tok.reset(array);
713 assertEquals("abc", tok.next());
714 assertEquals(false, tok.hasNext());
715
716 tok.reset((char[]) null);
717 assertEquals(false, tok.hasNext());
718 }
719
720 //-----------------------------------------------------------------------
721 public void testTSV() {
722 this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE));
723 this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE.toCharArray()));
724 }
725
726 public void testTSVEmpty() {
727 this.testEmpty(StrTokenizer.getCSVInstance());
728 this.testEmpty(StrTokenizer.getCSVInstance(""));
729 }
730
731 void testXSVAbc(StrTokenizer tokenizer) {
732 this.checkClone(tokenizer);
733 assertEquals(-1, tokenizer.previousIndex());
734 assertEquals(0, tokenizer.nextIndex());
735 assertEquals(null, tokenizer.previousToken());
736 assertEquals("A", tokenizer.nextToken());
737 assertEquals(1, tokenizer.nextIndex());
738 assertEquals("b", tokenizer.nextToken());
739 assertEquals(2, tokenizer.nextIndex());
740 assertEquals("c", tokenizer.nextToken());
741 assertEquals(3, tokenizer.nextIndex());
742 assertEquals(null, tokenizer.nextToken());
743 assertEquals(3, tokenizer.nextIndex());
744 assertEquals("c", tokenizer.previousToken());
745 assertEquals(2, tokenizer.nextIndex());
746 assertEquals("b", tokenizer.previousToken());
747 assertEquals(1, tokenizer.nextIndex());
748 assertEquals("A", tokenizer.previousToken());
749 assertEquals(0, tokenizer.nextIndex());
750 assertEquals(null, tokenizer.previousToken());
751 assertEquals(0, tokenizer.nextIndex());
752 assertEquals(-1, tokenizer.previousIndex());
753 assertEquals(3, tokenizer.size());
754 }
755
756 public void testIteration() {
757 StrTokenizer tkn = new StrTokenizer("a b c");
758 assertEquals(false, tkn.hasPrevious());
759 try {
760 tkn.previous();
761 fail();
762 } catch (NoSuchElementException ex) {}
763 assertEquals(true, tkn.hasNext());
764
765 assertEquals("a", tkn.next());
766 try {
767 tkn.remove();
768 fail();
769 } catch (UnsupportedOperationException ex) {}
770 try {
771 tkn.set("x");
772 fail();
773 } catch (UnsupportedOperationException ex) {}
774 try {
775 tkn.add("y");
776 fail();
777 } catch (UnsupportedOperationException ex) {}
778 assertEquals(true, tkn.hasPrevious());
779 assertEquals(true, tkn.hasNext());
780
781 assertEquals("b", tkn.next());
782 assertEquals(true, tkn.hasPrevious());
783 assertEquals(true, tkn.hasNext());
784
785 assertEquals("c", tkn.next());
786 assertEquals(true, tkn.hasPrevious());
787 assertEquals(false, tkn.hasNext());
788
789 try {
790 tkn.next();
791 fail();
792 } catch (NoSuchElementException ex) {}
793 assertEquals(true, tkn.hasPrevious());
794 assertEquals(false, tkn.hasNext());
795 }
796
797 //-----------------------------------------------------------------------
798 public void testTokenizeSubclassInputChange() {
799 StrTokenizer tkn = new StrTokenizer("a b c d e") {
800 @Override
801 protected List<String> tokenize(char[] chars, int offset, int count) {
802 return super.tokenize("w x y z".toCharArray(), 2, 5);
803 }
804 };
805 assertEquals("x", tkn.next());
806 assertEquals("y", tkn.next());
807 }
808
809 //-----------------------------------------------------------------------
810 public void testTokenizeSubclassOutputChange() {
811 StrTokenizer tkn = new StrTokenizer("a b c") {
812 @Override
813 protected List<String> tokenize(char[] chars, int offset, int count) {
814 List<String> list = super.tokenize(chars, offset, count);
815 Collections.reverse(list);
816 return list;
817 }
818 };
819 assertEquals("c", tkn.next());
820 assertEquals("b", tkn.next());
821 assertEquals("a", tkn.next());
822 }
823
824 //-----------------------------------------------------------------------
825 public void testToString() {
826 StrTokenizer tkn = new StrTokenizer("a b c d e");
827 assertEquals("StrTokenizer[not tokenized yet]", tkn.toString());
828 tkn.next();
829 assertEquals("StrTokenizer[a, b, c, d, e]", tkn.toString());
830 }
831
832 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.text;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.Modifier;
20
21 import junit.framework.TestCase;
22
23 /**
24 * Unit tests for WordUtils class.
25 *
26 * @version $Id: WordUtilsTest.java 1088899 2011-04-05 05:31:27Z bayard $
27 */
28 public class WordUtilsTest extends TestCase {
29
30 public WordUtilsTest(String name) {
31 super(name);
32 }
33
34 //-----------------------------------------------------------------------
35 public void testConstructor() {
36 assertNotNull(new WordUtils());
37 Constructor<?>[] cons = WordUtils.class.getDeclaredConstructors();
38 assertEquals(1, cons.length);
39 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
40 assertEquals(true, Modifier.isPublic(WordUtils.class.getModifiers()));
41 assertEquals(false, Modifier.isFinal(WordUtils.class.getModifiers()));
42 }
43
44 //-----------------------------------------------------------------------
45 public void testWrap_StringInt() {
46 assertEquals(null, WordUtils.wrap(null, 20));
47 assertEquals(null, WordUtils.wrap(null, -1));
48
49 assertEquals("", WordUtils.wrap("", 20));
50 assertEquals("", WordUtils.wrap("", -1));
51
52 // normal
53 String systemNewLine = System.getProperty("line.separator");
54 String input = "Here is one line of text that is going to be wrapped after 20 columns.";
55 String expected = "Here is one line of" + systemNewLine + "text that is going"
56 + systemNewLine + "to be wrapped after" + systemNewLine + "20 columns.";
57 assertEquals(expected, WordUtils.wrap(input, 20));
58
59 // long word at end
60 input = "Click here to jump to the jakarta website - http://jakarta.apache.org";
61 expected = "Click here to jump" + systemNewLine + "to the jakarta" + systemNewLine
62 + "website -" + systemNewLine + "http://jakarta.apache.org";
63 assertEquals(expected, WordUtils.wrap(input, 20));
64
65 // long word in middle
66 input = "Click here, http://jakarta.apache.org, to jump to the jakarta website";
67 expected = "Click here," + systemNewLine + "http://jakarta.apache.org," + systemNewLine
68 + "to jump to the" + systemNewLine + "jakarta website";
69 assertEquals(expected, WordUtils.wrap(input, 20));
70 }
71
72 public void testWrap_StringIntStringBoolean() {
73 assertEquals(null, WordUtils.wrap(null, 20, "\n", false));
74 assertEquals(null, WordUtils.wrap(null, 20, "\n", true));
75 assertEquals(null, WordUtils.wrap(null, 20, null, true));
76 assertEquals(null, WordUtils.wrap(null, 20, null, false));
77 assertEquals(null, WordUtils.wrap(null, -1, null, true));
78 assertEquals(null, WordUtils.wrap(null, -1, null, false));
79
80 assertEquals("", WordUtils.wrap("", 20, "\n", false));
81 assertEquals("", WordUtils.wrap("", 20, "\n", true));
82 assertEquals("", WordUtils.wrap("", 20, null, false));
83 assertEquals("", WordUtils.wrap("", 20, null, true));
84 assertEquals("", WordUtils.wrap("", -1, null, false));
85 assertEquals("", WordUtils.wrap("", -1, null, true));
86
87 // normal
88 String input = "Here is one line of text that is going to be wrapped after 20 columns.";
89 String expected = "Here is one line of\ntext that is going\nto be wrapped after\n20 columns.";
90 assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
91 assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
92
93 // unusual newline char
94 input = "Here is one line of text that is going to be wrapped after 20 columns.";
95 expected = "Here is one line of<br />text that is going<br />to be wrapped after<br />20 columns.";
96 assertEquals(expected, WordUtils.wrap(input, 20, "<br />", false));
97 assertEquals(expected, WordUtils.wrap(input, 20, "<br />", true));
98
99 // short line length
100 input = "Here is one line";
101 expected = "Here\nis one\nline";
102 assertEquals(expected, WordUtils.wrap(input, 6, "\n", false));
103 expected = "Here\nis\none\nline";
104 assertEquals(expected, WordUtils.wrap(input, 2, "\n", false));
105 assertEquals(expected, WordUtils.wrap(input, -1, "\n", false));
106
107 // system newline char
108 String systemNewLine = System.getProperty("line.separator");
109 input = "Here is one line of text that is going to be wrapped after 20 columns.";
110 expected = "Here is one line of" + systemNewLine + "text that is going" + systemNewLine
111 + "to be wrapped after" + systemNewLine + "20 columns.";
112 assertEquals(expected, WordUtils.wrap(input, 20, null, false));
113 assertEquals(expected, WordUtils.wrap(input, 20, null, true));
114
115 // with extra spaces
116 input = " Here: is one line of text that is going to be wrapped after 20 columns.";
117 expected = "Here: is one line\nof text that is \ngoing to be \nwrapped after 20 \ncolumns.";
118 assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
119 assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
120
121 // with tab
122 input = "Here is\tone line of text that is going to be wrapped after 20 columns.";
123 expected = "Here is\tone line of\ntext that is going\nto be wrapped after\n20 columns.";
124 assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
125 assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
126
127 // with tab at wrapColumn
128 input = "Here is one line of\ttext that is going to be wrapped after 20 columns.";
129 expected = "Here is one line\nof\ttext that is\ngoing to be wrapped\nafter 20 columns.";
130 assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
131 assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
132
133 // difference because of long word
134 input = "Click here to jump to the jakarta website - http://jakarta.apache.org";
135 expected = "Click here to jump\nto the jakarta\nwebsite -\nhttp://jakarta.apache.org";
136 assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
137 expected = "Click here to jump\nto the jakarta\nwebsite -\nhttp://jakarta.apach\ne.org";
138 assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
139
140 // difference because of long word in middle
141 input = "Click here, http://jakarta.apache.org, to jump to the jakarta website";
142 expected = "Click here,\nhttp://jakarta.apache.org,\nto jump to the\njakarta website";
143 assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
144 expected = "Click here,\nhttp://jakarta.apach\ne.org, to jump to\nthe jakarta website";
145 assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
146 // System.err.println(expected);
147 // System.err.println(WordUtils.wrap(input, 20, "\n", false));
148 }
149
150 //-----------------------------------------------------------------------
151 public void testCapitalize_String() {
152 assertEquals(null, WordUtils.capitalize(null));
153 assertEquals("", WordUtils.capitalize(""));
154 assertEquals(" ", WordUtils.capitalize(" "));
155
156 assertEquals("I", WordUtils.capitalize("I") );
157 assertEquals("I", WordUtils.capitalize("i") );
158 assertEquals("I Am Here 123", WordUtils.capitalize("i am here 123") );
159 assertEquals("I Am Here 123", WordUtils.capitalize("I Am Here 123") );
160 assertEquals("I Am HERE 123", WordUtils.capitalize("i am HERE 123") );
161 assertEquals("I AM HERE 123", WordUtils.capitalize("I AM HERE 123") );
162 }
163
164 public void testCapitalizeWithDelimiters_String() {
165 assertEquals(null, WordUtils.capitalize(null, null));
166 assertEquals("", WordUtils.capitalize("", new char[0]));
167 assertEquals(" ", WordUtils.capitalize(" ", new char[0]));
168
169 char[] chars = new char[] { '-', '+', ' ', '@' };
170 assertEquals("I", WordUtils.capitalize("I", chars) );
171 assertEquals("I", WordUtils.capitalize("i", chars) );
172 assertEquals("I-Am Here+123", WordUtils.capitalize("i-am here+123", chars) );
173 assertEquals("I Am+Here-123", WordUtils.capitalize("I Am+Here-123", chars) );
174 assertEquals("I+Am-HERE 123", WordUtils.capitalize("i+am-HERE 123", chars) );
175 assertEquals("I-AM HERE+123", WordUtils.capitalize("I-AM HERE+123", chars) );
176 chars = new char[] {'.'};
177 assertEquals("I aM.Fine", WordUtils.capitalize("i aM.fine", chars) );
178 assertEquals("I Am.fine", WordUtils.capitalize("i am.fine", null) );
179 }
180
181 public void testCapitalizeFully_String() {
182 assertEquals(null, WordUtils.capitalizeFully(null));
183 assertEquals("", WordUtils.capitalizeFully(""));
184 assertEquals(" ", WordUtils.capitalizeFully(" "));
185
186 assertEquals("I", WordUtils.capitalizeFully("I") );
187 assertEquals("I", WordUtils.capitalizeFully("i") );
188 assertEquals("I Am Here 123", WordUtils.capitalizeFully("i am here 123") );
189 assertEquals("I Am Here 123", WordUtils.capitalizeFully("I Am Here 123") );
190 assertEquals("I Am Here 123", WordUtils.capitalizeFully("i am HERE 123") );
191 assertEquals("I Am Here 123", WordUtils.capitalizeFully("I AM HERE 123") );
192 }
193
194 public void testCapitalizeFullyWithDelimiters_String() {
195 assertEquals(null, WordUtils.capitalizeFully(null, null));
196 assertEquals("", WordUtils.capitalizeFully("", new char[0]));
197 assertEquals(" ", WordUtils.capitalizeFully(" ", new char[0]));
198
199 char[] chars = new char[] { '-', '+', ' ', '@' };
200 assertEquals("I", WordUtils.capitalizeFully("I", chars) );
201 assertEquals("I", WordUtils.capitalizeFully("i", chars) );
202 assertEquals("I-Am Here+123", WordUtils.capitalizeFully("i-am here+123", chars) );
203 assertEquals("I Am+Here-123", WordUtils.capitalizeFully("I Am+Here-123", chars) );
204 assertEquals("I+Am-Here 123", WordUtils.capitalizeFully("i+am-HERE 123", chars) );
205 assertEquals("I-Am Here+123", WordUtils.capitalizeFully("I-AM HERE+123", chars) );
206 chars = new char[] {'.'};
207 assertEquals("I am.Fine", WordUtils.capitalizeFully("i aM.fine", chars) );
208 assertEquals("I Am.fine", WordUtils.capitalizeFully("i am.fine", null) );
209 }
210
211 public void testUncapitalize_String() {
212 assertEquals(null, WordUtils.uncapitalize(null));
213 assertEquals("", WordUtils.uncapitalize(""));
214 assertEquals(" ", WordUtils.uncapitalize(" "));
215
216 assertEquals("i", WordUtils.uncapitalize("I") );
217 assertEquals("i", WordUtils.uncapitalize("i") );
218 assertEquals("i am here 123", WordUtils.uncapitalize("i am here 123") );
219 assertEquals("i am here 123", WordUtils.uncapitalize("I Am Here 123") );
220 assertEquals("i am hERE 123", WordUtils.uncapitalize("i am HERE 123") );
221 assertEquals("i aM hERE 123", WordUtils.uncapitalize("I AM HERE 123") );
222 }
223
224 public void testUncapitalizeWithDelimiters_String() {
225 assertEquals(null, WordUtils.uncapitalize(null, null));
226 assertEquals("", WordUtils.uncapitalize("", new char[0]));
227 assertEquals(" ", WordUtils.uncapitalize(" ", new char[0]));
228
229 char[] chars = new char[] { '-', '+', ' ', '@' };
230 assertEquals("i", WordUtils.uncapitalize("I", chars) );
231 assertEquals("i", WordUtils.uncapitalize("i", chars) );
232 assertEquals("i am-here+123", WordUtils.uncapitalize("i am-here+123", chars) );
233 assertEquals("i+am here-123", WordUtils.uncapitalize("I+Am Here-123", chars) );
234 assertEquals("i-am+hERE 123", WordUtils.uncapitalize("i-am+HERE 123", chars) );
235 assertEquals("i aM-hERE+123", WordUtils.uncapitalize("I AM-HERE+123", chars) );
236 chars = new char[] {'.'};
237 assertEquals("i AM.fINE", WordUtils.uncapitalize("I AM.FINE", chars) );
238 assertEquals("i aM.FINE", WordUtils.uncapitalize("I AM.FINE", null) );
239 }
240
241 //-----------------------------------------------------------------------
242 public void testInitials_String() {
243 assertEquals(null, WordUtils.initials(null));
244 assertEquals("", WordUtils.initials(""));
245 assertEquals("", WordUtils.initials(" "));
246
247 assertEquals("I", WordUtils.initials("I"));
248 assertEquals("i", WordUtils.initials("i"));
249 assertEquals("BJL", WordUtils.initials("Ben John Lee"));
250 assertEquals("BJ", WordUtils.initials("Ben J.Lee"));
251 assertEquals("BJ.L", WordUtils.initials(" Ben John . Lee"));
252 assertEquals("iah1", WordUtils.initials("i am here 123"));
253 }
254
255 // -----------------------------------------------------------------------
256 public void testInitials_String_charArray() {
257 char[] array = null;
258 assertEquals(null, WordUtils.initials(null, array));
259 assertEquals("", WordUtils.initials("", array));
260 assertEquals("", WordUtils.initials(" ", array));
261 assertEquals("I", WordUtils.initials("I", array));
262 assertEquals("i", WordUtils.initials("i", array));
263 assertEquals("S", WordUtils.initials("SJC", array));
264 assertEquals("BJL", WordUtils.initials("Ben John Lee", array));
265 assertEquals("BJ", WordUtils.initials("Ben J.Lee", array));
266 assertEquals("BJ.L", WordUtils.initials(" Ben John . Lee", array));
267 assertEquals("KO", WordUtils.initials("Kay O'Murphy", array));
268 assertEquals("iah1", WordUtils.initials("i am here 123", array));
269
270 array = new char[0];
271 assertEquals(null, WordUtils.initials(null, array));
272 assertEquals("", WordUtils.initials("", array));
273 assertEquals("", WordUtils.initials(" ", array));
274 assertEquals("", WordUtils.initials("I", array));
275 assertEquals("", WordUtils.initials("i", array));
276 assertEquals("", WordUtils.initials("SJC", array));
277 assertEquals("", WordUtils.initials("Ben John Lee", array));
278 assertEquals("", WordUtils.initials("Ben J.Lee", array));
279 assertEquals("", WordUtils.initials(" Ben John . Lee", array));
280 assertEquals("", WordUtils.initials("Kay O'Murphy", array));
281 assertEquals("", WordUtils.initials("i am here 123", array));
282
283 array = " ".toCharArray();
284 assertEquals(null, WordUtils.initials(null, array));
285 assertEquals("", WordUtils.initials("", array));
286 assertEquals("", WordUtils.initials(" ", array));
287 assertEquals("I", WordUtils.initials("I", array));
288 assertEquals("i", WordUtils.initials("i", array));
289 assertEquals("S", WordUtils.initials("SJC", array));
290 assertEquals("BJL", WordUtils.initials("Ben John Lee", array));
291 assertEquals("BJ", WordUtils.initials("Ben J.Lee", array));
292 assertEquals("BJ.L", WordUtils.initials(" Ben John . Lee", array));
293 assertEquals("KO", WordUtils.initials("Kay O'Murphy", array));
294 assertEquals("iah1", WordUtils.initials("i am here 123", array));
295
296 array = " .".toCharArray();
297 assertEquals(null, WordUtils.initials(null, array));
298 assertEquals("", WordUtils.initials("", array));
299 assertEquals("", WordUtils.initials(" ", array));
300 assertEquals("I", WordUtils.initials("I", array));
301 assertEquals("i", WordUtils.initials("i", array));
302 assertEquals("S", WordUtils.initials("SJC", array));
303 assertEquals("BJL", WordUtils.initials("Ben John Lee", array));
304 assertEquals("BJL", WordUtils.initials("Ben J.Lee", array));
305 assertEquals("BJL", WordUtils.initials(" Ben John . Lee", array));
306 assertEquals("KO", WordUtils.initials("Kay O'Murphy", array));
307 assertEquals("iah1", WordUtils.initials("i am here 123", array));
308
309 array = " .'".toCharArray();
310 assertEquals(null, WordUtils.initials(null, array));
311 assertEquals("", WordUtils.initials("", array));
312 assertEquals("", WordUtils.initials(" ", array));
313 assertEquals("I", WordUtils.initials("I", array));
314 assertEquals("i", WordUtils.initials("i", array));
315 assertEquals("S", WordUtils.initials("SJC", array));
316 assertEquals("BJL", WordUtils.initials("Ben John Lee", array));
317 assertEquals("BJL", WordUtils.initials("Ben J.Lee", array));
318 assertEquals("BJL", WordUtils.initials(" Ben John . Lee", array));
319 assertEquals("KOM", WordUtils.initials("Kay O'Murphy", array));
320 assertEquals("iah1", WordUtils.initials("i am here 123", array));
321
322 array = "SIJo1".toCharArray();
323 assertEquals(null, WordUtils.initials(null, array));
324 assertEquals("", WordUtils.initials("", array));
325 assertEquals(" ", WordUtils.initials(" ", array));
326 assertEquals("", WordUtils.initials("I", array));
327 assertEquals("i", WordUtils.initials("i", array));
328 assertEquals("C", WordUtils.initials("SJC", array));
329 assertEquals("Bh", WordUtils.initials("Ben John Lee", array));
330 assertEquals("B.", WordUtils.initials("Ben J.Lee", array));
331 assertEquals(" h", WordUtils.initials(" Ben John . Lee", array));
332 assertEquals("K", WordUtils.initials("Kay O'Murphy", array));
333 assertEquals("i2", WordUtils.initials("i am here 123", array));
334 }
335
336 // -----------------------------------------------------------------------
337 public void testSwapCase_String() {
338 assertEquals(null, WordUtils.swapCase(null));
339 assertEquals("", WordUtils.swapCase(""));
340 assertEquals(" ", WordUtils.swapCase(" "));
341
342 assertEquals("i", WordUtils.swapCase("I") );
343 assertEquals("I", WordUtils.swapCase("i") );
344 assertEquals("I AM HERE 123", WordUtils.swapCase("i am here 123") );
345 assertEquals("i aM hERE 123", WordUtils.swapCase("I Am Here 123") );
346 assertEquals("I AM here 123", WordUtils.swapCase("i am HERE 123") );
347 assertEquals("i am here 123", WordUtils.swapCase("I AM HERE 123") );
348
349 String test = "This String contains a TitleCase character: \u01C8";
350 String expect = "tHIS sTRING CONTAINS A tITLEcASE CHARACTER: \u01C9";
351 assertEquals(expect, WordUtils.swapCase(test));
352 }
353
354 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text.translate;
18
19 import java.util.HashSet;
20 import java.util.Set;
21
22 import junit.framework.TestCase;
23
24 /**
25 * Unit tests for {@link org.apache.commons.lang3.text.translate.EntityArrays}.
26 * @version $Id: EntityArraysTest.java 1034797 2010-11-13 16:31:08Z sebb $
27 */
28 public class EntityArraysTest extends TestCase {
29
30 public void testConstructorExists() {
31 new EntityArrays();
32 }
33
34 // LANG-659 - check arrays for duplicate entries
35 public void testHTML40_EXTENDED_ESCAPE(){
36 Set<String> col0 = new HashSet<String>();
37 Set<String> col1 = new HashSet<String>();
38 String [][] sa = EntityArrays.HTML40_EXTENDED_ESCAPE();
39 for(int i =0; i <sa.length; i++){
40 assertTrue("Already added entry 0: "+i+" "+sa[i][0],col0.add(sa[i][0]));
41 assertTrue("Already added entry 1: "+i+" "+sa[i][1],col1.add(sa[i][1]));
42 }
43 }
44
45 // LANG-658 - check arrays for duplicate entries
46 public void testISO8859_1_ESCAPE(){
47 Set<String> col0 = new HashSet<String>();
48 Set<String> col1 = new HashSet<String>();
49 String [][] sa = EntityArrays.ISO8859_1_ESCAPE();
50 boolean success = true;
51 for(int i =0; i <sa.length; i++){
52 boolean add0 = col0.add(sa[i][0]);
53 boolean add1 = col1.add(sa[i][1]);
54 if (!add0) {
55 success = false;
56 System.out.println("Already added entry 0: "+i+" "+sa[i][0]+" "+sa[i][1]);
57 }
58 if (!add1) {
59 success = false;
60 System.out.println("Already added entry 1: "+i+" "+sa[i][0]+" "+sa[i][1]);
61 }
62 }
63 assertTrue("One or more errors detected",success);
64 }
65
66
67 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text.translate;
18
19 import java.io.IOException;
20 import java.io.StringWriter;
21
22 import junit.framework.TestCase;
23
24 /**
25 * Unit tests for {@link org.apache.commons.lang3.text.translate.LookupTranslator}.
26 * @version $Id: LookupTranslatorTest.java 1022749 2010-10-14 22:49:55Z ggregory $
27 */
28 public class LookupTranslatorTest extends TestCase {
29
30 public void testBasicLookup() throws IOException {
31 LookupTranslator lt = new LookupTranslator(new CharSequence[][] { { "one", "two" } });
32 StringWriter out = new StringWriter();
33 int result = lt.translate("one", 0, out);
34 assertEquals("Incorrect codepoint consumption", 3, result);
35 assertEquals("Incorrect value", "two", out.toString());
36 }
37
38 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text.translate;
18
19 import junit.framework.TestCase;
20
21 /**
22 * Unit tests for {@link org.apache.commons.lang3.text.translate.NumericEntityEscaper}.
23 * @version $Id: NumericEntityEscaperTest.java 1142151 2011-07-02 04:06:23Z bayard $
24 */
25 public class NumericEntityEscaperTest extends TestCase {
26
27 public void testBelow() {
28 NumericEntityEscaper nee = NumericEntityEscaper.below('F');
29
30 String input = "ADFGZ";
31 String result = nee.translate(input);
32 assertEquals("Failed to escape numeric entities via the below method", "&#65;&#68;FGZ", result);
33 }
34
35 public void testBetween() {
36 NumericEntityEscaper nee = NumericEntityEscaper.between('F', 'L');
37
38 String input = "ADFGZ";
39 String result = nee.translate(input);
40 assertEquals("Failed to escape numeric entities via the between method", "AD&#70;&#71;Z", result);
41 }
42
43 public void testAbove() {
44 NumericEntityEscaper nee = NumericEntityEscaper.above('F');
45
46 String input = "ADFGZ";
47 String result = nee.translate(input);
48 assertEquals("Failed to escape numeric entities via the above method", "ADF&#71;&#90;", result);
49 }
50
51 // See LANG-617
52 public void testSupplementary() {
53 NumericEntityEscaper nee = new NumericEntityEscaper();
54 String input = "\uD803\uDC22";
55 String expected = "&#68642;";
56
57 String result = nee.translate(input);
58 assertEquals("Failed to escape numeric entities supplementary characters", expected, result);
59
60 }
61
62 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text.translate;
18
19 import junit.framework.TestCase;
20
21 /**
22 * Unit tests for {@link org.apache.commons.lang3.text.translate.NumericEntityUnescaper}.
23 * @version $Id: NumericEntityUnescaperTest.java 1143643 2011-07-07 03:47:17Z bayard $
24 */
25 public class NumericEntityUnescaperTest extends TestCase {
26
27 public void testSupplementaryUnescaping() {
28 NumericEntityUnescaper neu = new NumericEntityUnescaper();
29 String input = "&#68642;";
30 String expected = "\uD803\uDC22";
31
32 String result = neu.translate(input);
33 assertEquals("Failed to unescape numeric entities supplementary characters", expected, result);
34 }
35
36 public void testOutOfBounds() {
37 NumericEntityUnescaper neu = new NumericEntityUnescaper();
38
39 assertEquals("Failed to ignore when last character is &", "Test &", neu.translate("Test &"));
40 assertEquals("Failed to ignore when last character is &", "Test &#", neu.translate("Test &#"));
41 assertEquals("Failed to ignore when last character is &", "Test &#x", neu.translate("Test &#x"));
42 assertEquals("Failed to ignore when last character is &", "Test &#X", neu.translate("Test &#X"));
43 }
44
45 public void testUnfinishedEntity() {
46 // parse it
47 NumericEntityUnescaper neu = new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.semiColonOptional);
48 String input = "Test &#x30 not test";
49 String expected = "Test \u0030 not test";
50
51 String result = neu.translate(input);
52 assertEquals("Failed to support unfinished entities (i.e. missing semi-colon)", expected, result);
53
54 // ignore it
55 neu = new NumericEntityUnescaper();
56 input = "Test &#x30 not test";
57 expected = input;
58
59 result = neu.translate(input);
60 assertEquals("Failed to ignore unfinished entities (i.e. missing semi-colon)", expected, result);
61
62 // fail it
63 neu = new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.errorIfNoSemiColon);
64 input = "Test &#x30 not test";
65
66 try {
67 result = neu.translate(input);
68 fail("IllegalArgumentException expected");
69 } catch(IllegalArgumentException iae) {
70 // expected
71 }
72 }
73
74 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text.translate;
18
19 import junit.framework.TestCase;
20
21 /**
22 * Unit tests for {@link org.apache.commons.lang3.text.translate.OctalUnescaper}.
23 * @version $Id: OctalUnescaperTest.java 979392 2010-07-26 18:09:52Z mbenson $
24 */
25 public class OctalUnescaperTest extends TestCase {
26
27 public void testBetween() {
28 OctalUnescaper oue = new OctalUnescaper(); //.between("1", "377");
29
30 String input = "\\45";
31 String result = oue.translate(input);
32 assertEquals("Failed to unescape octal characters via the between method", "\45", result);
33
34 input = "\\377";
35 result = oue.translate(input);
36 assertEquals("Failed to unescape octal characters via the between method", "\377", result);
37
38 input = "\\377 and";
39 result = oue.translate(input);
40 assertEquals("Failed to unescape octal characters via the between method", "\377 and", result);
41
42 input = "\\378 and";
43 result = oue.translate(input);
44 assertEquals("Failed to unescape octal characters via the between method", "\378 and", result);
45
46 input = "\\378";
47 result = oue.translate(input);
48 assertEquals("Failed to unescape octal characters via the between method", "\378", result);
49
50 input = "\\1";
51 result = oue.translate(input);
52 assertEquals("Failed to unescape octal characters via the between method", "\1", result);
53 }
54
55 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text.translate;
18
19 import junit.framework.TestCase;
20
21 /**
22 * Unit tests for {@link org.apache.commons.lang3.text.translate.UnicodeEscaper}.
23 * @version $Id: UnicodeEscaperTest.java 1148520 2011-07-19 20:53:23Z ggregory $
24 */
25 public class UnicodeEscaperTest extends TestCase {
26
27 public void testBelow() {
28 UnicodeEscaper ue = UnicodeEscaper.below('F');
29
30 String input = "ADFGZ";
31 String result = ue.translate(input);
32 assertEquals("Failed to escape Unicode characters via the below method", "\\u0041\\u0044FGZ", result);
33 }
34
35 public void testBetween() {
36 UnicodeEscaper ue = UnicodeEscaper.between('F', 'L');
37
38 String input = "ADFGZ";
39 String result = ue.translate(input);
40 assertEquals("Failed to escape Unicode characters via the between method", "AD\\u0046\\u0047Z", result);
41 }
42
43 public void testAbove() {
44 UnicodeEscaper ue = UnicodeEscaper.above('F');
45
46 String input = "ADFGZ";
47 String result = ue.translate(input);
48 assertEquals("Failed to escape Unicode characters via the above method", "ADF\\u0047\\u005A", result);
49 }
50 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.text.translate;
18
19 import junit.framework.TestCase;
20
21 /**
22 * Unit tests for {@link org.apache.commons.lang3.text.translate.UnicodeEscaper}.
23 * @version $Id: UnicodeUnescaperTest.java 1148520 2011-07-19 20:53:23Z ggregory $
24 */
25 public class UnicodeUnescaperTest extends TestCase {
26
27 // Requested in LANG-507
28 public void testUPlus() {
29 UnicodeUnescaper uu = new UnicodeUnescaper();
30
31 String input = "\\u+0047";
32 assertEquals("Failed to unescape Unicode characters with 'u+' notation", "G", uu.translate(input));
33 }
34
35 public void testUuuuu() {
36 UnicodeUnescaper uu = new UnicodeUnescaper();
37
38 String input = "\\uuuuuuuu0047";
39 String result = uu.translate(input);
40 assertEquals("Failed to unescape Unicode characters with many 'u' characters", "G", result);
41 }
42
43 public void testLessThanFour() {
44 UnicodeUnescaper uu = new UnicodeUnescaper();
45
46 String input = "\\0047\\u006";
47 try {
48 uu.translate(input);
49 fail("A lack of digits in a Unicode escape sequence failed to throw an exception");
50 } catch(IllegalArgumentException iae) {
51 // expected
52 }
53 }
54 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.Modifier;
20 import java.util.Calendar;
21 import java.util.Locale;
22 import java.util.TimeZone;
23
24 import junit.framework.TestCase;
25
26 /**
27 * TestCase for DateFormatUtils.
28 *
29 */
30 public class DateFormatUtilsTest extends TestCase {
31
32 public DateFormatUtilsTest(String s) {
33 super(s);
34 }
35
36 //-----------------------------------------------------------------------
37 public void testConstructor() {
38 assertNotNull(new DateFormatUtils());
39 Constructor<?>[] cons = DateFormatUtils.class.getDeclaredConstructors();
40 assertEquals(1, cons.length);
41 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
42 assertEquals(true, Modifier.isPublic(DateFormatUtils.class.getModifiers()));
43 assertEquals(false, Modifier.isFinal(DateFormatUtils.class.getModifiers()));
44 }
45
46 //-----------------------------------------------------------------------
47 public void testFormat() {
48 Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
49 c.set(2005,0,1,12,0,0);
50 c.setTimeZone(TimeZone.getDefault());
51 StringBuffer buffer = new StringBuffer ();
52 int year = c.get(Calendar.YEAR);
53 int month = c.get(Calendar.MONTH) + 1;
54 int day = c.get(Calendar.DAY_OF_MONTH);
55 int hour = c.get(Calendar.HOUR_OF_DAY);
56 buffer.append (year);
57 buffer.append(month);
58 buffer.append(day);
59 buffer.append(hour);
60 assertEquals(buffer.toString(), DateFormatUtils.format(c.getTime(), "yyyyMdH"));
61
62 assertEquals(buffer.toString(), DateFormatUtils.format(c.getTime().getTime(), "yyyyMdH"));
63
64 assertEquals(buffer.toString(), DateFormatUtils.format(c.getTime(), "yyyyMdH", Locale.US));
65
66 assertEquals(buffer.toString(), DateFormatUtils.format(c.getTime().getTime(), "yyyyMdH", Locale.US));
67 }
68
69 //-----------------------------------------------------------------------
70 public void testFormatCalendar() {
71 Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
72 c.set(2005,0,1,12,0,0);
73 c.setTimeZone(TimeZone.getDefault());
74 StringBuffer buffer = new StringBuffer ();
75 int year = c.get(Calendar.YEAR);
76 int month = c.get(Calendar.MONTH) + 1;
77 int day = c.get(Calendar.DAY_OF_MONTH);
78 int hour = c.get(Calendar.HOUR_OF_DAY);
79 buffer.append (year);
80 buffer.append(month);
81 buffer.append(day);
82 buffer.append(hour);
83 assertEquals(buffer.toString(), DateFormatUtils.format(c, "yyyyMdH"));
84
85 assertEquals(buffer.toString(), DateFormatUtils.format(c.getTime(), "yyyyMdH"));
86
87 assertEquals(buffer.toString(), DateFormatUtils.format(c, "yyyyMdH", Locale.US));
88
89 assertEquals(buffer.toString(), DateFormatUtils.format(c.getTime(), "yyyyMdH", Locale.US));
90 }
91
92 public void testFormatUTC() {
93 Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
94 c.set(2005,0,1,12,0,0);
95 assertEquals ("2005-01-01T12:00:00", DateFormatUtils.formatUTC(c.getTime(), DateFormatUtils.ISO_DATETIME_FORMAT.getPattern()));
96
97 assertEquals ("2005-01-01T12:00:00", DateFormatUtils.formatUTC(c.getTime().getTime(), DateFormatUtils.ISO_DATETIME_FORMAT.getPattern()));
98
99 assertEquals ("2005-01-01T12:00:00", DateFormatUtils.formatUTC(c.getTime(), DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), Locale.US));
100
101 assertEquals ("2005-01-01T12:00:00", DateFormatUtils.formatUTC(c.getTime().getTime(), DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), Locale.US));
102 }
103
104 public void testDateTimeISO(){
105 TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
106 Calendar cal = Calendar.getInstance(timeZone);
107 cal.set(2002,1,23,9,11,12);
108 String text = DateFormatUtils.format(cal.getTime(),
109 DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), timeZone);
110 assertEquals("2002-02-23T09:11:12", text);
111 text = DateFormatUtils.format(cal.getTime().getTime(),
112 DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), timeZone);
113 assertEquals("2002-02-23T09:11:12", text);
114 text = DateFormatUtils.ISO_DATETIME_FORMAT.format(cal);
115 assertEquals("2002-02-23T09:11:12", text);
116
117 text = DateFormatUtils.format(cal.getTime(),
118 DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), timeZone);
119 assertEquals("2002-02-23T09:11:12-03:00", text);
120 text = DateFormatUtils.format(cal.getTime().getTime(),
121 DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), timeZone);
122 assertEquals("2002-02-23T09:11:12-03:00", text);
123 text = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(cal);
124 assertEquals("2002-02-23T09:11:12-03:00", text);
125 }
126
127 public void testDateISO(){
128 TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
129 Calendar cal = Calendar.getInstance(timeZone);
130 cal.set(2002,1,23,10,11,12);
131 String text = DateFormatUtils.format(cal.getTime(),
132 DateFormatUtils.ISO_DATE_FORMAT.getPattern(), timeZone);
133 assertEquals("2002-02-23", text);
134 text = DateFormatUtils.format(cal.getTime().getTime(),
135 DateFormatUtils.ISO_DATE_FORMAT.getPattern(), timeZone);
136 assertEquals("2002-02-23", text);
137 text = DateFormatUtils.ISO_DATE_FORMAT.format(cal);
138 assertEquals("2002-02-23", text);
139
140 text = DateFormatUtils.format(cal.getTime(),
141 DateFormatUtils.ISO_DATE_TIME_ZONE_FORMAT.getPattern(), timeZone);
142 assertEquals("2002-02-23-03:00", text);
143 text = DateFormatUtils.format(cal.getTime().getTime(),
144 DateFormatUtils.ISO_DATE_TIME_ZONE_FORMAT.getPattern(), timeZone);
145 assertEquals("2002-02-23-03:00", text);
146 text = DateFormatUtils.ISO_DATE_TIME_ZONE_FORMAT.format(cal);
147 assertEquals("2002-02-23-03:00", text);
148 }
149
150 public void testTimeISO(){
151 TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
152 Calendar cal = Calendar.getInstance(timeZone);
153 cal.set(2002,1,23,10,11,12);
154 String text = DateFormatUtils.format(cal.getTime(),
155 DateFormatUtils.ISO_TIME_FORMAT.getPattern(), timeZone);
156 assertEquals("T10:11:12", text);
157 text = DateFormatUtils.format(cal.getTime().getTime(),
158 DateFormatUtils.ISO_TIME_FORMAT.getPattern(), timeZone);
159 assertEquals("T10:11:12", text);
160 text = DateFormatUtils.ISO_TIME_FORMAT.format(cal);
161 assertEquals("T10:11:12", text);
162
163 text = DateFormatUtils.format(cal.getTime(),
164 DateFormatUtils.ISO_TIME_TIME_ZONE_FORMAT.getPattern(), timeZone);
165 assertEquals("T10:11:12-03:00", text);
166 text = DateFormatUtils.format(cal.getTime().getTime(),
167 DateFormatUtils.ISO_TIME_TIME_ZONE_FORMAT.getPattern(), timeZone);
168 assertEquals("T10:11:12-03:00", text);
169 text = DateFormatUtils.ISO_TIME_TIME_ZONE_FORMAT.format(cal);
170 assertEquals("T10:11:12-03:00", text);
171 }
172
173 public void testTimeNoTISO(){
174 TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
175 Calendar cal = Calendar.getInstance(timeZone);
176 cal.set(2002,1,23,10,11,12);
177 String text = DateFormatUtils.format(cal.getTime(),
178 DateFormatUtils.ISO_TIME_NO_T_FORMAT.getPattern(), timeZone);
179 assertEquals("10:11:12", text);
180 text = DateFormatUtils.format(cal.getTime().getTime(),
181 DateFormatUtils.ISO_TIME_NO_T_FORMAT.getPattern(), timeZone);
182 assertEquals("10:11:12", text);
183 text = DateFormatUtils.ISO_TIME_NO_T_FORMAT.format(cal);
184 assertEquals("10:11:12", text);
185
186 text = DateFormatUtils.format(cal.getTime(),
187 DateFormatUtils.ISO_TIME_NO_T_TIME_ZONE_FORMAT.getPattern(), timeZone);
188 assertEquals("10:11:12-03:00", text);
189 text = DateFormatUtils.format(cal.getTime().getTime(),
190 DateFormatUtils.ISO_TIME_NO_T_TIME_ZONE_FORMAT.getPattern(), timeZone);
191 assertEquals("10:11:12-03:00", text);
192 text = DateFormatUtils.ISO_TIME_NO_T_TIME_ZONE_FORMAT.format(cal);
193 assertEquals("10:11:12-03:00", text);
194 }
195
196 public void testSMTP(){
197 TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
198 Calendar cal = Calendar.getInstance(timeZone);
199 cal.set(2003,5,8,10,11,12);
200 String text = DateFormatUtils.format(cal.getTime(),
201 DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), timeZone,
202 DateFormatUtils.SMTP_DATETIME_FORMAT.getLocale());
203 assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text);
204 text = DateFormatUtils.format(cal.getTime().getTime(),
205 DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), timeZone,
206 DateFormatUtils.SMTP_DATETIME_FORMAT.getLocale());
207 assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text);
208 text = DateFormatUtils.SMTP_DATETIME_FORMAT.format(cal);
209 assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text);
210
211 // format UTC
212 text = DateFormatUtils.formatUTC(cal.getTime().getTime(),
213 DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(),
214 DateFormatUtils.SMTP_DATETIME_FORMAT.getLocale());
215 assertEquals("Sun, 08 Jun 2003 13:11:12 +0000", text);
216 }
217
218 /*
219 public void testLang312() {
220 String pattern = "dd/MM/yyyy";
221 String expected = "19/04/1948";
222 TimeZone timeZone = TimeZone.getTimeZone("CET");
223 Locale locale = Locale.GERMANY;
224
225 // show Calendar is good
226 Calendar cal = Calendar.getInstance(timeZone, locale);
227 cal.set(1948, 3, 19);
228 assertEquals(expected, DateFormatUtils.format( cal.getTime(), pattern, timeZone, locale ) );
229
230 Date date = new Date(48, 3, 19);
231
232 // test JDK
233 java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(pattern, locale);
234 sdf.setTimeZone(timeZone);
235 // There's nothing we can do if the JDK fails, so just going to pring a warning in this case
236 // assertEquals(expected, sdf.format( date ) );
237 if( ! expected.equals( sdf.format( date ) ) ) {
238 System.out.println("WARNING: JDK test failed - testLang312()");
239 }
240
241 // test Commons
242 assertEquals(expected, DateFormatUtils.format( date, pattern, timeZone, locale ) );
243 }
244 */
245
246 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import java.util.Calendar;
19 import java.util.Date;
20
21 import junit.framework.TestCase;
22
23 public class DateUtilsFragmentTest extends TestCase {
24
25 private static final int months = 7; // second final prime before 12
26 private static final int days = 23; // second final prime before 31 (and valid)
27 private static final int hours = 19; // second final prime before 24
28 private static final int minutes = 53; // second final prime before 60
29 private static final int seconds = 47; // third final prime before 60
30 private static final int millis = 991; // second final prime before 1000
31
32 private Date aDate;
33 private Calendar aCalendar;
34
35 @Override
36 protected void setUp() {
37 aCalendar = Calendar.getInstance();
38 aCalendar.set(2005, months, days, hours, minutes, seconds);
39 aCalendar.set(Calendar.MILLISECOND, millis);
40 aDate = aCalendar.getTime();
41 }
42
43 public void testNullDate() {
44 try {
45 DateUtils.getFragmentInMilliseconds((Date) null, Calendar.MILLISECOND);
46 fail();
47 } catch(IllegalArgumentException iae) {}
48
49 try {
50 DateUtils.getFragmentInSeconds((Date) null, Calendar.MILLISECOND);
51 fail();
52 } catch(IllegalArgumentException iae) {}
53
54 try {
55 DateUtils.getFragmentInMinutes((Date) null, Calendar.MILLISECOND);
56 fail();
57 } catch(IllegalArgumentException iae) {}
58
59 try {
60 DateUtils.getFragmentInHours((Date) null, Calendar.MILLISECOND);
61 fail();
62 } catch(IllegalArgumentException iae) {}
63
64 try {
65 DateUtils.getFragmentInDays((Date) null, Calendar.MILLISECOND);
66 fail();
67 } catch(IllegalArgumentException iae) {}
68 }
69
70 public void testNullCalendar() {
71 try {
72 DateUtils.getFragmentInMilliseconds((Calendar) null, Calendar.MILLISECOND);
73 fail();
74 } catch(IllegalArgumentException iae) {}
75
76 try {
77 DateUtils.getFragmentInSeconds((Calendar) null, Calendar.MILLISECOND);
78 fail();
79 } catch(IllegalArgumentException iae) {}
80
81 try {
82 DateUtils.getFragmentInMinutes((Calendar) null, Calendar.MILLISECOND);
83 fail();
84 } catch(IllegalArgumentException iae) {}
85
86 try {
87 DateUtils.getFragmentInHours((Calendar) null, Calendar.MILLISECOND);
88 fail();
89 } catch(IllegalArgumentException iae) {}
90
91 try {
92 DateUtils.getFragmentInDays((Calendar) null, Calendar.MILLISECOND);
93 fail();
94 } catch(IllegalArgumentException iae) {}
95 }
96
97 public void testInvalidFragmentWithDate() {
98 try {
99 DateUtils.getFragmentInMilliseconds(aDate, 0);
100 fail();
101 } catch(IllegalArgumentException iae) {}
102
103 try {
104 DateUtils.getFragmentInSeconds(aDate, 0);
105 fail();
106 } catch(IllegalArgumentException iae) {}
107
108 try {
109 DateUtils.getFragmentInMinutes(aDate, 0);
110 fail();
111 } catch(IllegalArgumentException iae) {}
112
113 try {
114 DateUtils.getFragmentInHours(aDate, 0);
115 fail();
116 } catch(IllegalArgumentException iae) {}
117
118 try {
119 DateUtils.getFragmentInDays(aDate, 0);
120 fail();
121 } catch(IllegalArgumentException iae) {}
122 }
123
124 public void testInvalidFragmentWithCalendar() {
125 try {
126 DateUtils.getFragmentInMilliseconds(aCalendar, 0);
127 fail();
128 } catch(IllegalArgumentException iae) {}
129
130 try {
131 DateUtils.getFragmentInSeconds(aCalendar, 0);
132 fail();
133 } catch(IllegalArgumentException iae) {}
134
135 try {
136 DateUtils.getFragmentInMinutes(aCalendar, 0);
137 fail();
138 } catch(IllegalArgumentException iae) {}
139
140 try {
141 DateUtils.getFragmentInHours(aCalendar, 0);
142 fail();
143 } catch(IllegalArgumentException iae) {}
144
145 try {
146 DateUtils.getFragmentInDays(aCalendar, 0);
147 fail();
148 } catch(IllegalArgumentException iae) {}
149 }
150
151 public void testMillisecondFragmentInLargerUnitWithDate() {
152 assertEquals(0, DateUtils.getFragmentInMilliseconds(aDate, Calendar.MILLISECOND));
153 assertEquals(0, DateUtils.getFragmentInSeconds(aDate, Calendar.MILLISECOND));
154 assertEquals(0, DateUtils.getFragmentInMinutes(aDate, Calendar.MILLISECOND));
155 assertEquals(0, DateUtils.getFragmentInHours(aDate, Calendar.MILLISECOND));
156 assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.MILLISECOND));
157 }
158
159 public void testMillisecondFragmentInLargerUnitWithCalendar() {
160 assertEquals(0, DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.MILLISECOND));
161 assertEquals(0, DateUtils.getFragmentInSeconds(aCalendar, Calendar.MILLISECOND));
162 assertEquals(0, DateUtils.getFragmentInMinutes(aCalendar, Calendar.MILLISECOND));
163 assertEquals(0, DateUtils.getFragmentInHours(aCalendar, Calendar.MILLISECOND));
164 assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.MILLISECOND));
165 }
166
167 public void testSecondFragmentInLargerUnitWithDate() {
168 assertEquals(0, DateUtils.getFragmentInSeconds(aDate, Calendar.SECOND));
169 assertEquals(0, DateUtils.getFragmentInMinutes(aDate, Calendar.SECOND));
170 assertEquals(0, DateUtils.getFragmentInHours(aDate, Calendar.SECOND));
171 assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.SECOND));
172 }
173
174 public void testSecondFragmentInLargerUnitWithCalendar() {
175 assertEquals(0, DateUtils.getFragmentInSeconds(aCalendar, Calendar.SECOND));
176 assertEquals(0, DateUtils.getFragmentInMinutes(aCalendar, Calendar.SECOND));
177 assertEquals(0, DateUtils.getFragmentInHours(aCalendar, Calendar.SECOND));
178 assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.SECOND));
179 }
180
181 public void testMinuteFragmentInLargerUnitWithDate() {
182 assertEquals(0, DateUtils.getFragmentInMinutes(aDate, Calendar.MINUTE));
183 assertEquals(0, DateUtils.getFragmentInHours(aDate, Calendar.MINUTE));
184 assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.MINUTE));
185 }
186
187 public void testMinuteFragmentInLargerUnitWithCalendar() {
188 assertEquals(0, DateUtils.getFragmentInMinutes(aCalendar, Calendar.MINUTE));
189 assertEquals(0, DateUtils.getFragmentInHours(aCalendar, Calendar.MINUTE));
190 assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.MINUTE));
191 }
192
193 public void testHourOfDayFragmentInLargerUnitWithDate() {
194 assertEquals(0, DateUtils.getFragmentInHours(aDate, Calendar.HOUR_OF_DAY));
195 assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.HOUR_OF_DAY));
196 }
197
198 public void testHourOfDayFragmentInLargerUnitWithCalendar() {
199 assertEquals(0, DateUtils.getFragmentInHours(aCalendar, Calendar.HOUR_OF_DAY));
200 assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.HOUR_OF_DAY));
201 }
202
203 public void testDayOfYearFragmentInLargerUnitWithDate() {
204 assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.DAY_OF_YEAR));
205 }
206
207 public void testDayOfYearFragmentInLargerUnitWithCalendar() {
208 assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.DAY_OF_YEAR));
209 }
210
211 public void testDateFragmentInLargerUnitWithDate() {
212 assertEquals(0, DateUtils.getFragmentInDays(aDate, Calendar.DATE));
213 }
214
215 public void testDateFragmentInLargerUnitWithCalendar() {
216 assertEquals(0, DateUtils.getFragmentInDays(aCalendar, Calendar.DATE));
217 }
218
219 //Calendar.SECOND as useful fragment
220
221 public void testMillisecondsOfSecondWithDate() {
222 long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.SECOND);
223 assertEquals(millis, testResult);
224 }
225
226 public void testMillisecondsOfSecondWithCalendar() {
227 long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.SECOND);
228 assertEquals(millis, testResult);
229 assertEquals(aCalendar.get(Calendar.MILLISECOND), testResult);
230 }
231
232 //Calendar.MINUTE as useful fragment
233
234 public void testMillisecondsOfMinuteWithDate() {
235 long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.MINUTE);
236 assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND), testResult);
237 }
238
239 public void testMillisecondsOfMinuteWithCalender() {
240 long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.MINUTE);
241 assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND), testResult);
242 }
243
244 public void testSecondsofMinuteWithDate() {
245 long testResult = DateUtils.getFragmentInSeconds(aDate, Calendar.MINUTE);
246 assertEquals(seconds, testResult);
247 }
248
249 public void testSecondsofMinuteWithCalendar() {
250 long testResult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.MINUTE);
251 assertEquals(seconds, testResult);
252 assertEquals(aCalendar.get(Calendar.SECOND), testResult);
253 }
254
255 //Calendar.HOUR_OF_DAY as useful fragment
256
257 public void testMillisecondsOfHourWithDate() {
258 long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.HOUR_OF_DAY);
259 assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE), testResult);
260 }
261
262 public void testMillisecondsOfHourWithCalendar() {
263 long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.HOUR_OF_DAY);
264 assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE), testResult);
265 }
266
267 public void testSecondsofHourWithDate() {
268 long testResult = DateUtils.getFragmentInSeconds(aDate, Calendar.HOUR_OF_DAY);
269 assertEquals(
270 seconds
271 + (minutes
272 * DateUtils.MILLIS_PER_MINUTE / DateUtils.MILLIS_PER_SECOND),
273 testResult);
274 }
275
276 public void testSecondsofHourWithCalendar() {
277 long testResult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.HOUR_OF_DAY);
278 assertEquals(
279 seconds
280 + (minutes
281 * DateUtils.MILLIS_PER_MINUTE / DateUtils.MILLIS_PER_SECOND),
282 testResult);
283 }
284
285 public void testMinutesOfHourWithDate() {
286 long testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.HOUR_OF_DAY);
287 assertEquals(minutes, testResult);
288 }
289
290 public void testMinutesOfHourWithCalendar() {
291 long testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.HOUR_OF_DAY);
292 assertEquals(minutes, testResult);
293 }
294
295 //Calendar.DATE and Calendar.DAY_OF_YEAR as useful fragment
296 public void testMillisecondsOfDayWithDate() {
297 long testresult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.DATE);
298 long expectedValue = millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR);
299 assertEquals(expectedValue, testresult);
300 testresult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.DAY_OF_YEAR);
301 assertEquals(expectedValue, testresult);
302 }
303
304 public void testMillisecondsOfDayWithCalendar() {
305 long testresult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.DATE);
306 long expectedValue = millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR);
307 assertEquals(expectedValue, testresult);
308 testresult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.DAY_OF_YEAR);
309 assertEquals(expectedValue, testresult);
310 }
311
312 public void testSecondsOfDayWithDate() {
313 long testresult = DateUtils.getFragmentInSeconds(aDate, Calendar.DATE);
314 long expectedValue = seconds + ((minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR))/ DateUtils.MILLIS_PER_SECOND;
315 assertEquals(expectedValue, testresult);
316 testresult = DateUtils.getFragmentInSeconds(aDate, Calendar.DAY_OF_YEAR);
317 assertEquals(expectedValue, testresult);
318 }
319
320 public void testSecondsOfDayWithCalendar() {
321 long testresult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.DATE);
322 long expectedValue = seconds + ((minutes * DateUtils.MILLIS_PER_MINUTE) + (hours * DateUtils.MILLIS_PER_HOUR))/ DateUtils.MILLIS_PER_SECOND;
323 assertEquals(expectedValue, testresult);
324 testresult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.DAY_OF_YEAR);
325 assertEquals(expectedValue, testresult);
326 }
327
328 public void testMinutesOfDayWithDate() {
329 long testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.DATE);
330 long expectedValue = minutes + ((hours * DateUtils.MILLIS_PER_HOUR))/ DateUtils.MILLIS_PER_MINUTE;
331 assertEquals(expectedValue,testResult);
332 testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.DAY_OF_YEAR);
333 assertEquals(expectedValue,testResult);
334 }
335
336 public void testMinutesOfDayWithCalendar() {
337 long testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.DATE);
338 long expectedValue = minutes + ((hours * DateUtils.MILLIS_PER_HOUR))/ DateUtils.MILLIS_PER_MINUTE;
339 assertEquals(expectedValue, testResult);
340 testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.DAY_OF_YEAR);
341 assertEquals(expectedValue, testResult);
342 }
343
344 public void testHoursOfDayWithDate() {
345 long testResult = DateUtils.getFragmentInHours(aDate, Calendar.DATE);
346 long expectedValue = hours;
347 assertEquals(expectedValue,testResult);
348 testResult = DateUtils.getFragmentInHours(aDate, Calendar.DAY_OF_YEAR);
349 assertEquals(expectedValue,testResult);
350 }
351
352 public void testHoursOfDayWithCalendar() {
353 long testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.DATE);
354 long expectedValue = hours;
355 assertEquals(expectedValue, testResult);
356 testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.DAY_OF_YEAR);
357 assertEquals(expectedValue, testResult);
358 }
359
360
361 //Calendar.MONTH as useful fragment
362 public void testMillisecondsOfMonthWithDate() {
363 long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.MONTH);
364 assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE)
365 + (hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY),
366 testResult);
367 }
368
369 public void testMillisecondsOfMonthWithCalendar() {
370 long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.MONTH);
371 assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE)
372 + (hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY),
373 testResult);
374 }
375
376 public void testSecondsOfMonthWithDate() {
377 long testResult = DateUtils.getFragmentInSeconds(aDate, Calendar.MONTH);
378 assertEquals(
379 seconds
380 + ((minutes * DateUtils.MILLIS_PER_MINUTE)
381 + (hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY))
382 / DateUtils.MILLIS_PER_SECOND,
383 testResult);
384 }
385
386 public void testSecondsOfMonthWithCalendar() {
387 long testResult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.MONTH);
388 assertEquals(
389 seconds
390 + ((minutes * DateUtils.MILLIS_PER_MINUTE)
391 + (hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY))
392 / DateUtils.MILLIS_PER_SECOND,
393 testResult);
394 }
395
396 public void testMinutesOfMonthWithDate() {
397 long testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.MONTH);
398 assertEquals(minutes
399 + ((hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY))
400 / DateUtils.MILLIS_PER_MINUTE,
401 testResult);
402 }
403
404 public void testMinutesOfMonthWithCalendar() {
405 long testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.MONTH);
406 assertEquals( minutes +((hours * DateUtils.MILLIS_PER_HOUR) + (days * DateUtils.MILLIS_PER_DAY))
407 / DateUtils.MILLIS_PER_MINUTE,
408 testResult);
409 }
410
411 public void testHoursOfMonthWithDate() {
412 long testResult = DateUtils.getFragmentInHours(aDate, Calendar.MONTH);
413 assertEquals(hours + ((days * DateUtils.MILLIS_PER_DAY))
414 / DateUtils.MILLIS_PER_HOUR,
415 testResult);
416 }
417
418 public void testHoursOfMonthWithCalendar() {
419 long testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.MONTH);
420 assertEquals( hours +((days * DateUtils.MILLIS_PER_DAY))
421 / DateUtils.MILLIS_PER_HOUR,
422 testResult);
423 }
424
425 //Calendar.YEAR as useful fragment
426 public void testMillisecondsOfYearWithDate() {
427 long testResult = DateUtils.getFragmentInMilliseconds(aDate, Calendar.YEAR);
428 Calendar cal = Calendar.getInstance();
429 cal.setTime(aDate);
430 assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE)
431 + (hours * DateUtils.MILLIS_PER_HOUR) + (cal.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY),
432 testResult);
433 }
434
435 public void testMillisecondsOfYearWithCalendar() {
436 long testResult = DateUtils.getFragmentInMilliseconds(aCalendar, Calendar.YEAR);
437 assertEquals(millis + (seconds * DateUtils.MILLIS_PER_SECOND) + (minutes * DateUtils.MILLIS_PER_MINUTE)
438 + (hours * DateUtils.MILLIS_PER_HOUR) + (aCalendar.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY),
439 testResult);
440 }
441
442 public void testSecondsOfYearWithDate() {
443 long testResult = DateUtils.getFragmentInSeconds(aDate, Calendar.YEAR);
444 Calendar cal = Calendar.getInstance();
445 cal.setTime(aDate);
446 assertEquals(
447 seconds
448 + ((minutes * DateUtils.MILLIS_PER_MINUTE)
449 + (hours * DateUtils.MILLIS_PER_HOUR) + (cal.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
450 / DateUtils.MILLIS_PER_SECOND,
451 testResult);
452 }
453
454 public void testSecondsOfYearWithCalendar() {
455 long testResult = DateUtils.getFragmentInSeconds(aCalendar, Calendar.YEAR);
456 assertEquals(
457 seconds
458 + ((minutes * DateUtils.MILLIS_PER_MINUTE)
459 + (hours * DateUtils.MILLIS_PER_HOUR) + (aCalendar.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
460 / DateUtils.MILLIS_PER_SECOND,
461 testResult);
462 }
463
464 public void testMinutesOfYearWithDate() {
465 long testResult = DateUtils.getFragmentInMinutes(aDate, Calendar.YEAR);
466 Calendar cal = Calendar.getInstance();
467 cal.setTime(aDate);
468 assertEquals(minutes
469 + ((hours * DateUtils.MILLIS_PER_HOUR) + (cal.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
470 / DateUtils.MILLIS_PER_MINUTE,
471 testResult);
472 }
473
474 public void testMinutesOfYearWithCalendar() {
475 long testResult = DateUtils.getFragmentInMinutes(aCalendar, Calendar.YEAR);
476 assertEquals( minutes +((hours * DateUtils.MILLIS_PER_HOUR) + (aCalendar.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
477 / DateUtils.MILLIS_PER_MINUTE,
478 testResult);
479 }
480
481 public void testHoursOfYearWithDate() {
482 long testResult = DateUtils.getFragmentInHours(aDate, Calendar.YEAR);
483 Calendar cal = Calendar.getInstance();
484 cal.setTime(aDate);
485 assertEquals(hours + ((cal.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
486 / DateUtils.MILLIS_PER_HOUR,
487 testResult);
488 }
489
490 public void testHoursOfYearWithCalendar() {
491 long testResult = DateUtils.getFragmentInHours(aCalendar, Calendar.YEAR);
492 assertEquals( hours +((aCalendar.get(Calendar.DAY_OF_YEAR) * DateUtils.MILLIS_PER_DAY))
493 / DateUtils.MILLIS_PER_HOUR,
494 testResult);
495 }
496 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import java.text.DateFormat;
19 import java.text.SimpleDateFormat;
20 import java.util.Calendar;
21 import java.util.Date;
22 import java.util.Locale;
23
24 import junit.framework.TestCase;
25
26 /**
27 * These Unit-tests will check all possible extremes when using some rounding-methods of DateUtils.
28 * The extremes are tested at the switch-point in milliseconds
29 *
30 * According to the implementation SEMI_MONTH will either round/truncate to the 1st or 16th
31 * When rounding Calendar.MONTH it depends on the number of days within that month.
32 * A month with 28 days will be rounded up from the 15th
33 * A month with 29 or 30 days will be rounded up from the 16th
34 * A month with 31 days will be rounded up from the 17th
35 *
36 * @since 3.0
37 * @version $Id: DateUtilsRoundingTest.java 1088899 2011-04-05 05:31:27Z bayard $
38 */
39 public class DateUtilsRoundingTest extends TestCase {
40
41 DateFormat dateTimeParser;
42
43 Date januaryOneDate;
44 Date targetYearDate;
45 //No targetMonths, these must be tested for every type of month(28-31 days)
46 Date targetDateDate, targetDayOfMonthDate, targetAmDate, targetPmDate;
47 Date targetHourOfDayDate, targetHourDate;
48 Date targetMinuteDate;
49 Date targetSecondDate;
50 Date targetMilliSecondDate;
51
52 Calendar januaryOneCalendar;
53 FastDateFormat fdf = DateFormatUtils.ISO_DATETIME_FORMAT;
54
55 @Override
56 protected void setUp() throws Exception {
57 super.setUp();
58 dateTimeParser = new SimpleDateFormat("MMM dd, yyyy H:mm:ss.SSS", Locale.ENGLISH);
59
60 targetYearDate = dateTimeParser.parse("January 1, 2007 0:00:00.000");
61 targetDateDate = targetDayOfMonthDate = dateTimeParser.parse("June 1, 2008 0:00:00.000");
62 targetAmDate = dateTimeParser.parse("June 1, 2008 0:00:00.000");
63 targetPmDate = dateTimeParser.parse("June 1, 2008 12:00:00.000");
64 targetHourDate = dateTimeParser.parse("June 1, 2008 8:00:00.000");
65 targetHourOfDayDate = dateTimeParser.parse("June 1, 2008 8:00:00.000");
66 targetMinuteDate = dateTimeParser.parse("June 1, 2008 8:15:00.000");
67 targetSecondDate = dateTimeParser.parse("June 1, 2008 8:15:14.000");
68 targetMilliSecondDate = dateTimeParser.parse("June 1, 2008 8:15:14.231");
69
70 januaryOneDate = dateTimeParser.parse("January 1, 2008 0:00:00.000");
71 januaryOneCalendar = Calendar.getInstance();
72 januaryOneCalendar.setTime(januaryOneDate);
73 }
74
75 /**
76 * Tests DateUtils.round()-method with Calendar.Year
77 *
78 * @throws Exception
79 * @since 3.0
80 */
81 public void testRoundYear() throws Exception {
82 final int calendarField = Calendar.YEAR;
83 Date roundedUpDate = dateTimeParser.parse("January 1, 2008 0:00:00.000");
84 Date roundedDownDate = targetYearDate;
85 Date lastRoundedDownDate = dateTimeParser.parse("June 30, 2007 23:59:59.999");
86 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
87 }
88
89 /**
90 * Tests DateUtils.round()-method with Calendar.MONTH
91 * Includes rounding months with 28, 29, 30 and 31 days
92 * Includes rounding to January 1
93 *
94 * @throws Exception
95 * @since 3.0
96 */
97 public void testRoundMonth() throws Exception {
98 final int calendarField = Calendar.MONTH;
99 Date roundedUpDate, roundedDownDate, lastRoundedDownDate;
100 Date minDate, maxDate;
101
102 //month with 28 days
103 roundedUpDate = dateTimeParser.parse("March 1, 2007 0:00:00.000");
104 roundedDownDate = dateTimeParser.parse("February 1, 2007 0:00:00.000");
105 lastRoundedDownDate = dateTimeParser.parse("February 14, 2007 23:59:59.999");
106 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
107
108 //month with 29 days
109 roundedUpDate = dateTimeParser.parse("March 1, 2008 0:00:00.000");
110 roundedDownDate = dateTimeParser.parse("February 1, 2008 0:00:00.000");
111 lastRoundedDownDate = dateTimeParser.parse("February 15, 2008 23:59:59.999");
112 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
113
114 //month with 30 days
115 roundedUpDate = dateTimeParser.parse("May 1, 2008 0:00:00.000");
116 roundedDownDate = dateTimeParser.parse("April 1, 2008 0:00:00.000");
117 lastRoundedDownDate = dateTimeParser.parse("April 15, 2008 23:59:59.999");
118 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
119
120 //month with 31 days
121 roundedUpDate = dateTimeParser.parse("June 1, 2008 0:00:00.000");
122 roundedDownDate = dateTimeParser.parse("May 1, 2008 0:00:00.000");
123 lastRoundedDownDate = dateTimeParser.parse("May 16, 2008 23:59:59.999");
124 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
125
126 //round to January 1
127 minDate = dateTimeParser.parse("December 17, 2007 00:00:00.000");
128 maxDate = dateTimeParser.parse("January 16, 2008 23:59:59.999");
129 roundToJanuaryFirst(minDate, maxDate, calendarField);
130 }
131
132 /**
133 * Tests DateUtils.round()-method with DateUtils.SEMI_MONTH
134 * Includes rounding months with 28, 29, 30 and 31 days, each with first and second half
135 * Includes rounding to January 1
136 *
137 * @throws Exception
138 * @since 3.0
139 */
140 public void testRoundSemiMonth() throws Exception {
141 final int calendarField = DateUtils.SEMI_MONTH;
142 Date roundedUpDate, roundedDownDate, lastRoundedDownDate;
143 Date minDate, maxDate;
144
145 //month with 28 days (1)
146 roundedUpDate = dateTimeParser.parse("February 16, 2007 0:00:00.000");
147 roundedDownDate = dateTimeParser.parse("February 1, 2007 0:00:00.000");
148 lastRoundedDownDate = dateTimeParser.parse("February 8, 2007 23:59:59.999");
149 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
150
151 //month with 28 days (2)
152 roundedUpDate = dateTimeParser.parse("March 1, 2007 0:00:00.000");
153 roundedDownDate = dateTimeParser.parse("February 16, 2007 0:00:00.000");
154 lastRoundedDownDate = dateTimeParser.parse("February 23, 2007 23:59:59.999");
155 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
156
157 //month with 29 days (1)
158 roundedUpDate = dateTimeParser.parse("February 16, 2008 0:00:00.000");
159 roundedDownDate = dateTimeParser.parse("February 1, 2008 0:00:00.000");
160 lastRoundedDownDate = dateTimeParser.parse("February 8, 2008 23:59:59.999");
161 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
162
163 //month with 29 days (2)
164 roundedUpDate = dateTimeParser.parse("March 1, 2008 0:00:00.000");
165 roundedDownDate = dateTimeParser.parse("February 16, 2008 0:00:00.000");
166 lastRoundedDownDate = dateTimeParser.parse("February 23, 2008 23:59:59.999");
167 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
168
169 //month with 30 days (1)
170 roundedUpDate = dateTimeParser.parse("April 16, 2008 0:00:00.000");
171 roundedDownDate = dateTimeParser.parse("April 1, 2008 0:00:00.000");
172 lastRoundedDownDate = dateTimeParser.parse("April 8, 2008 23:59:59.999");
173 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
174
175 //month with 30 days (2)
176 roundedUpDate = dateTimeParser.parse("May 1, 2008 0:00:00.000");
177 roundedDownDate = dateTimeParser.parse("April 16, 2008 0:00:00.000");
178 lastRoundedDownDate = dateTimeParser.parse("April 23, 2008 23:59:59.999");
179 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
180
181 //month with 31 days (1)
182 roundedUpDate = dateTimeParser.parse("May 16, 2008 0:00:00.000");
183 roundedDownDate = dateTimeParser.parse("May 1, 2008 0:00:00.000");
184 lastRoundedDownDate = dateTimeParser.parse("May 8, 2008 23:59:59.999");
185 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
186
187 //month with 31 days (2)
188 roundedUpDate = dateTimeParser.parse("June 1, 2008 0:00:00.000");
189 roundedDownDate = dateTimeParser.parse("May 16, 2008 0:00:00.000");
190 lastRoundedDownDate = dateTimeParser.parse("May 23, 2008 23:59:59.999");
191 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
192
193 //round to January 1
194 minDate = dateTimeParser.parse("December 24, 2007 00:00:00.000");
195 maxDate = dateTimeParser.parse("January 8, 2008 23:59:59.999");
196 roundToJanuaryFirst(minDate, maxDate, calendarField);
197 }
198
199 /**
200 * Tests DateUtils.round()-method with Calendar.DATE
201 * Includes rounding the extremes of one day
202 * Includes rounding to January 1
203 *
204 * @throws Exception
205 * @since 3.0
206 */
207 public void testRoundDate() throws Exception {
208 final int calendarField = Calendar.DATE;
209 Date roundedUpDate, roundedDownDate, lastRoundedDownDate;
210 Date minDate, maxDate;
211
212 roundedUpDate = dateTimeParser.parse("June 2, 2008 0:00:00.000");
213 roundedDownDate = targetDateDate;
214 lastRoundedDownDate = dateTimeParser.parse("June 1, 2008 11:59:59.999");
215 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
216
217 //round to January 1
218 minDate = dateTimeParser.parse("December 31, 2007 12:00:00.000");
219 maxDate = dateTimeParser.parse("January 1, 2008 11:59:59.999");
220 roundToJanuaryFirst(minDate, maxDate, calendarField);
221 }
222
223 /**
224 * Tests DateUtils.round()-method with Calendar.DAY_OF_MONTH
225 * Includes rounding the extremes of one day
226 * Includes rounding to January 1
227 *
228 * @throws Exception
229 * @since 3.0
230 */
231 public void testRoundDayOfMonth() throws Exception {
232 final int calendarField = Calendar.DAY_OF_MONTH;
233 Date roundedUpDate, roundedDownDate, lastRoundedDownDate;
234 Date minDate, maxDate;
235
236 roundedUpDate = dateTimeParser.parse("June 2, 2008 0:00:00.000");
237 roundedDownDate = targetDayOfMonthDate;
238 lastRoundedDownDate = dateTimeParser.parse("June 1, 2008 11:59:59.999");
239 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
240
241 //round to January 1
242 minDate = dateTimeParser.parse("December 31, 2007 12:00:00.000");
243 maxDate = dateTimeParser.parse("January 1, 2008 11:59:59.999");
244 roundToJanuaryFirst(minDate, maxDate, calendarField);
245 }
246
247 /**
248 * Tests DateUtils.round()-method with Calendar.AM_PM
249 * Includes rounding the extremes of both AM and PM of one day
250 * Includes rounding to January 1
251 *
252 * @throws Exception
253 * @since 3.0
254 */
255 public void testRoundAmPm() throws Exception {
256 final int calendarField = Calendar.AM_PM;
257 Date roundedUpDate, roundedDownDate, lastRoundedDownDate;
258 Date minDate, maxDate;
259
260 //AM
261 roundedUpDate = dateTimeParser.parse("June 1, 2008 12:00:00.000");
262 roundedDownDate = targetAmDate;
263 lastRoundedDownDate = dateTimeParser.parse("June 1, 2008 5:59:59.999");
264 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
265
266 //PM
267 roundedUpDate = dateTimeParser.parse("June 2, 2008 0:00:00.000");
268 roundedDownDate = targetPmDate;
269 lastRoundedDownDate = dateTimeParser.parse("June 1, 2008 17:59:59.999");
270 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
271
272 //round to January 1
273 minDate = dateTimeParser.parse("December 31, 2007 18:00:00.000");
274 maxDate = dateTimeParser.parse("January 1, 2008 5:59:59.999");
275 roundToJanuaryFirst(minDate, maxDate, calendarField);
276 }
277
278 /**
279 * Tests DateUtils.round()-method with Calendar.HOUR_OF_DAY
280 * Includes rounding the extremes of one hour
281 * Includes rounding to January 1
282 *
283 * @throws Exception
284 * @since 3.0
285 */
286 public void testRoundHourOfDay() throws Exception {
287 final int calendarField = Calendar.HOUR_OF_DAY;
288 Date roundedUpDate, roundedDownDate, lastRoundedDownDate;
289 Date minDate, maxDate;
290
291 roundedUpDate = dateTimeParser.parse("June 1, 2008 9:00:00.000");
292 roundedDownDate = targetHourOfDayDate;
293 lastRoundedDownDate = dateTimeParser.parse("June 1, 2008 8:29:59.999");
294 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
295
296 //round to January 1
297 minDate = dateTimeParser.parse("December 31, 2007 23:30:00.000");
298 maxDate = dateTimeParser.parse("January 1, 2008 0:29:59.999");
299 roundToJanuaryFirst(minDate, maxDate, calendarField);
300 }
301
302 /**
303 * Tests DateUtils.round()-method with Calendar.HOUR
304 * Includes rounding the extremes of one hour
305 * Includes rounding to January 1
306 *
307 * @throws Exception
308 * @since 3.0
309 */
310 public void testRoundHour() throws Exception {
311 final int calendarField = Calendar.HOUR;
312 Date roundedUpDate, roundedDownDate, lastRoundedDownDate;
313 Date minDate, maxDate;
314
315 roundedUpDate = dateTimeParser.parse("June 1, 2008 9:00:00.000");
316 roundedDownDate = targetHourDate;
317 lastRoundedDownDate = dateTimeParser.parse("June 1, 2008 8:29:59.999");
318 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
319
320 //round to January 1
321 minDate = dateTimeParser.parse("December 31, 2007 23:30:00.000");
322 maxDate = dateTimeParser.parse("January 1, 2008 0:29:59.999");
323 roundToJanuaryFirst(minDate, maxDate, calendarField);
324 }
325
326 /**
327 * Tests DateUtils.round()-method with Calendar.MINUTE
328 * Includes rounding the extremes of one minute
329 * Includes rounding to January 1
330 *
331 * @throws Exception
332 * @since 3.0
333 */
334 public void testRoundMinute() throws Exception {
335 final int calendarField = Calendar.MINUTE;
336 Date roundedUpDate, roundedDownDate, lastRoundedDownDate;
337 Date minDate, maxDate;
338
339 roundedUpDate = dateTimeParser.parse("June 1, 2008 8:16:00.000");
340 roundedDownDate = targetMinuteDate;
341 lastRoundedDownDate = dateTimeParser.parse("June 1, 2008 8:15:29.999");
342 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
343
344 //round to January 1
345 minDate = dateTimeParser.parse("December 31, 2007 23:59:30.000");
346 maxDate = dateTimeParser.parse("January 1, 2008 0:00:29.999");
347 roundToJanuaryFirst(minDate, maxDate, calendarField);
348 }
349
350 /**
351 * Tests DateUtils.round()-method with Calendar.SECOND
352 * Includes rounding the extremes of one second
353 * Includes rounding to January 1
354 *
355 * @throws Exception
356 * @since 3.0
357 */
358 public void testRoundSecond() throws Exception {
359 final int calendarField = Calendar.SECOND;
360 Date roundedUpDate, roundedDownDate, lastRoundedDownDate;
361 Date minDate, maxDate;
362
363 roundedUpDate = dateTimeParser.parse("June 1, 2008 8:15:15.000");
364 roundedDownDate = targetSecondDate;
365 lastRoundedDownDate = dateTimeParser.parse("June 1, 2008 8:15:14.499");
366 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
367
368 //round to January 1
369 minDate = dateTimeParser.parse("December 31, 2007 23:59:59.500");
370 maxDate = dateTimeParser.parse("January 1, 2008 0:00:00.499");
371 roundToJanuaryFirst(minDate, maxDate, calendarField);
372 }
373
374 /**
375 * Tests DateUtils.round()-method with Calendar.MILLISECOND
376 * Includes rounding the extremes of one second
377 * Includes rounding to January 1
378 *
379 * @throws Exception
380 * @since 3.0
381 */
382 public void testRoundMilliSecond() throws Exception {
383 final int calendarField = Calendar.MILLISECOND;
384 Date roundedUpDate, roundedDownDate, lastRoundedDownDate;
385 Date minDate, maxDate;
386
387 roundedDownDate = lastRoundedDownDate = targetMilliSecondDate;
388 roundedUpDate = dateTimeParser.parse("June 1, 2008 8:15:14.232");
389 baseRoundTest(roundedUpDate, roundedDownDate, lastRoundedDownDate, calendarField);
390
391 //round to January 1
392 minDate = maxDate = januaryOneDate;
393 roundToJanuaryFirst(minDate, maxDate, calendarField);
394 }
395
396 /**
397 * Test DateUtils.truncate()-method with Calendar.YEAR
398 *
399 * @throws Exception
400 * @since 3.0
401 */
402 public void testTruncateYear() throws Exception {
403 final int calendarField = Calendar.YEAR;
404 Date lastTruncateDate = dateTimeParser.parse("December 31, 2007 23:59:59.999");
405 baseTruncateTest(targetYearDate, lastTruncateDate, calendarField);
406 }
407
408 /**
409 * Test DateUtils.truncate()-method with Calendar.MONTH
410 *
411 * @throws Exception
412 * @since 3.0
413 */
414 public void testTruncateMonth() throws Exception {
415 final int calendarField = Calendar.MONTH;
416 Date truncatedDate = dateTimeParser.parse("March 1, 2008 0:00:00.000");
417 Date lastTruncateDate = dateTimeParser.parse("March 31, 2008 23:59:59.999");
418 baseTruncateTest(truncatedDate, lastTruncateDate, calendarField);
419 }
420
421 /**
422 * Test DateUtils.truncate()-method with DateUtils.SEMI_MONTH
423 * Includes truncating months with 28, 29, 30 and 31 days, each with first and second half
424 *
425 * @throws Exception
426 * @since 3.0
427 */
428 public void testTruncateSemiMonth() throws Exception {
429 final int calendarField = DateUtils.SEMI_MONTH;
430 Date truncatedDate, lastTruncateDate;
431
432 //month with 28 days (1)
433 truncatedDate = dateTimeParser.parse("February 1, 2007 0:00:00.000");
434 lastTruncateDate = dateTimeParser.parse("February 15, 2007 23:59:59.999");
435 baseTruncateTest(truncatedDate, lastTruncateDate, calendarField);
436
437 //month with 28 days (2)
438 truncatedDate = dateTimeParser.parse("February 16, 2007 0:00:00.000");
439 lastTruncateDate = dateTimeParser.parse("February 28, 2007 23:59:59.999");
440 baseTruncateTest(truncatedDate, lastTruncateDate, calendarField);
441
442 //month with 29 days (1)
443 truncatedDate = dateTimeParser.parse("February 1, 2008 0:00:00.000");
444 lastTruncateDate = dateTimeParser.parse("February 15, 2008 23:59:59.999");
445 baseTruncateTest(truncatedDate, lastTruncateDate, calendarField);
446
447 //month with 29 days (2)
448 truncatedDate = dateTimeParser.parse("February 16, 2008 0:00:00.000");
449 lastTruncateDate = dateTimeParser.parse("February 29, 2008 23:59:59.999");
450 baseTruncateTest(truncatedDate, lastTruncateDate, calendarField);
451
452 //month with 30 days (1)
453 truncatedDate = dateTimeParser.parse("April 1, 2008 0:00:00.000");
454 lastTruncateDate = dateTimeParser.parse("April 15, 2008 23:59:59.999");
455 baseTruncateTest(truncatedDate, lastTruncateDate, calendarField);
456
457 //month with 30 days (2)
458 truncatedDate = dateTimeParser.parse("April 16, 2008 0:00:00.000");
459 lastTruncateDate = dateTimeParser.parse("April 30, 2008 23:59:59.999");
460 baseTruncateTest(truncatedDate, lastTruncateDate, calendarField);
461
462 //month with 31 days (1)
463 truncatedDate = dateTimeParser.parse("March 1, 2008 0:00:00.000");
464 lastTruncateDate = dateTimeParser.parse("March 15, 2008 23:59:59.999");
465 baseTruncateTest(truncatedDate, lastTruncateDate, calendarField);
466
467 //month with 31 days (2)
468 truncatedDate = dateTimeParser.parse("March 16, 2008 0:00:00.000");
469 lastTruncateDate = dateTimeParser.parse("March 31, 2008 23:59:59.999");
470 baseTruncateTest(truncatedDate, lastTruncateDate, calendarField);
471
472 }
473
474 /**
475 * Test DateUtils.truncate()-method with Calendar.DATE
476 *
477 * @throws Exception
478 * @since 3.0
479 */
480 public void testTruncateDate() throws Exception {
481 final int calendarField = Calendar.DATE;
482 Date lastTruncateDate = dateTimeParser.parse("June 1, 2008 23:59:59.999");
483 baseTruncateTest(targetDateDate, lastTruncateDate, calendarField);
484 }
485
486 /**
487 * Test DateUtils.truncate()-method with Calendar.DAY_OF_MONTH
488 *
489 * @throws Exception
490 * @since 3.0
491 */
492 public void testTruncateDayOfMonth() throws Exception {
493 final int calendarField = Calendar.DAY_OF_MONTH;
494 Date lastTruncateDate = dateTimeParser.parse("June 1, 2008 23:59:59.999");
495 baseTruncateTest(targetDayOfMonthDate, lastTruncateDate, calendarField);
496 }
497
498 /**
499 * Test DateUtils.truncate()-method with Calendar.AM_PM
500 * Includes truncating the extremes of both AM and PM of one day
501 *
502 * @throws Exception
503 * @since 3.0
504 */
505 public void testTruncateAmPm() throws Exception {
506 final int calendarField = Calendar.AM_PM;
507
508 //AM
509 Date lastTruncateDate = dateTimeParser.parse("June 1, 2008 11:59:59.999");
510 baseTruncateTest(targetAmDate, lastTruncateDate, calendarField);
511
512 //PM
513 lastTruncateDate = dateTimeParser.parse("June 1, 2008 23:59:59.999");
514 baseTruncateTest(targetPmDate, lastTruncateDate, calendarField);
515 }
516
517 /**
518 * Test DateUtils.truncate()-method with Calendar.HOUR
519 *
520 * @throws Exception
521 * @since 3.0
522 */
523 public void testTruncateHour() throws Exception {
524 final int calendarField = Calendar.HOUR;
525 Date lastTruncateDate = dateTimeParser.parse("June 1, 2008 8:59:59.999");
526 baseTruncateTest(targetHourDate, lastTruncateDate, calendarField);
527 }
528
529 /**
530 * Test DateUtils.truncate()-method with Calendar.HOUR_OF_DAY
531 *
532 * @throws Exception
533 * @since 3.0
534 */
535 public void testTruncateHourOfDay() throws Exception {
536 final int calendarField = Calendar.HOUR_OF_DAY;
537 Date lastTruncateDate = dateTimeParser.parse("June 1, 2008 8:59:59.999");
538 baseTruncateTest(targetHourOfDayDate, lastTruncateDate, calendarField);
539 }
540
541 /**
542 * Test DateUtils.truncate()-method with Calendar.MINUTE
543 *
544 * @throws Exception
545 * @since 3.0
546 */
547 public void testTruncateMinute() throws Exception {
548 final int calendarField = Calendar.MINUTE;
549 Date lastTruncateDate = dateTimeParser.parse("June 1, 2008 8:15:59.999");
550 baseTruncateTest(targetMinuteDate, lastTruncateDate, calendarField);
551 }
552
553 /**
554 * Test DateUtils.truncate()-method with Calendar.SECOND
555 *
556 * @throws Exception
557 * @since 3.0
558 */
559 public void testTruncateSecond() throws Exception {
560 final int calendarField = Calendar.SECOND;
561 Date lastTruncateDate = dateTimeParser.parse("June 1, 2008 8:15:14.999");
562 baseTruncateTest(targetSecondDate, lastTruncateDate, calendarField);
563 }
564
565 /**
566 * Test DateUtils.truncate()-method with Calendar.SECOND
567 *
568 * @throws Exception
569 * @since 3.0
570 */
571 public void testTruncateMilliSecond() throws Exception {
572 final int calendarField = Calendar.MILLISECOND;
573 baseTruncateTest(targetMilliSecondDate, targetMilliSecondDate, calendarField);
574 }
575
576 /**
577 * When using this basetest all extremes are tested.<br>
578 * It will test the Date, Calendar and Object-implementation<br>
579 * lastRoundDownDate should round down to roundedDownDate<br>
580 * lastRoundDownDate + 1 millisecond should round up to roundedUpDate
581 *
582 * @param roundedUpDate the next rounded date after <strong>roundedDownDate</strong> when using <strong>calendarField</strong>
583 * @param roundedDownDate the result if <strong>lastRoundDownDate</strong> was rounded with <strong>calendarField</strong>
584 * @param lastRoundDownDate rounding this value with <strong>calendarField</strong> will result in <strong>roundedDownDate</strong>
585 * @param calendarField
586 * @since 3.0
587 */
588 protected void baseRoundTest(final Date roundedUpDate, final Date roundedDownDate, final Date lastRoundDownDate, final int calendarField) {
589 Date firstRoundUpDate = DateUtils.addMilliseconds(lastRoundDownDate, 1);
590
591 //Date-comparison
592 assertEquals(roundedDownDate, DateUtils.round(roundedDownDate, calendarField));
593 assertEquals(roundedUpDate, DateUtils.round(roundedUpDate, calendarField));
594 assertEquals(roundedDownDate, DateUtils.round(lastRoundDownDate, calendarField));
595 assertEquals(roundedUpDate, DateUtils.round(firstRoundUpDate, calendarField));
596
597 //Calendar-initiations
598 Calendar roundedUpCalendar, roundedDownCalendar, lastRoundDownCalendar, firstRoundUpCalendar;
599 roundedDownCalendar = Calendar.getInstance();
600 roundedUpCalendar = Calendar.getInstance();
601 lastRoundDownCalendar = Calendar.getInstance();
602 firstRoundUpCalendar = Calendar.getInstance();
603 roundedDownCalendar.setTime(roundedDownDate);
604 roundedUpCalendar.setTime(roundedUpDate);
605 lastRoundDownCalendar.setTime(lastRoundDownDate);
606 firstRoundUpCalendar.setTime(firstRoundUpDate);
607
608 //Calendar-comparison
609 assertEquals(roundedDownCalendar, DateUtils.round(roundedDownCalendar, calendarField));
610 assertEquals(roundedUpCalendar, DateUtils.round(roundedUpCalendar, calendarField));
611 assertEquals(roundedDownCalendar, DateUtils.round(lastRoundDownCalendar, calendarField));
612 assertEquals(roundedUpCalendar, DateUtils.round(firstRoundUpCalendar, calendarField));
613
614 //Object-comparison
615 assertEquals(roundedDownDate, DateUtils.round((Object) roundedDownDate, calendarField));
616 assertEquals(roundedUpDate, DateUtils.round((Object) roundedUpDate, calendarField));
617 assertEquals(roundedDownDate, DateUtils.round((Object) lastRoundDownDate, calendarField));
618 assertEquals(roundedUpDate, DateUtils.round((Object) firstRoundUpDate, calendarField));
619 assertEquals(roundedDownDate, DateUtils.round((Object) roundedDownCalendar, calendarField));
620 assertEquals(roundedUpDate, DateUtils.round((Object) roundedUpCalendar, calendarField));
621 assertEquals(roundedDownDate, DateUtils.round((Object) lastRoundDownDate, calendarField));
622 assertEquals(roundedUpDate, DateUtils.round((Object) firstRoundUpDate, calendarField));
623 }
624
625 /**
626 * When using this basetest all extremes are tested.<br>
627 * It will test the Date, Calendar and Object-implementation<br>
628 * lastTruncateDate should round down to truncatedDate<br>
629 * lastTruncateDate + 1 millisecond should never round down to truncatedDate
630 *
631 * @param truncatedDate expected Date when <strong>lastTruncateDate</strong> is truncated with <strong>calendarField</strong>
632 * @param lastTruncateDate the last possible Date which will truncate to <strong>truncatedDate</strong> with <strong>calendarField</strong>
633 * @param calendarField a Calendar.field value
634 * @since 3.0
635 */
636 protected void baseTruncateTest(final Date truncatedDate, final Date lastTruncateDate, final int calendarField) {
637 Date nextTruncateDate = DateUtils.addMilliseconds(lastTruncateDate, 1);
638
639 //Date-comparison
640 assertEquals("Truncating "+ fdf.format(truncatedDate) +" as Date with CalendarField-value "+ calendarField +" must return itself", truncatedDate, DateUtils.truncate(truncatedDate, calendarField));
641 assertEquals(truncatedDate, DateUtils.truncate(lastTruncateDate, calendarField));
642 assertFalse(fdf.format(lastTruncateDate) +" is not an extreme when truncating as Date with CalendarField-value "+ calendarField, truncatedDate.equals(DateUtils.truncate(nextTruncateDate, calendarField)));
643
644 //Calendar-initiations
645 Calendar truncatedCalendar, lastTruncateCalendar, nextTruncateCalendar;
646 truncatedCalendar = Calendar.getInstance();
647 lastTruncateCalendar = Calendar.getInstance();
648 nextTruncateCalendar = Calendar.getInstance();
649 truncatedCalendar.setTime(truncatedDate);
650 lastTruncateCalendar.setTime(lastTruncateDate);
651 nextTruncateCalendar.setTime(nextTruncateDate);
652
653 //Calendar-comparison
654 assertEquals("Truncating "+ fdf.format(truncatedCalendar) +" as Calendar with CalendarField-value "+ calendarField +" must return itself", truncatedCalendar, DateUtils.truncate(truncatedCalendar, calendarField));
655 assertEquals(truncatedCalendar, DateUtils.truncate(lastTruncateCalendar, calendarField));
656 assertFalse(fdf.format(lastTruncateCalendar) +" is not an extreme when truncating as Calendar with CalendarField-value "+ calendarField, truncatedCalendar.equals(DateUtils.truncate(nextTruncateCalendar, calendarField)));
657
658 //Object-comparison
659 assertEquals("Truncating "+ fdf.format(truncatedDate) +" as Date cast to Object with CalendarField-value "+ calendarField +" must return itself as Date", truncatedDate, DateUtils.truncate((Object) truncatedDate, calendarField));
660 assertEquals(truncatedDate, DateUtils.truncate((Object) lastTruncateDate, calendarField));
661 assertFalse(fdf.format(lastTruncateDate) +" is not an extreme when truncating as Date cast to Object with CalendarField-value "+ calendarField, truncatedDate.equals(DateUtils.truncate((Object) nextTruncateDate, calendarField)));
662 assertEquals("Truncating "+ fdf.format(truncatedCalendar) +" as Calendar cast to Object with CalendarField-value "+ calendarField +" must return itself as Date", truncatedDate, DateUtils.truncate((Object) truncatedCalendar, calendarField));
663 assertEquals(truncatedDate, DateUtils.truncate((Object) lastTruncateCalendar, calendarField));
664 assertFalse(fdf.format(lastTruncateCalendar) +" is not an extreme when truncating as Calendar cast to Object with CalendarField-value "+ calendarField, truncatedDate.equals(DateUtils.truncate((Object) nextTruncateCalendar, calendarField)));
665 }
666
667 /**
668 *
669 * Any January 1 could be considered as the ultimate extreme.
670 * Instead of comparing the results if the input has a difference of 1 millisecond we check the output to be exactly January first.
671 *
672 * @param minDate
673 * @param maxDate
674 * @param calendarField
675 * @since 3.0
676 */
677 protected void roundToJanuaryFirst(Date minDate, Date maxDate, int calendarField) {
678 assertEquals("Rounding "+ fdf.format(januaryOneDate) +" as Date with CalendarField-value "+ calendarField +" must return itself", januaryOneDate, DateUtils.round(januaryOneDate, calendarField));
679 assertEquals(januaryOneDate, DateUtils.round(minDate, calendarField));
680 assertEquals(januaryOneDate, DateUtils.round(maxDate, calendarField));
681
682 Calendar minCalendar = Calendar.getInstance();
683 minCalendar.setTime(minDate);
684 Calendar maxCalendar = Calendar.getInstance();
685 maxCalendar.setTime(maxDate);
686 assertEquals("Rounding "+ fdf.format(januaryOneCalendar) +" as Date with CalendarField-value "+ calendarField +" must return itself", januaryOneCalendar, DateUtils.round(januaryOneCalendar, calendarField));
687 assertEquals(januaryOneCalendar, DateUtils.round(minCalendar, calendarField));
688 assertEquals(januaryOneCalendar, DateUtils.round(maxCalendar, calendarField));
689
690 Date toPrevRoundDate = DateUtils.addMilliseconds(minDate, -1);
691 Date toNextRoundDate = DateUtils.addMilliseconds(maxDate, 1);
692 assertFalse(fdf.format(minDate) +" is not an lower-extreme when rounding as Date with CalendarField-value "+ calendarField, januaryOneDate.equals(DateUtils.round(toPrevRoundDate, calendarField)));
693 assertFalse(fdf.format(maxDate) +" is not an upper-extreme when rounding as Date with CalendarField-value "+ calendarField, januaryOneDate.equals(DateUtils.round(toNextRoundDate, calendarField)));
694
695 Calendar toPrevRoundCalendar = Calendar.getInstance();
696 toPrevRoundCalendar.setTime(toPrevRoundDate);
697 Calendar toNextRoundCalendar = Calendar.getInstance();
698 toNextRoundCalendar.setTime(toNextRoundDate);
699 assertFalse(fdf.format(minCalendar) +" is not an lower-extreme when rounding as Date with CalendarField-value "+ calendarField, januaryOneDate.equals(DateUtils.round(toPrevRoundDate, calendarField)));
700 assertFalse(fdf.format(maxCalendar) +" is not an upper-extreme when rounding as Date with CalendarField-value "+ calendarField, januaryOneDate.equals(DateUtils.round(toNextRoundDate, calendarField)));
701 }
702 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import static org.apache.commons.lang3.JavaVersion.JAVA_1_4;
19
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Modifier;
22 import java.text.DateFormat;
23 import java.text.ParseException;
24 import java.text.SimpleDateFormat;
25 import java.util.Calendar;
26 import java.util.Date;
27 import java.util.GregorianCalendar;
28 import java.util.Iterator;
29 import java.util.Locale;
30 import java.util.NoSuchElementException;
31 import java.util.TimeZone;
32
33 import junit.framework.AssertionFailedError;
34 import junit.framework.TestCase;
35
36 import org.apache.commons.lang3.SystemUtils;
37
38 /**
39 * Unit tests {@link org.apache.commons.lang3.time.DateUtils}.
40 *
41 */
42 public class DateUtilsTest extends TestCase {
43
44 private static final long MILLIS_TEST;
45 static {
46 GregorianCalendar cal = new GregorianCalendar(2000, 6, 5, 4, 3, 2);
47 cal.set(Calendar.MILLISECOND, 1);
48 MILLIS_TEST = cal.getTime().getTime();
49 }
50
51 DateFormat dateParser = null;
52 DateFormat dateTimeParser = null;
53 DateFormat timeZoneDateParser = null;
54 Date dateAmPm1 = null;
55 Date dateAmPm2 = null;
56 Date dateAmPm3 = null;
57 Date dateAmPm4 = null;
58 Date date0 = null;
59 Date date1 = null;
60 Date date2 = null;
61 Date date3 = null;
62 Date date4 = null;
63 Date date5 = null;
64 Date date6 = null;
65 Date date7 = null;
66 Date date8 = null;
67 Calendar calAmPm1 = null;
68 Calendar calAmPm2 = null;
69 Calendar calAmPm3 = null;
70 Calendar calAmPm4 = null;
71 Calendar cal1 = null;
72 Calendar cal2 = null;
73 Calendar cal3 = null;
74 Calendar cal4 = null;
75 Calendar cal5 = null;
76 Calendar cal6 = null;
77 Calendar cal7 = null;
78 Calendar cal8 = null;
79 TimeZone zone = null;
80 TimeZone defaultZone = null;
81
82 public DateUtilsTest(String name) {
83 super(name);
84 }
85
86 @Override
87 protected void setUp() throws Exception {
88 super.setUp();
89
90 dateParser = new SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH);
91 dateTimeParser = new SimpleDateFormat("MMM dd, yyyy H:mm:ss.SSS", Locale.ENGLISH);
92
93 dateAmPm1 = dateTimeParser.parse("February 3, 2002 01:10:00.000");
94 dateAmPm2 = dateTimeParser.parse("February 3, 2002 11:10:00.000");
95 dateAmPm3 = dateTimeParser.parse("February 3, 2002 13:10:00.000");
96 dateAmPm4 = dateTimeParser.parse("February 3, 2002 19:10:00.000");
97 date0 = dateTimeParser.parse("February 3, 2002 12:34:56.789");
98 date1 = dateTimeParser.parse("February 12, 2002 12:34:56.789");
99 date2 = dateTimeParser.parse("November 18, 2001 1:23:11.321");
100 defaultZone = TimeZone.getDefault();
101 zone = TimeZone.getTimeZone("MET");
102 TimeZone.setDefault(zone);
103 dateTimeParser.setTimeZone(zone);
104 date3 = dateTimeParser.parse("March 30, 2003 05:30:45.000");
105 date4 = dateTimeParser.parse("March 30, 2003 01:10:00.000");
106 date5 = dateTimeParser.parse("March 30, 2003 01:40:00.000");
107 date6 = dateTimeParser.parse("March 30, 2003 02:10:00.000");
108 date7 = dateTimeParser.parse("March 30, 2003 02:40:00.000");
109 date8 = dateTimeParser.parse("October 26, 2003 05:30:45.000");
110 dateTimeParser.setTimeZone(defaultZone);
111 TimeZone.setDefault(defaultZone);
112 calAmPm1 = Calendar.getInstance();
113 calAmPm1.setTime(dateAmPm1);
114 calAmPm2 = Calendar.getInstance();
115 calAmPm2.setTime(dateAmPm2);
116 calAmPm3 = Calendar.getInstance();
117 calAmPm3.setTime(dateAmPm3);
118 calAmPm4 = Calendar.getInstance();
119 calAmPm4.setTime(dateAmPm4);
120 cal1 = Calendar.getInstance();
121 cal1.setTime(date1);
122 cal2 = Calendar.getInstance();
123 cal2.setTime(date2);
124 TimeZone.setDefault(zone);
125 cal3 = Calendar.getInstance();
126 cal3.setTime(date3);
127 cal4 = Calendar.getInstance();
128 cal4.setTime(date4);
129 cal5 = Calendar.getInstance();
130 cal5.setTime(date5);
131 cal6 = Calendar.getInstance();
132 cal6.setTime(date6);
133 cal7 = Calendar.getInstance();
134 cal7.setTime(date7);
135 cal8 = Calendar.getInstance();
136 cal8.setTime(date8);
137 TimeZone.setDefault(defaultZone);
138 }
139
140 //-----------------------------------------------------------------------
141 public void testConstructor() {
142 assertNotNull(new DateUtils());
143 Constructor<?>[] cons = DateUtils.class.getDeclaredConstructors();
144 assertEquals(1, cons.length);
145 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
146 assertEquals(true, Modifier.isPublic(DateUtils.class.getModifiers()));
147 assertEquals(false, Modifier.isFinal(DateUtils.class.getModifiers()));
148 }
149
150 //-----------------------------------------------------------------------
151 public void testIsSameDay_Date() {
152 Date date1 = new GregorianCalendar(2004, 6, 9, 13, 45).getTime();
153 Date date2 = new GregorianCalendar(2004, 6, 9, 13, 45).getTime();
154 assertEquals(true, DateUtils.isSameDay(date1, date2));
155 date2 = new GregorianCalendar(2004, 6, 10, 13, 45).getTime();
156 assertEquals(false, DateUtils.isSameDay(date1, date2));
157 date1 = new GregorianCalendar(2004, 6, 10, 13, 45).getTime();
158 assertEquals(true, DateUtils.isSameDay(date1, date2));
159 date2 = new GregorianCalendar(2005, 6, 10, 13, 45).getTime();
160 assertEquals(false, DateUtils.isSameDay(date1, date2));
161 try {
162 DateUtils.isSameDay((Date) null, (Date) null);
163 fail();
164 } catch (IllegalArgumentException ex) {}
165 }
166
167 //-----------------------------------------------------------------------
168 public void testIsSameDay_Cal() {
169 GregorianCalendar cal1 = new GregorianCalendar(2004, 6, 9, 13, 45);
170 GregorianCalendar cal2 = new GregorianCalendar(2004, 6, 9, 13, 45);
171 assertEquals(true, DateUtils.isSameDay(cal1, cal2));
172 cal2.add(Calendar.DAY_OF_YEAR, 1);
173 assertEquals(false, DateUtils.isSameDay(cal1, cal2));
174 cal1.add(Calendar.DAY_OF_YEAR, 1);
175 assertEquals(true, DateUtils.isSameDay(cal1, cal2));
176 cal2.add(Calendar.YEAR, 1);
177 assertEquals(false, DateUtils.isSameDay(cal1, cal2));
178 try {
179 DateUtils.isSameDay((Calendar) null, (Calendar) null);
180 fail();
181 } catch (IllegalArgumentException ex) {}
182 }
183
184 //-----------------------------------------------------------------------
185 public void testIsSameInstant_Date() {
186 Date date1 = new GregorianCalendar(2004, 6, 9, 13, 45).getTime();
187 Date date2 = new GregorianCalendar(2004, 6, 9, 13, 45).getTime();
188 assertEquals(true, DateUtils.isSameInstant(date1, date2));
189 date2 = new GregorianCalendar(2004, 6, 10, 13, 45).getTime();
190 assertEquals(false, DateUtils.isSameInstant(date1, date2));
191 date1 = new GregorianCalendar(2004, 6, 10, 13, 45).getTime();
192 assertEquals(true, DateUtils.isSameInstant(date1, date2));
193 date2 = new GregorianCalendar(2005, 6, 10, 13, 45).getTime();
194 assertEquals(false, DateUtils.isSameInstant(date1, date2));
195 try {
196 DateUtils.isSameInstant((Date) null, (Date) null);
197 fail();
198 } catch (IllegalArgumentException ex) {}
199 }
200
201 //-----------------------------------------------------------------------
202 public void testIsSameInstant_Cal() {
203 GregorianCalendar cal1 = new GregorianCalendar(TimeZone.getTimeZone("GMT+1"));
204 GregorianCalendar cal2 = new GregorianCalendar(TimeZone.getTimeZone("GMT-1"));
205 cal1.set(2004, 6, 9, 13, 45, 0);
206 cal1.set(Calendar.MILLISECOND, 0);
207 cal2.set(2004, 6, 9, 13, 45, 0);
208 cal2.set(Calendar.MILLISECOND, 0);
209 assertEquals(false, DateUtils.isSameInstant(cal1, cal2));
210
211 cal2.set(2004, 6, 9, 11, 45, 0);
212 assertEquals(true, DateUtils.isSameInstant(cal1, cal2));
213 try {
214 DateUtils.isSameInstant((Calendar) null, (Calendar) null);
215 fail();
216 } catch (IllegalArgumentException ex) {}
217 }
218
219 //-----------------------------------------------------------------------
220 public void testIsSameLocalTime_Cal() {
221 GregorianCalendar cal1 = new GregorianCalendar(TimeZone.getTimeZone("GMT+1"));
222 GregorianCalendar cal2 = new GregorianCalendar(TimeZone.getTimeZone("GMT-1"));
223 cal1.set(2004, 6, 9, 13, 45, 0);
224 cal1.set(Calendar.MILLISECOND, 0);
225 cal2.set(2004, 6, 9, 13, 45, 0);
226 cal2.set(Calendar.MILLISECOND, 0);
227 assertEquals(true, DateUtils.isSameLocalTime(cal1, cal2));
228
229 Calendar cal3 = Calendar.getInstance();
230 Calendar cal4 = Calendar.getInstance();
231 cal3.set(2004, 6, 9, 4, 0, 0);
232 cal4.set(2004, 6, 9, 16, 0, 0);
233 cal3.set(Calendar.MILLISECOND, 0);
234 cal4.set(Calendar.MILLISECOND, 0);
235 assertFalse("LANG-677", DateUtils.isSameLocalTime(cal3, cal4));
236
237 cal2.set(2004, 6, 9, 11, 45, 0);
238 assertEquals(false, DateUtils.isSameLocalTime(cal1, cal2));
239 try {
240 DateUtils.isSameLocalTime((Calendar) null, (Calendar) null);
241 fail();
242 } catch (IllegalArgumentException ex) {}
243 }
244
245 //-----------------------------------------------------------------------
246 public void testParseDate() throws Exception {
247 GregorianCalendar cal = new GregorianCalendar(1972, 11, 3);
248 String dateStr = "1972-12-03";
249 String[] parsers = new String[] {"yyyy'-'DDD", "yyyy'-'MM'-'dd", "yyyyMMdd"};
250 Date date = DateUtils.parseDate(dateStr, parsers);
251 assertEquals(cal.getTime(), date);
252
253 dateStr = "1972-338";
254 date = DateUtils.parseDate(dateStr, parsers);
255 assertEquals(cal.getTime(), date);
256
257 dateStr = "19721203";
258 date = DateUtils.parseDate(dateStr, parsers);
259 assertEquals(cal.getTime(), date);
260
261 try {
262 DateUtils.parseDate("PURPLE", parsers);
263 fail();
264 } catch (ParseException ex) {}
265 try {
266 DateUtils.parseDate("197212AB", parsers);
267 fail();
268 } catch (ParseException ex) {}
269 try {
270 DateUtils.parseDate(null, parsers);
271 fail();
272 } catch (IllegalArgumentException ex) {}
273 try {
274 DateUtils.parseDate(dateStr, (String[]) null);
275 fail();
276 } catch (IllegalArgumentException ex) {}
277 try {
278 DateUtils.parseDate(dateStr, new String[0]);
279 fail();
280 } catch (ParseException ex) {}
281 }
282 // LANG-486
283 public void testParseDateWithLeniency() throws Exception {
284 GregorianCalendar cal = new GregorianCalendar(1998, 6, 30);
285 String dateStr = "02 942, 1996";
286 String[] parsers = new String[] {"MM DDD, yyyy"};
287
288 Date date = DateUtils.parseDate(dateStr, parsers);
289 assertEquals(cal.getTime(), date);
290
291 try {
292 date = DateUtils.parseDateStrictly(dateStr, parsers);
293 fail();
294 } catch (ParseException ex) {}
295 }
296
297 //-----------------------------------------------------------------------
298 public void testAddYears() throws Exception {
299 Date base = new Date(MILLIS_TEST);
300 Date result = DateUtils.addYears(base, 0);
301 assertNotSame(base, result);
302 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
303 assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
304
305 result = DateUtils.addYears(base, 1);
306 assertNotSame(base, result);
307 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
308 assertDate(result, 2001, 6, 5, 4, 3, 2, 1);
309
310 result = DateUtils.addYears(base, -1);
311 assertNotSame(base, result);
312 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
313 assertDate(result, 1999, 6, 5, 4, 3, 2, 1);
314 }
315
316 //-----------------------------------------------------------------------
317 public void testAddMonths() throws Exception {
318 Date base = new Date(MILLIS_TEST);
319 Date result = DateUtils.addMonths(base, 0);
320 assertNotSame(base, result);
321 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
322 assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
323
324 result = DateUtils.addMonths(base, 1);
325 assertNotSame(base, result);
326 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
327 assertDate(result, 2000, 7, 5, 4, 3, 2, 1);
328
329 result = DateUtils.addMonths(base, -1);
330 assertNotSame(base, result);
331 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
332 assertDate(result, 2000, 5, 5, 4, 3, 2, 1);
333 }
334
335 //-----------------------------------------------------------------------
336 public void testAddWeeks() throws Exception {
337 Date base = new Date(MILLIS_TEST);
338 Date result = DateUtils.addWeeks(base, 0);
339 assertNotSame(base, result);
340 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
341 assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
342
343 result = DateUtils.addWeeks(base, 1);
344 assertNotSame(base, result);
345 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
346 assertDate(result, 2000, 6, 12, 4, 3, 2, 1);
347
348 result = DateUtils.addWeeks(base, -1);
349 assertNotSame(base, result);
350 assertDate(base, 2000, 6, 5, 4, 3, 2, 1); // july
351 assertDate(result, 2000, 5, 28, 4, 3, 2, 1); // june
352 }
353
354 //-----------------------------------------------------------------------
355 public void testAddDays() throws Exception {
356 Date base = new Date(MILLIS_TEST);
357 Date result = DateUtils.addDays(base, 0);
358 assertNotSame(base, result);
359 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
360 assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
361
362 result = DateUtils.addDays(base, 1);
363 assertNotSame(base, result);
364 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
365 assertDate(result, 2000, 6, 6, 4, 3, 2, 1);
366
367 result = DateUtils.addDays(base, -1);
368 assertNotSame(base, result);
369 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
370 assertDate(result, 2000, 6, 4, 4, 3, 2, 1);
371 }
372
373 //-----------------------------------------------------------------------
374 public void testAddHours() throws Exception {
375 Date base = new Date(MILLIS_TEST);
376 Date result = DateUtils.addHours(base, 0);
377 assertNotSame(base, result);
378 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
379 assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
380
381 result = DateUtils.addHours(base, 1);
382 assertNotSame(base, result);
383 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
384 assertDate(result, 2000, 6, 5, 5, 3, 2, 1);
385
386 result = DateUtils.addHours(base, -1);
387 assertNotSame(base, result);
388 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
389 assertDate(result, 2000, 6, 5, 3, 3, 2, 1);
390 }
391
392 //-----------------------------------------------------------------------
393 public void testAddMinutes() throws Exception {
394 Date base = new Date(MILLIS_TEST);
395 Date result = DateUtils.addMinutes(base, 0);
396 assertNotSame(base, result);
397 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
398 assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
399
400 result = DateUtils.addMinutes(base, 1);
401 assertNotSame(base, result);
402 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
403 assertDate(result, 2000, 6, 5, 4, 4, 2, 1);
404
405 result = DateUtils.addMinutes(base, -1);
406 assertNotSame(base, result);
407 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
408 assertDate(result, 2000, 6, 5, 4, 2, 2, 1);
409 }
410
411 //-----------------------------------------------------------------------
412 public void testAddSeconds() throws Exception {
413 Date base = new Date(MILLIS_TEST);
414 Date result = DateUtils.addSeconds(base, 0);
415 assertNotSame(base, result);
416 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
417 assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
418
419 result = DateUtils.addSeconds(base, 1);
420 assertNotSame(base, result);
421 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
422 assertDate(result, 2000, 6, 5, 4, 3, 3, 1);
423
424 result = DateUtils.addSeconds(base, -1);
425 assertNotSame(base, result);
426 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
427 assertDate(result, 2000, 6, 5, 4, 3, 1, 1);
428 }
429
430 //-----------------------------------------------------------------------
431 public void testAddMilliseconds() throws Exception {
432 Date base = new Date(MILLIS_TEST);
433 Date result = DateUtils.addMilliseconds(base, 0);
434 assertNotSame(base, result);
435 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
436 assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
437
438 result = DateUtils.addMilliseconds(base, 1);
439 assertNotSame(base, result);
440 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
441 assertDate(result, 2000, 6, 5, 4, 3, 2, 2);
442
443 result = DateUtils.addMilliseconds(base, -1);
444 assertNotSame(base, result);
445 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
446 assertDate(result, 2000, 6, 5, 4, 3, 2, 0);
447 }
448
449 // -----------------------------------------------------------------------
450 public void testSetYears() throws Exception {
451 Date base = new Date(MILLIS_TEST);
452 Date result = DateUtils.setYears(base, 2000);
453 assertNotSame(base, result);
454 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
455 assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
456
457 result = DateUtils.setYears(base, 2008);
458 assertNotSame(base, result);
459 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
460 assertDate(result, 2008, 6, 5, 4, 3, 2, 1);
461
462 result = DateUtils.setYears(base, 2005);
463 assertNotSame(base, result);
464 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
465 assertDate(result, 2005, 6, 5, 4, 3, 2, 1);
466 }
467
468 // -----------------------------------------------------------------------
469 public void testSetMonths() throws Exception {
470 Date base = new Date(MILLIS_TEST);
471 Date result = DateUtils.setMonths(base, 5);
472 assertNotSame(base, result);
473 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
474 assertDate(result, 2000, 5, 5, 4, 3, 2, 1);
475
476 result = DateUtils.setMonths(base, 1);
477 assertNotSame(base, result);
478 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
479 assertDate(result, 2000, 1, 5, 4, 3, 2, 1);
480
481 try {
482 result = DateUtils.setMonths(base, 12);
483 fail("DateUtils.setMonths did not throw an expected IllegalArguementException.");
484 } catch (IllegalArgumentException e) {
485
486 }
487 }
488
489 // -----------------------------------------------------------------------
490 public void testSetDays() throws Exception {
491 Date base = new Date(MILLIS_TEST);
492 Date result = DateUtils.setDays(base, 1);
493 assertNotSame(base, result);
494 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
495 assertDate(result, 2000, 6, 1, 4, 3, 2, 1);
496
497 result = DateUtils.setDays(base, 29);
498 assertNotSame(base, result);
499 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
500 assertDate(result, 2000, 6, 29, 4, 3, 2, 1);
501
502 try {
503 result = DateUtils.setDays(base, 32);
504 fail("DateUtils.setDays did not throw an expected IllegalArguementException.");
505 } catch (IllegalArgumentException e) {
506
507 }
508 }
509
510 // -----------------------------------------------------------------------
511 public void testSetHours() throws Exception {
512 Date base = new Date(MILLIS_TEST);
513 Date result = DateUtils.setHours(base, 0);
514 assertNotSame(base, result);
515 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
516 assertDate(result, 2000, 6, 5, 0, 3, 2, 1);
517
518 result = DateUtils.setHours(base, 23);
519 assertNotSame(base, result);
520 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
521 assertDate(result, 2000, 6, 5, 23, 3, 2, 1);
522
523 try {
524 result = DateUtils.setHours(base, 24);
525 fail("DateUtils.setHours did not throw an expected IllegalArguementException.");
526 } catch (IllegalArgumentException e) {
527
528 }
529 }
530
531 // -----------------------------------------------------------------------
532 public void testSetMinutes() throws Exception {
533 Date base = new Date(MILLIS_TEST);
534 Date result = DateUtils.setMinutes(base, 0);
535 assertNotSame(base, result);
536 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
537 assertDate(result, 2000, 6, 5, 4, 0, 2, 1);
538
539 result = DateUtils.setMinutes(base, 59);
540 assertNotSame(base, result);
541 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
542 assertDate(result, 2000, 6, 5, 4, 59, 2, 1);
543
544 try {
545 result = DateUtils.setMinutes(base, 60);
546 fail("DateUtils.setMinutes did not throw an expected IllegalArguementException.");
547 } catch (IllegalArgumentException e) {
548
549 }
550 }
551
552 // -----------------------------------------------------------------------
553 public void testSetSeconds() throws Exception {
554 Date base = new Date(MILLIS_TEST);
555 Date result = DateUtils.setSeconds(base, 0);
556 assertNotSame(base, result);
557 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
558 assertDate(result, 2000, 6, 5, 4, 3, 0, 1);
559
560 result = DateUtils.setSeconds(base, 59);
561 assertNotSame(base, result);
562 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
563 assertDate(result, 2000, 6, 5, 4, 3, 59, 1);
564
565 try {
566 result = DateUtils.setSeconds(base, 60);
567 fail("DateUtils.setSeconds did not throw an expected IllegalArguementException.");
568 } catch (IllegalArgumentException e) {
569
570 }
571 }
572
573 // -----------------------------------------------------------------------
574 public void testSetMilliseconds() throws Exception {
575 Date base = new Date(MILLIS_TEST);
576 Date result = DateUtils.setMilliseconds(base, 0);
577 assertNotSame(base, result);
578 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
579 assertDate(result, 2000, 6, 5, 4, 3, 2, 0);
580
581 result = DateUtils.setMilliseconds(base, 999);
582 assertNotSame(base, result);
583 assertDate(base, 2000, 6, 5, 4, 3, 2, 1);
584 assertDate(result, 2000, 6, 5, 4, 3, 2, 999);
585
586 try {
587 result = DateUtils.setMilliseconds(base, 1000);
588 fail("DateUtils.setMilliseconds did not throw an expected IllegalArguementException.");
589 } catch (IllegalArgumentException e) {
590
591 }
592 }
593
594 //-----------------------------------------------------------------------
595 private void assertDate(Date date, int year, int month, int day, int hour, int min, int sec, int mil) throws Exception {
596 GregorianCalendar cal = new GregorianCalendar();
597 cal.setTime(date);
598 assertEquals(year, cal.get(Calendar.YEAR));
599 assertEquals(month, cal.get(Calendar.MONTH));
600 assertEquals(day, cal.get(Calendar.DAY_OF_MONTH));
601 assertEquals(hour, cal.get(Calendar.HOUR_OF_DAY));
602 assertEquals(min, cal.get(Calendar.MINUTE));
603 assertEquals(sec, cal.get(Calendar.SECOND));
604 assertEquals(mil, cal.get(Calendar.MILLISECOND));
605 }
606
607 //-----------------------------------------------------------------------
608 public void testToCalendar() {
609 assertEquals("Failed to convert to a Calendar and back", date1, DateUtils.toCalendar(date1).getTime());
610 try {
611 DateUtils.toCalendar(null);
612 fail("Expected NullPointerException to be thrown");
613 } catch(NullPointerException npe) {
614 // expected
615 }
616 }
617
618 //-----------------------------------------------------------------------
619 /**
620 * Tests various values with the round method
621 */
622 public void testRound() throws Exception {
623 // tests for public static Date round(Date date, int field)
624 assertEquals("round year-1 failed",
625 dateParser.parse("January 1, 2002"),
626 DateUtils.round(date1, Calendar.YEAR));
627 assertEquals("round year-2 failed",
628 dateParser.parse("January 1, 2002"),
629 DateUtils.round(date2, Calendar.YEAR));
630 assertEquals("round month-1 failed",
631 dateParser.parse("February 1, 2002"),
632 DateUtils.round(date1, Calendar.MONTH));
633 assertEquals("round month-2 failed",
634 dateParser.parse("December 1, 2001"),
635 DateUtils.round(date2, Calendar.MONTH));
636 assertEquals("round semimonth-0 failed",
637 dateParser.parse("February 1, 2002"),
638 DateUtils.round(date0, DateUtils.SEMI_MONTH));
639 assertEquals("round semimonth-1 failed",
640 dateParser.parse("February 16, 2002"),
641 DateUtils.round(date1, DateUtils.SEMI_MONTH));
642 assertEquals("round semimonth-2 failed",
643 dateParser.parse("November 16, 2001"),
644 DateUtils.round(date2, DateUtils.SEMI_MONTH));
645
646
647 assertEquals("round date-1 failed",
648 dateParser.parse("February 13, 2002"),
649 DateUtils.round(date1, Calendar.DATE));
650 assertEquals("round date-2 failed",
651 dateParser.parse("November 18, 2001"),
652 DateUtils.round(date2, Calendar.DATE));
653 assertEquals("round hour-1 failed",
654 dateTimeParser.parse("February 12, 2002 13:00:00.000"),
655 DateUtils.round(date1, Calendar.HOUR));
656 assertEquals("round hour-2 failed",
657 dateTimeParser.parse("November 18, 2001 1:00:00.000"),
658 DateUtils.round(date2, Calendar.HOUR));
659 assertEquals("round minute-1 failed",
660 dateTimeParser.parse("February 12, 2002 12:35:00.000"),
661 DateUtils.round(date1, Calendar.MINUTE));
662 assertEquals("round minute-2 failed",
663 dateTimeParser.parse("November 18, 2001 1:23:00.000"),
664 DateUtils.round(date2, Calendar.MINUTE));
665 assertEquals("round second-1 failed",
666 dateTimeParser.parse("February 12, 2002 12:34:57.000"),
667 DateUtils.round(date1, Calendar.SECOND));
668 assertEquals("round second-2 failed",
669 dateTimeParser.parse("November 18, 2001 1:23:11.000"),
670 DateUtils.round(date2, Calendar.SECOND));
671 assertEquals("round ampm-1 failed",
672 dateTimeParser.parse("February 3, 2002 00:00:00.000"),
673 DateUtils.round(dateAmPm1, Calendar.AM_PM));
674 assertEquals("round ampm-2 failed",
675 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
676 DateUtils.round(dateAmPm2, Calendar.AM_PM));
677 assertEquals("round ampm-3 failed",
678 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
679 DateUtils.round(dateAmPm3, Calendar.AM_PM));
680 assertEquals("round ampm-4 failed",
681 dateTimeParser.parse("February 4, 2002 00:00:00.000"),
682 DateUtils.round(dateAmPm4, Calendar.AM_PM));
683
684 // tests for public static Date round(Object date, int field)
685 assertEquals("round year-1 failed",
686 dateParser.parse("January 1, 2002"),
687 DateUtils.round((Object) date1, Calendar.YEAR));
688 assertEquals("round year-2 failed",
689 dateParser.parse("January 1, 2002"),
690 DateUtils.round((Object) date2, Calendar.YEAR));
691 assertEquals("round month-1 failed",
692 dateParser.parse("February 1, 2002"),
693 DateUtils.round((Object) date1, Calendar.MONTH));
694 assertEquals("round month-2 failed",
695 dateParser.parse("December 1, 2001"),
696 DateUtils.round((Object) date2, Calendar.MONTH));
697 assertEquals("round semimonth-1 failed",
698 dateParser.parse("February 16, 2002"),
699 DateUtils.round((Object) date1, DateUtils.SEMI_MONTH));
700 assertEquals("round semimonth-2 failed",
701 dateParser.parse("November 16, 2001"),
702 DateUtils.round((Object) date2, DateUtils.SEMI_MONTH));
703 assertEquals("round date-1 failed",
704 dateParser.parse("February 13, 2002"),
705 DateUtils.round((Object) date1, Calendar.DATE));
706 assertEquals("round date-2 failed",
707 dateParser.parse("November 18, 2001"),
708 DateUtils.round((Object) date2, Calendar.DATE));
709 assertEquals("round hour-1 failed",
710 dateTimeParser.parse("February 12, 2002 13:00:00.000"),
711 DateUtils.round((Object) date1, Calendar.HOUR));
712 assertEquals("round hour-2 failed",
713 dateTimeParser.parse("November 18, 2001 1:00:00.000"),
714 DateUtils.round((Object) date2, Calendar.HOUR));
715 assertEquals("round minute-1 failed",
716 dateTimeParser.parse("February 12, 2002 12:35:00.000"),
717 DateUtils.round((Object) date1, Calendar.MINUTE));
718 assertEquals("round minute-2 failed",
719 dateTimeParser.parse("November 18, 2001 1:23:00.000"),
720 DateUtils.round((Object) date2, Calendar.MINUTE));
721 assertEquals("round second-1 failed",
722 dateTimeParser.parse("February 12, 2002 12:34:57.000"),
723 DateUtils.round((Object) date1, Calendar.SECOND));
724 assertEquals("round second-2 failed",
725 dateTimeParser.parse("November 18, 2001 1:23:11.000"),
726 DateUtils.round((Object) date2, Calendar.SECOND));
727 assertEquals("round calendar second-1 failed",
728 dateTimeParser.parse("February 12, 2002 12:34:57.000"),
729 DateUtils.round((Object) cal1, Calendar.SECOND));
730 assertEquals("round calendar second-2 failed",
731 dateTimeParser.parse("November 18, 2001 1:23:11.000"),
732 DateUtils.round((Object) cal2, Calendar.SECOND));
733 assertEquals("round ampm-1 failed",
734 dateTimeParser.parse("February 3, 2002 00:00:00.000"),
735 DateUtils.round((Object) dateAmPm1, Calendar.AM_PM));
736 assertEquals("round ampm-2 failed",
737 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
738 DateUtils.round((Object) dateAmPm2, Calendar.AM_PM));
739 assertEquals("round ampm-3 failed",
740 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
741 DateUtils.round((Object) dateAmPm3, Calendar.AM_PM));
742 assertEquals("round ampm-4 failed",
743 dateTimeParser.parse("February 4, 2002 00:00:00.000"),
744 DateUtils.round((Object) dateAmPm4, Calendar.AM_PM));
745
746 try {
747 DateUtils.round((Date) null, Calendar.SECOND);
748 fail();
749 } catch (IllegalArgumentException ex) {}
750 try {
751 DateUtils.round((Calendar) null, Calendar.SECOND);
752 fail();
753 } catch (IllegalArgumentException ex) {}
754 try {
755 DateUtils.round((Object) null, Calendar.SECOND);
756 fail();
757 } catch (IllegalArgumentException ex) {}
758 try {
759 DateUtils.round("", Calendar.SECOND);
760 fail();
761 } catch (ClassCastException ex) {}
762 try {
763 DateUtils.round(date1, -9999);
764 fail();
765 } catch(IllegalArgumentException ex) {}
766
767 assertEquals("round ampm-1 failed",
768 dateTimeParser.parse("February 3, 2002 00:00:00.000"),
769 DateUtils.round((Object) calAmPm1, Calendar.AM_PM));
770 assertEquals("round ampm-2 failed",
771 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
772 DateUtils.round((Object) calAmPm2, Calendar.AM_PM));
773 assertEquals("round ampm-3 failed",
774 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
775 DateUtils.round((Object) calAmPm3, Calendar.AM_PM));
776 assertEquals("round ampm-4 failed",
777 dateTimeParser.parse("February 4, 2002 00:00:00.000"),
778 DateUtils.round((Object) calAmPm4, Calendar.AM_PM));
779
780 // Fix for http://issues.apache.org/bugzilla/show_bug.cgi?id=25560 / LANG-13
781 // Test rounding across the beginning of daylight saving time
782 TimeZone.setDefault(zone);
783 dateTimeParser.setTimeZone(zone);
784 assertEquals("round MET date across DST change-over",
785 dateTimeParser.parse("March 30, 2003 00:00:00.000"),
786 DateUtils.round(date4, Calendar.DATE));
787 assertEquals("round MET date across DST change-over",
788 dateTimeParser.parse("March 30, 2003 00:00:00.000"),
789 DateUtils.round((Object) cal4, Calendar.DATE));
790 assertEquals("round MET date across DST change-over",
791 dateTimeParser.parse("March 30, 2003 00:00:00.000"),
792 DateUtils.round(date5, Calendar.DATE));
793 assertEquals("round MET date across DST change-over",
794 dateTimeParser.parse("March 30, 2003 00:00:00.000"),
795 DateUtils.round((Object) cal5, Calendar.DATE));
796 assertEquals("round MET date across DST change-over",
797 dateTimeParser.parse("March 30, 2003 00:00:00.000"),
798 DateUtils.round(date6, Calendar.DATE));
799 assertEquals("round MET date across DST change-over",
800 dateTimeParser.parse("March 30, 2003 00:00:00.000"),
801 DateUtils.round((Object) cal6, Calendar.DATE));
802 assertEquals("round MET date across DST change-over",
803 dateTimeParser.parse("March 30, 2003 00:00:00.000"),
804 DateUtils.round(date7, Calendar.DATE));
805 assertEquals("round MET date across DST change-over",
806 dateTimeParser.parse("March 30, 2003 00:00:00.000"),
807 DateUtils.round((Object) cal7, Calendar.DATE));
808
809 assertEquals("round MET date across DST change-over",
810 dateTimeParser.parse("March 30, 2003 01:00:00.000"),
811 DateUtils.round(date4, Calendar.HOUR_OF_DAY));
812 assertEquals("round MET date across DST change-over",
813 dateTimeParser.parse("March 30, 2003 01:00:00.000"),
814 DateUtils.round((Object) cal4, Calendar.HOUR_OF_DAY));
815 if (SystemUtils.isJavaVersionAtLeast(JAVA_1_4)) {
816 assertEquals("round MET date across DST change-over",
817 dateTimeParser.parse("March 30, 2003 03:00:00.000"),
818 DateUtils.round(date5, Calendar.HOUR_OF_DAY));
819 assertEquals("round MET date across DST change-over",
820 dateTimeParser.parse("March 30, 2003 03:00:00.000"),
821 DateUtils.round((Object) cal5, Calendar.HOUR_OF_DAY));
822 assertEquals("round MET date across DST change-over",
823 dateTimeParser.parse("March 30, 2003 03:00:00.000"),
824 DateUtils.round(date6, Calendar.HOUR_OF_DAY));
825 assertEquals("round MET date across DST change-over",
826 dateTimeParser.parse("March 30, 2003 03:00:00.000"),
827 DateUtils.round((Object) cal6, Calendar.HOUR_OF_DAY));
828 assertEquals("round MET date across DST change-over",
829 dateTimeParser.parse("March 30, 2003 04:00:00.000"),
830 DateUtils.round(date7, Calendar.HOUR_OF_DAY));
831 assertEquals("round MET date across DST change-over",
832 dateTimeParser.parse("March 30, 2003 04:00:00.000"),
833 DateUtils.round((Object) cal7, Calendar.HOUR_OF_DAY));
834 } else {
835 this.warn("WARNING: Some date rounding tests not run since the current version is " + SystemUtils.JAVA_SPECIFICATION_VERSION);
836 }
837 TimeZone.setDefault(defaultZone);
838 dateTimeParser.setTimeZone(defaultZone);
839 }
840
841 /**
842 * Tests the Changes Made by LANG-346 to the DateUtils.modify() private method invoked
843 * by DateUtils.round().
844 */
845 public void testRoundLang346() throws Exception
846 {
847 TimeZone.setDefault(defaultZone);
848 dateTimeParser.setTimeZone(defaultZone);
849 Calendar testCalendar = Calendar.getInstance();
850 testCalendar.set(2007, 6, 2, 8, 8, 50);
851 Date date = testCalendar.getTime();
852 assertEquals("Minute Round Up Failed",
853 dateTimeParser.parse("July 2, 2007 08:09:00.000"),
854 DateUtils.round(date, Calendar.MINUTE));
855
856 testCalendar.set(2007, 6, 2, 8, 8, 20);
857 date = testCalendar.getTime();
858 assertEquals("Minute No Round Failed",
859 dateTimeParser.parse("July 2, 2007 08:08:00.000"),
860 DateUtils.round(date, Calendar.MINUTE));
861
862 testCalendar.set(2007, 6, 2, 8, 8, 50);
863 testCalendar.set(Calendar.MILLISECOND, 600);
864 date = testCalendar.getTime();
865
866 assertEquals("Second Round Up with 600 Milli Seconds Failed",
867 dateTimeParser.parse("July 2, 2007 08:08:51.000"),
868 DateUtils.round(date, Calendar.SECOND));
869
870 testCalendar.set(2007, 6, 2, 8, 8, 50);
871 testCalendar.set(Calendar.MILLISECOND, 200);
872 date = testCalendar.getTime();
873 assertEquals("Second Round Down with 200 Milli Seconds Failed",
874 dateTimeParser.parse("July 2, 2007 08:08:50.000"),
875 DateUtils.round(date, Calendar.SECOND));
876
877 testCalendar.set(2007, 6, 2, 8, 8, 20);
878 testCalendar.set(Calendar.MILLISECOND, 600);
879 date = testCalendar.getTime();
880 assertEquals("Second Round Up with 200 Milli Seconds Failed",
881 dateTimeParser.parse("July 2, 2007 08:08:21.000"),
882 DateUtils.round(date, Calendar.SECOND));
883
884 testCalendar.set(2007, 6, 2, 8, 8, 20);
885 testCalendar.set(Calendar.MILLISECOND, 200);
886 date = testCalendar.getTime();
887 assertEquals("Second Round Down with 200 Milli Seconds Failed",
888 dateTimeParser.parse("July 2, 2007 08:08:20.000"),
889 DateUtils.round(date, Calendar.SECOND));
890
891 testCalendar.set(2007, 6, 2, 8, 8, 50);
892 date = testCalendar.getTime();
893 assertEquals("Hour Round Down Failed",
894 dateTimeParser.parse("July 2, 2007 08:00:00.000"),
895 DateUtils.round(date, Calendar.HOUR));
896
897 testCalendar.set(2007, 6, 2, 8, 31, 50);
898 date = testCalendar.getTime();
899 assertEquals("Hour Round Up Failed",
900 dateTimeParser.parse("July 2, 2007 09:00:00.000"),
901 DateUtils.round(date, Calendar.HOUR));
902 }
903
904 /**
905 * Tests various values with the trunc method
906 */
907 public void testTruncate() throws Exception {
908 // tests public static Date truncate(Date date, int field)
909 assertEquals("truncate year-1 failed",
910 dateParser.parse("January 1, 2002"),
911 DateUtils.truncate(date1, Calendar.YEAR));
912 assertEquals("truncate year-2 failed",
913 dateParser.parse("January 1, 2001"),
914 DateUtils.truncate(date2, Calendar.YEAR));
915 assertEquals("truncate month-1 failed",
916 dateParser.parse("February 1, 2002"),
917 DateUtils.truncate(date1, Calendar.MONTH));
918 assertEquals("truncate month-2 failed",
919 dateParser.parse("November 1, 2001"),
920 DateUtils.truncate(date2, Calendar.MONTH));
921 assertEquals("truncate semimonth-1 failed",
922 dateParser.parse("February 1, 2002"),
923 DateUtils.truncate(date1, DateUtils.SEMI_MONTH));
924 assertEquals("truncate semimonth-2 failed",
925 dateParser.parse("November 16, 2001"),
926 DateUtils.truncate(date2, DateUtils.SEMI_MONTH));
927 assertEquals("truncate date-1 failed",
928 dateParser.parse("February 12, 2002"),
929 DateUtils.truncate(date1, Calendar.DATE));
930 assertEquals("truncate date-2 failed",
931 dateParser.parse("November 18, 2001"),
932 DateUtils.truncate(date2, Calendar.DATE));
933 assertEquals("truncate hour-1 failed",
934 dateTimeParser.parse("February 12, 2002 12:00:00.000"),
935 DateUtils.truncate(date1, Calendar.HOUR));
936 assertEquals("truncate hour-2 failed",
937 dateTimeParser.parse("November 18, 2001 1:00:00.000"),
938 DateUtils.truncate(date2, Calendar.HOUR));
939 assertEquals("truncate minute-1 failed",
940 dateTimeParser.parse("February 12, 2002 12:34:00.000"),
941 DateUtils.truncate(date1, Calendar.MINUTE));
942 assertEquals("truncate minute-2 failed",
943 dateTimeParser.parse("November 18, 2001 1:23:00.000"),
944 DateUtils.truncate(date2, Calendar.MINUTE));
945 assertEquals("truncate second-1 failed",
946 dateTimeParser.parse("February 12, 2002 12:34:56.000"),
947 DateUtils.truncate(date1, Calendar.SECOND));
948 assertEquals("truncate second-2 failed",
949 dateTimeParser.parse("November 18, 2001 1:23:11.000"),
950 DateUtils.truncate(date2, Calendar.SECOND));
951 assertEquals("truncate ampm-1 failed",
952 dateTimeParser.parse("February 3, 2002 00:00:00.000"),
953 DateUtils.truncate(dateAmPm1, Calendar.AM_PM));
954 assertEquals("truncate ampm-2 failed",
955 dateTimeParser.parse("February 3, 2002 00:00:00.000"),
956 DateUtils.truncate(dateAmPm2, Calendar.AM_PM));
957 assertEquals("truncate ampm-3 failed",
958 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
959 DateUtils.truncate(dateAmPm3, Calendar.AM_PM));
960 assertEquals("truncate ampm-4 failed",
961 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
962 DateUtils.truncate(dateAmPm4, Calendar.AM_PM));
963
964 // tests public static Date truncate(Object date, int field)
965 assertEquals("truncate year-1 failed",
966 dateParser.parse("January 1, 2002"),
967 DateUtils.truncate((Object) date1, Calendar.YEAR));
968 assertEquals("truncate year-2 failed",
969 dateParser.parse("January 1, 2001"),
970 DateUtils.truncate((Object) date2, Calendar.YEAR));
971 assertEquals("truncate month-1 failed",
972 dateParser.parse("February 1, 2002"),
973 DateUtils.truncate((Object) date1, Calendar.MONTH));
974 assertEquals("truncate month-2 failed",
975 dateParser.parse("November 1, 2001"),
976 DateUtils.truncate((Object) date2, Calendar.MONTH));
977 assertEquals("truncate semimonth-1 failed",
978 dateParser.parse("February 1, 2002"),
979 DateUtils.truncate((Object) date1, DateUtils.SEMI_MONTH));
980 assertEquals("truncate semimonth-2 failed",
981 dateParser.parse("November 16, 2001"),
982 DateUtils.truncate((Object) date2, DateUtils.SEMI_MONTH));
983 assertEquals("truncate date-1 failed",
984 dateParser.parse("February 12, 2002"),
985 DateUtils.truncate((Object) date1, Calendar.DATE));
986 assertEquals("truncate date-2 failed",
987 dateParser.parse("November 18, 2001"),
988 DateUtils.truncate((Object) date2, Calendar.DATE));
989 assertEquals("truncate hour-1 failed",
990 dateTimeParser.parse("February 12, 2002 12:00:00.000"),
991 DateUtils.truncate((Object) date1, Calendar.HOUR));
992 assertEquals("truncate hour-2 failed",
993 dateTimeParser.parse("November 18, 2001 1:00:00.000"),
994 DateUtils.truncate((Object) date2, Calendar.HOUR));
995 assertEquals("truncate minute-1 failed",
996 dateTimeParser.parse("February 12, 2002 12:34:00.000"),
997 DateUtils.truncate((Object) date1, Calendar.MINUTE));
998 assertEquals("truncate minute-2 failed",
999 dateTimeParser.parse("November 18, 2001 1:23:00.000"),
1000 DateUtils.truncate((Object) date2, Calendar.MINUTE));
1001 assertEquals("truncate second-1 failed",
1002 dateTimeParser.parse("February 12, 2002 12:34:56.000"),
1003 DateUtils.truncate((Object) date1, Calendar.SECOND));
1004 assertEquals("truncate second-2 failed",
1005 dateTimeParser.parse("November 18, 2001 1:23:11.000"),
1006 DateUtils.truncate((Object) date2, Calendar.SECOND));
1007 assertEquals("truncate ampm-1 failed",
1008 dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1009 DateUtils.truncate((Object) dateAmPm1, Calendar.AM_PM));
1010 assertEquals("truncate ampm-2 failed",
1011 dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1012 DateUtils.truncate((Object) dateAmPm2, Calendar.AM_PM));
1013 assertEquals("truncate ampm-3 failed",
1014 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1015 DateUtils.truncate((Object) dateAmPm3, Calendar.AM_PM));
1016 assertEquals("truncate ampm-4 failed",
1017 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1018 DateUtils.truncate((Object) dateAmPm4, Calendar.AM_PM));
1019
1020 assertEquals("truncate calendar second-1 failed",
1021 dateTimeParser.parse("February 12, 2002 12:34:56.000"),
1022 DateUtils.truncate((Object) cal1, Calendar.SECOND));
1023 assertEquals("truncate calendar second-2 failed",
1024 dateTimeParser.parse("November 18, 2001 1:23:11.000"),
1025 DateUtils.truncate((Object) cal2, Calendar.SECOND));
1026
1027 assertEquals("truncate ampm-1 failed",
1028 dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1029 DateUtils.truncate((Object) calAmPm1, Calendar.AM_PM));
1030 assertEquals("truncate ampm-2 failed",
1031 dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1032 DateUtils.truncate((Object) calAmPm2, Calendar.AM_PM));
1033 assertEquals("truncate ampm-3 failed",
1034 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1035 DateUtils.truncate((Object) calAmPm3, Calendar.AM_PM));
1036 assertEquals("truncate ampm-4 failed",
1037 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1038 DateUtils.truncate((Object) calAmPm4, Calendar.AM_PM));
1039
1040 try {
1041 DateUtils.truncate((Date) null, Calendar.SECOND);
1042 fail();
1043 } catch (IllegalArgumentException ex) {}
1044 try {
1045 DateUtils.truncate((Calendar) null, Calendar.SECOND);
1046 fail();
1047 } catch (IllegalArgumentException ex) {}
1048 try {
1049 DateUtils.truncate((Object) null, Calendar.SECOND);
1050 fail();
1051 } catch (IllegalArgumentException ex) {}
1052 try {
1053 DateUtils.truncate("", Calendar.SECOND);
1054 fail();
1055 } catch (ClassCastException ex) {}
1056
1057 // Fix for http://issues.apache.org/bugzilla/show_bug.cgi?id=25560
1058 // Test truncate across beginning of daylight saving time
1059 TimeZone.setDefault(zone);
1060 dateTimeParser.setTimeZone(zone);
1061 assertEquals("truncate MET date across DST change-over",
1062 dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1063 DateUtils.truncate(date3, Calendar.DATE));
1064 assertEquals("truncate MET date across DST change-over",
1065 dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1066 DateUtils.truncate((Object) cal3, Calendar.DATE));
1067 // Test truncate across end of daylight saving time
1068 assertEquals("truncate MET date across DST change-over",
1069 dateTimeParser.parse("October 26, 2003 00:00:00.000"),
1070 DateUtils.truncate(date8, Calendar.DATE));
1071 assertEquals("truncate MET date across DST change-over",
1072 dateTimeParser.parse("October 26, 2003 00:00:00.000"),
1073 DateUtils.truncate((Object) cal8, Calendar.DATE));
1074 TimeZone.setDefault(defaultZone);
1075 dateTimeParser.setTimeZone(defaultZone);
1076
1077 // Bug 31395, large dates
1078 Date endOfTime = new Date(Long.MAX_VALUE); // fyi: Sun Aug 17 07:12:55 CET 292278994 -- 807 millis
1079 GregorianCalendar endCal = new GregorianCalendar();
1080 endCal.setTime(endOfTime);
1081 try {
1082 DateUtils.truncate(endCal, Calendar.DATE);
1083 fail();
1084 } catch (ArithmeticException ex) {}
1085 endCal.set(Calendar.YEAR, 280000001);
1086 try {
1087 DateUtils.truncate(endCal, Calendar.DATE);
1088 fail();
1089 } catch (ArithmeticException ex) {}
1090 endCal.set(Calendar.YEAR, 280000000);
1091 Calendar cal = DateUtils.truncate(endCal, Calendar.DATE);
1092 assertEquals(0, cal.get(Calendar.HOUR));
1093 }
1094
1095 /**
1096 * Tests for LANG-59
1097 *
1098 * see http://issues.apache.org/jira/browse/LANG-59
1099 */
1100 public void testTruncateLang59() throws Exception {
1101 if (!SystemUtils.isJavaVersionAtLeast(JAVA_1_4)) {
1102 this.warn("WARNING: Test for LANG-59 not run since the current version is " + SystemUtils.JAVA_SPECIFICATION_VERSION);
1103 return;
1104 }
1105
1106 // Set TimeZone to Mountain Time
1107 TimeZone MST_MDT = TimeZone.getTimeZone("MST7MDT");
1108 TimeZone.setDefault(MST_MDT);
1109 DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
1110 format.setTimeZone(MST_MDT);
1111
1112 Date oct31_01MDT = new Date(1099206000000L);
1113
1114 Date oct31MDT = new Date(oct31_01MDT.getTime() - 3600000L); // - 1 hour
1115 Date oct31_01_02MDT = new Date(oct31_01MDT.getTime() + 120000L); // + 2 minutes
1116 Date oct31_01_02_03MDT = new Date(oct31_01_02MDT.getTime() + 3000L); // + 3 seconds
1117 Date oct31_01_02_03_04MDT = new Date(oct31_01_02_03MDT.getTime() + 4L); // + 4 milliseconds
1118
1119 assertEquals("Check 00:00:00.000", "2004-10-31 00:00:00.000 MDT", format.format(oct31MDT));
1120 assertEquals("Check 01:00:00.000", "2004-10-31 01:00:00.000 MDT", format.format(oct31_01MDT));
1121 assertEquals("Check 01:02:00.000", "2004-10-31 01:02:00.000 MDT", format.format(oct31_01_02MDT));
1122 assertEquals("Check 01:02:03.000", "2004-10-31 01:02:03.000 MDT", format.format(oct31_01_02_03MDT));
1123 assertEquals("Check 01:02:03.004", "2004-10-31 01:02:03.004 MDT", format.format(oct31_01_02_03_04MDT));
1124
1125 // ------- Demonstrate Problem -------
1126 Calendar gval = Calendar.getInstance();
1127 gval.setTime(new Date(oct31_01MDT.getTime()));
1128 gval.set(Calendar.MINUTE, gval.get(Calendar.MINUTE)); // set minutes to the same value
1129 assertEquals("Demonstrate Problem", gval.getTime().getTime(), oct31_01MDT.getTime() + 3600000L);
1130
1131 // ---------- Test Truncate ----------
1132 assertEquals("Truncate Calendar.MILLISECOND",
1133 oct31_01_02_03_04MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.MILLISECOND));
1134
1135 assertEquals("Truncate Calendar.SECOND",
1136 oct31_01_02_03MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.SECOND));
1137
1138 assertEquals("Truncate Calendar.MINUTE",
1139 oct31_01_02MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.MINUTE));
1140
1141 assertEquals("Truncate Calendar.HOUR_OF_DAY",
1142 oct31_01MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.HOUR_OF_DAY));
1143
1144 assertEquals("Truncate Calendar.HOUR",
1145 oct31_01MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.HOUR));
1146
1147 assertEquals("Truncate Calendar.DATE",
1148 oct31MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.DATE));
1149
1150
1151 // ---------- Test Round (down) ----------
1152 assertEquals("Round Calendar.MILLISECOND",
1153 oct31_01_02_03_04MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.MILLISECOND));
1154
1155 assertEquals("Round Calendar.SECOND",
1156 oct31_01_02_03MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.SECOND));
1157
1158 assertEquals("Round Calendar.MINUTE",
1159 oct31_01_02MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.MINUTE));
1160
1161 assertEquals("Round Calendar.HOUR_OF_DAY",
1162 oct31_01MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.HOUR_OF_DAY));
1163
1164 assertEquals("Round Calendar.HOUR",
1165 oct31_01MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.HOUR));
1166
1167 assertEquals("Round Calendar.DATE",
1168 oct31MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.DATE));
1169
1170 // restore default time zone
1171 TimeZone.setDefault(defaultZone);
1172 }
1173
1174 // http://issues.apache.org/jira/browse/LANG-530
1175 public void testLang530() throws ParseException {
1176 Date d = new Date();
1177 String isoDateStr = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(d);
1178 Date d2 = DateUtils.parseDate(isoDateStr, new String[] { DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern() });
1179 // the format loses milliseconds so have to reintroduce them
1180 assertEquals("Date not equal to itself ISO formatted and parsed", d.getTime(), d2.getTime() + d.getTime() % 1000);
1181 }
1182
1183 /**
1184 * Tests various values with the ceiling method
1185 */
1186 public void testCeil() throws Exception {
1187 // test javadoc
1188 assertEquals("ceiling javadoc-1 failed",
1189 dateTimeParser.parse("March 28, 2002 14:00:00.000"),
1190 DateUtils.ceiling(
1191 dateTimeParser.parse("March 28, 2002 13:45:01.231"),
1192 Calendar.HOUR));
1193 assertEquals("ceiling javadoc-2 failed",
1194 dateTimeParser.parse("April 1, 2002 00:00:00.000"),
1195 DateUtils.ceiling(
1196 dateTimeParser.parse("March 28, 2002 13:45:01.231"),
1197 Calendar.MONTH));
1198
1199 // tests public static Date ceiling(Date date, int field)
1200 assertEquals("ceiling year-1 failed",
1201 dateParser.parse("January 1, 2003"),
1202 DateUtils.ceiling(date1, Calendar.YEAR));
1203 assertEquals("ceiling year-2 failed",
1204 dateParser.parse("January 1, 2002"),
1205 DateUtils.ceiling(date2, Calendar.YEAR));
1206 assertEquals("ceiling month-1 failed",
1207 dateParser.parse("March 1, 2002"),
1208 DateUtils.ceiling(date1, Calendar.MONTH));
1209 assertEquals("ceiling month-2 failed",
1210 dateParser.parse("December 1, 2001"),
1211 DateUtils.ceiling(date2, Calendar.MONTH));
1212 assertEquals("ceiling semimonth-1 failed",
1213 dateParser.parse("February 16, 2002"),
1214 DateUtils.ceiling(date1, DateUtils.SEMI_MONTH));
1215 assertEquals("ceiling semimonth-2 failed",
1216 dateParser.parse("December 1, 2001"),
1217 DateUtils.ceiling(date2, DateUtils.SEMI_MONTH));
1218 assertEquals("ceiling date-1 failed",
1219 dateParser.parse("February 13, 2002"),
1220 DateUtils.ceiling(date1, Calendar.DATE));
1221 assertEquals("ceiling date-2 failed",
1222 dateParser.parse("November 19, 2001"),
1223 DateUtils.ceiling(date2, Calendar.DATE));
1224 assertEquals("ceiling hour-1 failed",
1225 dateTimeParser.parse("February 12, 2002 13:00:00.000"),
1226 DateUtils.ceiling(date1, Calendar.HOUR));
1227 assertEquals("ceiling hour-2 failed",
1228 dateTimeParser.parse("November 18, 2001 2:00:00.000"),
1229 DateUtils.ceiling(date2, Calendar.HOUR));
1230 assertEquals("ceiling minute-1 failed",
1231 dateTimeParser.parse("February 12, 2002 12:35:00.000"),
1232 DateUtils.ceiling(date1, Calendar.MINUTE));
1233 assertEquals("ceiling minute-2 failed",
1234 dateTimeParser.parse("November 18, 2001 1:24:00.000"),
1235 DateUtils.ceiling(date2, Calendar.MINUTE));
1236 assertEquals("ceiling second-1 failed",
1237 dateTimeParser.parse("February 12, 2002 12:34:57.000"),
1238 DateUtils.ceiling(date1, Calendar.SECOND));
1239 assertEquals("ceiling second-2 failed",
1240 dateTimeParser.parse("November 18, 2001 1:23:12.000"),
1241 DateUtils.ceiling(date2, Calendar.SECOND));
1242 assertEquals("ceiling ampm-1 failed",
1243 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1244 DateUtils.ceiling(dateAmPm1, Calendar.AM_PM));
1245 assertEquals("ceiling ampm-2 failed",
1246 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1247 DateUtils.ceiling(dateAmPm2, Calendar.AM_PM));
1248 assertEquals("ceiling ampm-3 failed",
1249 dateTimeParser.parse("February 4, 2002 00:00:00.000"),
1250 DateUtils.ceiling(dateAmPm3, Calendar.AM_PM));
1251 assertEquals("ceiling ampm-4 failed",
1252 dateTimeParser.parse("February 4, 2002 00:00:00.000"),
1253 DateUtils.ceiling(dateAmPm4, Calendar.AM_PM));
1254
1255 // tests public static Date ceiling(Object date, int field)
1256 assertEquals("ceiling year-1 failed",
1257 dateParser.parse("January 1, 2003"),
1258 DateUtils.ceiling((Object) date1, Calendar.YEAR));
1259 assertEquals("ceiling year-2 failed",
1260 dateParser.parse("January 1, 2002"),
1261 DateUtils.ceiling((Object) date2, Calendar.YEAR));
1262 assertEquals("ceiling month-1 failed",
1263 dateParser.parse("March 1, 2002"),
1264 DateUtils.ceiling((Object) date1, Calendar.MONTH));
1265 assertEquals("ceiling month-2 failed",
1266 dateParser.parse("December 1, 2001"),
1267 DateUtils.ceiling((Object) date2, Calendar.MONTH));
1268 assertEquals("ceiling semimonth-1 failed",
1269 dateParser.parse("February 16, 2002"),
1270 DateUtils.ceiling((Object) date1, DateUtils.SEMI_MONTH));
1271 assertEquals("ceiling semimonth-2 failed",
1272 dateParser.parse("December 1, 2001"),
1273 DateUtils.ceiling((Object) date2, DateUtils.SEMI_MONTH));
1274 assertEquals("ceiling date-1 failed",
1275 dateParser.parse("February 13, 2002"),
1276 DateUtils.ceiling((Object) date1, Calendar.DATE));
1277 assertEquals("ceiling date-2 failed",
1278 dateParser.parse("November 19, 2001"),
1279 DateUtils.ceiling((Object) date2, Calendar.DATE));
1280 assertEquals("ceiling hour-1 failed",
1281 dateTimeParser.parse("February 12, 2002 13:00:00.000"),
1282 DateUtils.ceiling((Object) date1, Calendar.HOUR));
1283 assertEquals("ceiling hour-2 failed",
1284 dateTimeParser.parse("November 18, 2001 2:00:00.000"),
1285 DateUtils.ceiling((Object) date2, Calendar.HOUR));
1286 assertEquals("ceiling minute-1 failed",
1287 dateTimeParser.parse("February 12, 2002 12:35:00.000"),
1288 DateUtils.ceiling((Object) date1, Calendar.MINUTE));
1289 assertEquals("ceiling minute-2 failed",
1290 dateTimeParser.parse("November 18, 2001 1:24:00.000"),
1291 DateUtils.ceiling((Object) date2, Calendar.MINUTE));
1292 assertEquals("ceiling second-1 failed",
1293 dateTimeParser.parse("February 12, 2002 12:34:57.000"),
1294 DateUtils.ceiling((Object) date1, Calendar.SECOND));
1295 assertEquals("ceiling second-2 failed",
1296 dateTimeParser.parse("November 18, 2001 1:23:12.000"),
1297 DateUtils.ceiling((Object) date2, Calendar.SECOND));
1298 assertEquals("ceiling ampm-1 failed",
1299 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1300 DateUtils.ceiling((Object) dateAmPm1, Calendar.AM_PM));
1301 assertEquals("ceiling ampm-2 failed",
1302 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1303 DateUtils.ceiling((Object) dateAmPm2, Calendar.AM_PM));
1304 assertEquals("ceiling ampm-3 failed",
1305 dateTimeParser.parse("February 4, 2002 00:00:00.000"),
1306 DateUtils.ceiling((Object) dateAmPm3, Calendar.AM_PM));
1307 assertEquals("ceiling ampm-4 failed",
1308 dateTimeParser.parse("February 4, 2002 00:00:00.000"),
1309 DateUtils.ceiling((Object) dateAmPm4, Calendar.AM_PM));
1310
1311 assertEquals("ceiling calendar second-1 failed",
1312 dateTimeParser.parse("February 12, 2002 12:34:57.000"),
1313 DateUtils.ceiling((Object) cal1, Calendar.SECOND));
1314 assertEquals("ceiling calendar second-2 failed",
1315 dateTimeParser.parse("November 18, 2001 1:23:12.000"),
1316 DateUtils.ceiling((Object) cal2, Calendar.SECOND));
1317
1318 assertEquals("ceiling ampm-1 failed",
1319 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1320 DateUtils.ceiling((Object) calAmPm1, Calendar.AM_PM));
1321 assertEquals("ceiling ampm-2 failed",
1322 dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1323 DateUtils.ceiling((Object) calAmPm2, Calendar.AM_PM));
1324 assertEquals("ceiling ampm-3 failed",
1325 dateTimeParser.parse("February 4, 2002 00:00:00.000"),
1326 DateUtils.ceiling((Object) calAmPm3, Calendar.AM_PM));
1327 assertEquals("ceiling ampm-4 failed",
1328 dateTimeParser.parse("February 4, 2002 00:00:00.000"),
1329 DateUtils.ceiling((Object) calAmPm4, Calendar.AM_PM));
1330
1331 try {
1332 DateUtils.ceiling((Date) null, Calendar.SECOND);
1333 fail();
1334 } catch (IllegalArgumentException ex) {}
1335 try {
1336 DateUtils.ceiling((Calendar) null, Calendar.SECOND);
1337 fail();
1338 } catch (IllegalArgumentException ex) {}
1339 try {
1340 DateUtils.ceiling((Object) null, Calendar.SECOND);
1341 fail();
1342 } catch (IllegalArgumentException ex) {}
1343 try {
1344 DateUtils.ceiling("", Calendar.SECOND);
1345 fail();
1346 } catch (ClassCastException ex) {}
1347 try {
1348 DateUtils.ceiling(date1, -9999);
1349 fail();
1350 } catch(IllegalArgumentException ex) {}
1351
1352
1353 // Fix for http://issues.apache.org/bugzilla/show_bug.cgi?id=25560
1354 // Test ceiling across the beginning of daylight saving time
1355 TimeZone.setDefault(zone);
1356 dateTimeParser.setTimeZone(zone);
1357
1358 assertEquals("ceiling MET date across DST change-over",
1359 dateTimeParser.parse("March 31, 2003 00:00:00.000"),
1360 DateUtils.ceiling(date4, Calendar.DATE));
1361 assertEquals("ceiling MET date across DST change-over",
1362 dateTimeParser.parse("March 31, 2003 00:00:00.000"),
1363 DateUtils.ceiling((Object) cal4, Calendar.DATE));
1364 assertEquals("ceiling MET date across DST change-over",
1365 dateTimeParser.parse("March 31, 2003 00:00:00.000"),
1366 DateUtils.ceiling(date5, Calendar.DATE));
1367 assertEquals("ceiling MET date across DST change-over",
1368 dateTimeParser.parse("March 31, 2003 00:00:00.000"),
1369 DateUtils.ceiling((Object) cal5, Calendar.DATE));
1370 assertEquals("ceiling MET date across DST change-over",
1371 dateTimeParser.parse("March 31, 2003 00:00:00.000"),
1372 DateUtils.ceiling(date6, Calendar.DATE));
1373 assertEquals("ceiling MET date across DST change-over",
1374 dateTimeParser.parse("March 31, 2003 00:00:00.000"),
1375 DateUtils.ceiling((Object) cal6, Calendar.DATE));
1376 assertEquals("ceiling MET date across DST change-over",
1377 dateTimeParser.parse("March 31, 2003 00:00:00.000"),
1378 DateUtils.ceiling(date7, Calendar.DATE));
1379 assertEquals("ceiling MET date across DST change-over",
1380 dateTimeParser.parse("March 31, 2003 00:00:00.000"),
1381 DateUtils.ceiling((Object) cal7, Calendar.DATE));
1382
1383 assertEquals("ceiling MET date across DST change-over",
1384 dateTimeParser.parse("March 30, 2003 03:00:00.000"),
1385 DateUtils.ceiling(date4, Calendar.HOUR_OF_DAY));
1386 assertEquals("ceiling MET date across DST change-over",
1387 dateTimeParser.parse("March 30, 2003 03:00:00.000"),
1388 DateUtils.ceiling((Object) cal4, Calendar.HOUR_OF_DAY));
1389 if (SystemUtils.isJavaVersionAtLeast(JAVA_1_4)) {
1390 assertEquals("ceiling MET date across DST change-over",
1391 dateTimeParser.parse("March 30, 2003 03:00:00.000"),
1392 DateUtils.ceiling(date5, Calendar.HOUR_OF_DAY));
1393 assertEquals("ceiling MET date across DST change-over",
1394 dateTimeParser.parse("March 30, 2003 03:00:00.000"),
1395 DateUtils.ceiling((Object) cal5, Calendar.HOUR_OF_DAY));
1396 assertEquals("ceiling MET date across DST change-over",
1397 dateTimeParser.parse("March 30, 2003 04:00:00.000"),
1398 DateUtils.ceiling(date6, Calendar.HOUR_OF_DAY));
1399 assertEquals("ceiling MET date across DST change-over",
1400 dateTimeParser.parse("March 30, 2003 04:00:00.000"),
1401 DateUtils.ceiling((Object) cal6, Calendar.HOUR_OF_DAY));
1402 assertEquals("ceiling MET date across DST change-over",
1403 dateTimeParser.parse("March 30, 2003 04:00:00.000"),
1404 DateUtils.ceiling(date7, Calendar.HOUR_OF_DAY));
1405 assertEquals("ceiling MET date across DST change-over",
1406 dateTimeParser.parse("March 30, 2003 04:00:00.000"),
1407 DateUtils.ceiling((Object) cal7, Calendar.HOUR_OF_DAY));
1408 } else {
1409 this.warn("WARNING: Some date ceiling tests not run since the current version is " + SystemUtils.JAVA_SPECIFICATION_VERSION);
1410 }
1411 TimeZone.setDefault(defaultZone);
1412 dateTimeParser.setTimeZone(defaultZone);
1413
1414 // Bug 31395, large dates
1415 Date endOfTime = new Date(Long.MAX_VALUE); // fyi: Sun Aug 17 07:12:55 CET 292278994 -- 807 millis
1416 GregorianCalendar endCal = new GregorianCalendar();
1417 endCal.setTime(endOfTime);
1418 try {
1419 DateUtils.ceiling(endCal, Calendar.DATE);
1420 fail();
1421 } catch (ArithmeticException ex) {}
1422 endCal.set(Calendar.YEAR, 280000001);
1423 try {
1424 DateUtils.ceiling(endCal, Calendar.DATE);
1425 fail();
1426 } catch (ArithmeticException ex) {}
1427 endCal.set(Calendar.YEAR, 280000000);
1428 Calendar cal = DateUtils.ceiling(endCal, Calendar.DATE);
1429 assertEquals(0, cal.get(Calendar.HOUR));
1430 }
1431
1432 /**
1433 * Tests the iterator exceptions
1434 */
1435 public void testIteratorEx() throws Exception {
1436 try {
1437 DateUtils.iterator(Calendar.getInstance(), -9999);
1438 } catch (IllegalArgumentException ex) {}
1439 try {
1440 DateUtils.iterator((Date) null, DateUtils.RANGE_WEEK_CENTER);
1441 fail();
1442 } catch (IllegalArgumentException ex) {}
1443 try {
1444 DateUtils.iterator((Calendar) null, DateUtils.RANGE_WEEK_CENTER);
1445 fail();
1446 } catch (IllegalArgumentException ex) {}
1447 try {
1448 DateUtils.iterator((Object) null, DateUtils.RANGE_WEEK_CENTER);
1449 fail();
1450 } catch (IllegalArgumentException ex) {}
1451 try {
1452 DateUtils.iterator("", DateUtils.RANGE_WEEK_CENTER);
1453 fail();
1454 } catch (ClassCastException ex) {}
1455 }
1456
1457 /**
1458 * Tests the calendar iterator for week ranges
1459 */
1460 public void testWeekIterator() throws Exception {
1461 Calendar now = Calendar.getInstance();
1462 for (int i = 0; i< 7; i++) {
1463 Calendar today = DateUtils.truncate(now, Calendar.DATE);
1464 Calendar sunday = DateUtils.truncate(now, Calendar.DATE);
1465 sunday.add(Calendar.DATE, 1 - sunday.get(Calendar.DAY_OF_WEEK));
1466 Calendar monday = DateUtils.truncate(now, Calendar.DATE);
1467 if (monday.get(Calendar.DAY_OF_WEEK) == 1) {
1468 //This is sunday... roll back 6 days
1469 monday.add(Calendar.DATE, -6);
1470 } else {
1471 monday.add(Calendar.DATE, 2 - monday.get(Calendar.DAY_OF_WEEK));
1472 }
1473 Calendar centered = DateUtils.truncate(now, Calendar.DATE);
1474 centered.add(Calendar.DATE, -3);
1475
1476 Iterator<?> it = DateUtils.iterator(now, DateUtils.RANGE_WEEK_SUNDAY);
1477 assertWeekIterator(it, sunday);
1478 it = DateUtils.iterator(now, DateUtils.RANGE_WEEK_MONDAY);
1479 assertWeekIterator(it, monday);
1480 it = DateUtils.iterator(now, DateUtils.RANGE_WEEK_RELATIVE);
1481 assertWeekIterator(it, today);
1482 it = DateUtils.iterator(now, DateUtils.RANGE_WEEK_CENTER);
1483 assertWeekIterator(it, centered);
1484
1485 it = DateUtils.iterator((Object) now, DateUtils.RANGE_WEEK_CENTER);
1486 assertWeekIterator(it, centered);
1487 it = DateUtils.iterator((Object) now.getTime(), DateUtils.RANGE_WEEK_CENTER);
1488 assertWeekIterator(it, centered);
1489 try {
1490 it.next();
1491 fail();
1492 } catch (NoSuchElementException ex) {}
1493 it = DateUtils.iterator(now, DateUtils.RANGE_WEEK_CENTER);
1494 it.next();
1495 try {
1496 it.remove();
1497 } catch( UnsupportedOperationException ex) {}
1498
1499 now.add(Calendar.DATE,1);
1500 }
1501 }
1502
1503 /**
1504 * Tests the calendar iterator for month-based ranges
1505 */
1506 public void testMonthIterator() throws Exception {
1507 Iterator<?> it = DateUtils.iterator(date1, DateUtils.RANGE_MONTH_SUNDAY);
1508 assertWeekIterator(it,
1509 dateParser.parse("January 27, 2002"),
1510 dateParser.parse("March 2, 2002"));
1511
1512 it = DateUtils.iterator(date1, DateUtils.RANGE_MONTH_MONDAY);
1513 assertWeekIterator(it,
1514 dateParser.parse("January 28, 2002"),
1515 dateParser.parse("March 3, 2002"));
1516
1517 it = DateUtils.iterator(date2, DateUtils.RANGE_MONTH_SUNDAY);
1518 assertWeekIterator(it,
1519 dateParser.parse("October 28, 2001"),
1520 dateParser.parse("December 1, 2001"));
1521
1522 it = DateUtils.iterator(date2, DateUtils.RANGE_MONTH_MONDAY);
1523 assertWeekIterator(it,
1524 dateParser.parse("October 29, 2001"),
1525 dateParser.parse("December 2, 2001"));
1526 }
1527
1528 /**
1529 * This checks that this is a 7 element iterator of Calendar objects
1530 * that are dates (no time), and exactly 1 day spaced after each other.
1531 */
1532 private static void assertWeekIterator(Iterator<?> it, Calendar start) {
1533 Calendar end = (Calendar) start.clone();
1534 end.add(Calendar.DATE, 6);
1535
1536 assertWeekIterator(it, start, end);
1537 }
1538
1539 /**
1540 * Convenience method for when working with Date objects
1541 */
1542 private static void assertWeekIterator(Iterator<?> it, Date start, Date end) {
1543 Calendar calStart = Calendar.getInstance();
1544 calStart.setTime(start);
1545 Calendar calEnd = Calendar.getInstance();
1546 calEnd.setTime(end);
1547
1548 assertWeekIterator(it, calStart, calEnd);
1549 }
1550
1551 /**
1552 * This checks that this is a 7 divisble iterator of Calendar objects
1553 * that are dates (no time), and exactly 1 day spaced after each other
1554 * (in addition to the proper start and stop dates)
1555 */
1556 private static void assertWeekIterator(Iterator<?> it, Calendar start, Calendar end) {
1557 Calendar cal = (Calendar) it.next();
1558 assertEquals("", start, cal, 0);
1559 Calendar last = null;
1560 int count = 1;
1561 while (it.hasNext()) {
1562 //Check this is just a date (no time component)
1563 assertEquals("", cal, DateUtils.truncate(cal, Calendar.DATE), 0);
1564
1565 last = cal;
1566 cal = (Calendar) it.next();
1567 count++;
1568
1569 //Check that this is one day more than the last date
1570 last.add(Calendar.DATE, 1);
1571 assertEquals("", last, cal, 0);
1572 }
1573 if (count % 7 != 0) {
1574 throw new AssertionFailedError("There were " + count + " days in this iterator");
1575 }
1576 assertEquals("", end, cal, 0);
1577 }
1578
1579 /**
1580 * Used to check that Calendar objects are close enough
1581 * delta is in milliseconds
1582 */
1583 private static void assertEquals(String message, Calendar cal1, Calendar cal2, long delta) {
1584 if (Math.abs(cal1.getTime().getTime() - cal2.getTime().getTime()) > delta) {
1585 throw new AssertionFailedError(
1586 message + " expected " + cal1.getTime() + " but got " + cal2.getTime());
1587 }
1588 }
1589
1590 void warn(String msg) {
1591 System.err.println(msg);
1592 }
1593 }
1594
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.lang3.time;
18
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Modifier;
21 import java.util.Calendar;
22 import java.util.TimeZone;
23
24 import junit.framework.TestCase;
25
26 /**
27 * TestCase for DurationFormatUtils.
28 *
29 */
30 public class DurationFormatUtilsTest extends TestCase {
31
32 public DurationFormatUtilsTest(String s) {
33 super(s);
34 }
35
36 // -----------------------------------------------------------------------
37 public void testConstructor() {
38 assertNotNull(new DurationFormatUtils());
39 Constructor<?>[] cons = DurationFormatUtils.class.getDeclaredConstructors();
40 assertEquals(1, cons.length);
41 assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
42 assertEquals(true, Modifier.isPublic(DurationFormatUtils.class.getModifiers()));
43 assertEquals(false, Modifier.isFinal(DurationFormatUtils.class.getModifiers()));
44 }
45
46 // -----------------------------------------------------------------------
47 public void testFormatDurationWords() {
48 String text = null;
49
50 text = DurationFormatUtils.formatDurationWords(50 * 1000, true, false);
51 assertEquals("50 seconds", text);
52 text = DurationFormatUtils.formatDurationWords(65 * 1000, true, false);
53 assertEquals("1 minute 5 seconds", text);
54 text = DurationFormatUtils.formatDurationWords(120 * 1000, true, false);
55 assertEquals("2 minutes 0 seconds", text);
56 text = DurationFormatUtils.formatDurationWords(121 * 1000, true, false);
57 assertEquals("2 minutes 1 second", text);
58 text = DurationFormatUtils.formatDurationWords(72 * 60 * 1000, true, false);
59 assertEquals("1 hour 12 minutes 0 seconds", text);
60 text = DurationFormatUtils.formatDurationWords(24 * 60 * 60 * 1000, true, false);
61 assertEquals("1 day 0 hours 0 minutes 0 seconds", text);
62
63 text = DurationFormatUtils.formatDurationWords(50 * 1000, true, true);
64 assertEquals("50 seconds", text);
65 text = DurationFormatUtils.formatDurationWords(65 * 1000, true, true);
66 assertEquals("1 minute 5 seconds", text);
67 text = DurationFormatUtils.formatDurationWords(120 * 1000, true, true);
68 assertEquals("2 minutes", text);
69 text = DurationFormatUtils.formatDurationWords(121 * 1000, true, true);
70 assertEquals("2 minutes 1 second", text);
71 text = DurationFormatUtils.formatDurationWords(72 * 60 * 1000, true, true);
72 assertEquals("1 hour 12 minutes", text);
73 text = DurationFormatUtils.formatDurationWords(24 * 60 * 60 * 1000, true, true);
74 assertEquals("1 day", text);
75
76 text = DurationFormatUtils.formatDurationWords(50 * 1000, false, true);
77 assertEquals("0 days 0 hours 0 minutes 50 seconds", text);
78 text = DurationFormatUtils.formatDurationWords(65 * 1000, false, true);
79 assertEquals("0 days 0 hours 1 minute 5 seconds", text);
80 text = DurationFormatUtils.formatDurationWords(120 * 1000, false, true);
81 assertEquals("0 days 0 hours 2 minutes", text);
82 text = DurationFormatUtils.formatDurationWords(121 * 1000, false, true);
83 assertEquals("0 days 0 hours 2 minutes 1 second", text);
84 text = DurationFormatUtils.formatDurationWords(72 * 60 * 1000, false, true);
85 assertEquals("0 days 1 hour 12 minutes", text);
86 text = DurationFormatUtils.formatDurationWords(24 * 60 * 60 * 1000, false, true);
87 assertEquals("1 day", text);
88
89 text = DurationFormatUtils.formatDurationWords(50 * 1000, false, false);
90 assertEquals("0 days 0 hours 0 minutes 50 seconds", text);
91 text = DurationFormatUtils.formatDurationWords(65 * 1000, false, false);
92 assertEquals("0 days 0 hours 1 minute 5 seconds", text);
93 text = DurationFormatUtils.formatDurationWords(120 * 1000, false, false);
94 assertEquals("0 days 0 hours 2 minutes 0 seconds", text);
95 text = DurationFormatUtils.formatDurationWords(121 * 1000, false, false);
96 assertEquals("0 days 0 hours 2 minutes 1 second", text);
97 text = DurationFormatUtils.formatDurationWords(72 * 60 * 1000, false, false);
98 assertEquals("0 days 1 hour 12 minutes 0 seconds", text);
99 text = DurationFormatUtils.formatDurationWords(24 * 60 * 60 * 1000 + 72 * 60 * 1000, false, false);
100 assertEquals("1 day 1 hour 12 minutes 0 seconds", text);
101 text = DurationFormatUtils.formatDurationWords(2 * 24 * 60 * 60 * 1000 + 72 * 60 * 1000, false, false);
102 assertEquals("2 days 1 hour 12 minutes 0 seconds", text);
103 for (int i = 2; i < 31; i++) {
104 text = DurationFormatUtils.formatDurationWords(i * 24 * 60 * 60 * 1000L, false, false);
105 // assertEquals(i + " days 0 hours 0 minutes 0 seconds", text);
106 //
107 // junit.framework.ComparisonFailure: expected:<25 days 0 hours 0 minutes 0...> but was:<-24 days -17 hours
108 // -2 minutes -47...>
109 // at junit.framework.Assert.assertEquals(Assert.java:81)
110 // at junit.framework.Assert.assertEquals(Assert.java:87)
111 // at
112 // org.apache.commons.lang.time.DurationFormatUtilsTest.testFormatDurationWords(DurationFormatUtilsTest.java:124)
113 // at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
114 // at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
115 // at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
116 // at java.lang.reflect.Method.invoke(Method.java:324)
117 // at junit.framework.TestCase.runTest(TestCase.java:154)
118 // at junit.framework.TestCase.runBare(TestCase.java:127)
119 // at junit.framework.TestResult$1.protect(TestResult.java:106)
120 // at junit.framework.TestResult.runProtected(TestResult.java:124)
121 // at junit.framework.TestResult.run(TestResult.java:109)
122 // at junit.framework.TestCase.run(TestCase.java:118)
123 // at junit.framework.TestSuite.runTest(TestSuite.java:208)
124 // at junit.framework.TestSuite.run(TestSuite.java:203)
125 // at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
126 // at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
127 // at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
128 }
129 }
130
131 /**
132 * Tests that "1 <unit>s" gets converted to "1 <unit>" but that "11 <unit>s" is left alone.
133 */
134 public void testFormatDurationPluralWords() {
135 long oneSecond = 1000;
136 long oneMinute = oneSecond * 60;
137 long oneHour = oneMinute * 60;
138 long oneDay = oneHour * 24;
139 String text = null;
140
141 text = DurationFormatUtils.formatDurationWords(oneSecond, false, false);
142 assertEquals("0 days 0 hours 0 minutes 1 second", text);
143 text = DurationFormatUtils.formatDurationWords(oneSecond * 2, false, false);
144 assertEquals("0 days 0 hours 0 minutes 2 seconds", text);
145 text = DurationFormatUtils.formatDurationWords(oneSecond * 11, false, false);
146 assertEquals("0 days 0 hours 0 minutes 11 seconds", text);
147
148 text = DurationFormatUtils.formatDurationWords(oneMinute, false, false);
149 assertEquals("0 days 0 hours 1 minute 0 seconds", text);
150 text = DurationFormatUtils.formatDurationWords(oneMinute * 2, false, false);
151 assertEquals("0 days 0 hours 2 minutes 0 seconds", text);
152 text = DurationFormatUtils.formatDurationWords(oneMinute * 11, false, false);
153 assertEquals("0 days 0 hours 11 minutes 0 seconds", text);
154 text = DurationFormatUtils.formatDurationWords(oneMinute + oneSecond, false, false);
155 assertEquals("0 days 0 hours 1 minute 1 second", text);
156
157 text = DurationFormatUtils.formatDurationWords(oneHour, false, false);
158 assertEquals("0 days 1 hour 0 minutes 0 seconds", text);
159 text = DurationFormatUtils.formatDurationWords(oneHour * 2, false, false);
160 assertEquals("0 days 2 hours 0 minutes 0 seconds", text);
161 text = DurationFormatUtils.formatDurationWords(oneHour * 11, false, false);
162 assertEquals("0 days 11 hours 0 minutes 0 seconds", text);
163 text = DurationFormatUtils.formatDurationWords(oneHour + oneMinute + oneSecond, false, false);
164 assertEquals("0 days 1 hour 1 minute 1 second", text);
165
166 text = DurationFormatUtils.formatDurationWords(oneDay, false, false);
167 assertEquals("1 day 0 hours 0 minutes 0 seconds", text);
168 text = DurationFormatUtils.formatDurationWords(oneDay * 2, false, false);
169 assertEquals("2 days 0 hours 0 minutes 0 seconds", text);
170 text = DurationFormatUtils.formatDurationWords(oneDay * 11, false, false);
171 assertEquals("11 days 0 hours 0 minutes 0 seconds", text);
172 text = DurationFormatUtils.formatDurationWords(oneDay + oneHour + oneMinute + oneSecond, false, false);
173 assertEquals("1 day 1 hour 1 minute 1 second", text);
174 }
175
176 public void testFormatDurationHMS() {
177 long time = 0;
178 assertEquals("0:00:00.000", DurationFormatUtils.formatDurationHMS(time));
179
180 time = 1;
181 assertEquals("0:00:00.001", DurationFormatUtils.formatDurationHMS(time));
182
183 time = 15;
184 assertEquals("0:00:00.015", DurationFormatUtils.formatDurationHMS(time));
185
186 time = 165;
187 assertEquals("0:00:00.165", DurationFormatUtils.formatDurationHMS(time));
188
189 time = 1675;
190 assertEquals("0:00:01.675", DurationFormatUtils.formatDurationHMS(time));
191
192 time = 13465;
193 assertEquals("0:00:13.465", DurationFormatUtils.formatDurationHMS(time));
194
195 time = 72789;
196 assertEquals("0:01:12.789", DurationFormatUtils.formatDurationHMS(time));
197
198 time = 12789 + 32 * 60000;
199 assertEquals("0:32:12.789", DurationFormatUtils.formatDurationHMS(time));
200
201 time = 12789 + 62 * 60000;
202 assertEquals("1:02:12.789", DurationFormatUtils.formatDurationHMS(time));
203 }
204
205 public void testFormatDurationISO() {
206 assertEquals("P0Y0M0DT0H0M0.000S", DurationFormatUtils.formatDurationISO(0L));
207 assertEquals("P0Y0M0DT0H0M0.001S", DurationFormatUtils.formatDurationISO(1L));
208 assertEquals("P0Y0M0DT0H0M0.010S", DurationFormatUtils.formatDurationISO(10L));
209 assertEquals("P0Y0M0DT0H0M0.100S", DurationFormatUtils.formatDurationISO(100L));
210 assertEquals("P0Y0M0DT0H1M15.321S", DurationFormatUtils.formatDurationISO(75321L));
211 }
212
213 public void testFormatDuration() {
214 long duration = 0;
215 assertEquals("0", DurationFormatUtils.formatDuration(duration, "y"));
216 assertEquals("0", DurationFormatUtils.formatDuration(duration, "M"));
217 assertEquals("0", DurationFormatUtils.formatDuration(duration, "d"));
218 assertEquals("0", DurationFormatUtils.formatDuration(duration, "H"));
219 assertEquals("0", DurationFormatUtils.formatDuration(duration, "m"));
220 assertEquals("0", DurationFormatUtils.formatDuration(duration, "s"));
221 assertEquals("0", DurationFormatUtils.formatDuration(duration, "S"));
222 assertEquals("0000", DurationFormatUtils.formatDuration(duration, "SSSS"));
223 assertEquals("0000", DurationFormatUtils.formatDuration(duration, "yyyy"));
224 assertEquals("0000", DurationFormatUtils.formatDuration(duration, "yyMM"));
225
226 duration = 60 * 1000;
227 assertEquals("0", DurationFormatUtils.formatDuration(duration, "y"));
228 assertEquals("0", DurationFormatUtils.formatDuration(duration, "M"));
229 assertEquals("0", DurationFormatUtils.formatDuration(duration, "d"));
230 assertEquals("0", DurationFormatUtils.formatDuration(duration, "H"));
231 assertEquals("1", DurationFormatUtils.formatDuration(duration, "m"));
232 assertEquals("60", DurationFormatUtils.formatDuration(duration, "s"));
233 assertEquals("60000", DurationFormatUtils.formatDuration(duration, "S"));
234 assertEquals("01:00", DurationFormatUtils.formatDuration(duration, "mm:ss"));
235
236 Calendar base = Calendar.getInstance();
237 base.set(2000, 0, 1, 0, 0, 0);
238 base.set(Calendar.MILLISECOND, 0);
239
240 Calendar cal = Calendar.getInstance();
241 cal.set(2003, 1, 1, 0, 0, 0);
242 cal.set(Calendar.MILLISECOND, 0);
243 duration = cal.getTime().getTime() - base.getTime().getTime(); // duration from 2000-01-01 to cal
244 // don't use 1970 in test as time zones were less reliable in 1970 than now
245 // remember that duration formatting ignores time zones, working on strict hour lengths
246 int days = 366 + 365 + 365 + 31;
247 assertEquals("0 0 " + days, DurationFormatUtils.formatDuration(duration, "y M d"));
248 }
249
250 public void testFormatPeriodISO() {
251 TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
252 Calendar base = Calendar.getInstance(timeZone);
253 base.set(1970, 0, 1, 0, 0, 0);
254 base.set(Calendar.MILLISECOND, 0);
255
256 Calendar cal = Calendar.getInstance(timeZone);
257 cal.set(2002, 1, 23, 9, 11, 12);
258 cal.set(Calendar.MILLISECOND, 1);
259 String text;
260 // repeat a test from testDateTimeISO to compare extended and not extended.
261 text = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(cal);
262 assertEquals("2002-02-23T09:11:12-03:00", text);
263 // test fixture is the same as above, but now with extended format.
264 text = DurationFormatUtils.formatPeriod(base.getTime().getTime(), cal.getTime().getTime(),
265 DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false, timeZone);
266 assertEquals("P32Y1M22DT9H11M12.001S", text);
267 // test fixture from example in http://www.w3.org/TR/xmlschema-2/#duration
268 cal.set(1971, 1, 3, 10, 30, 0);
269 cal.set(Calendar.MILLISECOND, 0);
270 text = DurationFormatUtils.formatPeriod(base.getTime().getTime(), cal.getTime().getTime(),
271 DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false, timeZone);
272 assertEquals("P1Y1M2DT10H30M0.000S", text);
273 // want a way to say 'don't print the seconds in format()' or other fields for that matter:
274 // assertEquals("P1Y2M3DT10H30M", text);
275 }
276
277 public void testFormatPeriod() {
278 Calendar cal1970 = Calendar.getInstance();
279 cal1970.set(1970, 0, 1, 0, 0, 0);
280 cal1970.set(Calendar.MILLISECOND, 0);
281 long time1970 = cal1970.getTime().getTime();
282
283 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "y"));
284 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "M"));
285 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "d"));
286 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "H"));
287 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "m"));
288 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "s"));
289 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "S"));
290 assertEquals("0000", DurationFormatUtils.formatPeriod(time1970, time1970, "SSSS"));
291 assertEquals("0000", DurationFormatUtils.formatPeriod(time1970, time1970, "yyyy"));
292 assertEquals("0000", DurationFormatUtils.formatPeriod(time1970, time1970, "yyMM"));
293
294 long time = time1970 + 60 * 1000;
295 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time, "y"));
296 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time, "M"));
297 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time, "d"));
298 assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time, "H"));
299 assertEquals("1", DurationFormatUtils.formatPeriod(time1970, time, "m"));
300 assertEquals("60", DurationFormatUtils.formatPeriod(time1970, time, "s"));
301 assertEquals("60000", DurationFormatUtils.formatPeriod(time1970, time, "S"));
302 assertEquals("01:00", DurationFormatUtils.formatPeriod(time1970, time, "mm:ss"));
303
304 Calendar cal = Calendar.getInstance();
305 cal.set(1973, 6, 1, 0, 0, 0);
306 cal.set(Calendar.MILLISECOND, 0);
307 time = cal.getTime().getTime();
308 assertEquals("36", DurationFormatUtils.formatPeriod(time1970, time, "yM"));
309 assertEquals("3 years 6 months", DurationFormatUtils.formatPeriod(time1970, time, "y' years 'M' months'"));
310 assertEquals("03/06", DurationFormatUtils.formatPeriod(time1970, time, "yy/MM"));
311
312 cal.set(1973, 10, 1, 0, 0, 0);
313 cal.set(Calendar.MILLISECOND, 0);
314 time = cal.getTime().getTime();
315 assertEquals("310", DurationFormatUtils.formatPeriod(time1970, time, "yM"));
316 assertEquals("3 years 10 months", DurationFormatUtils.formatPeriod(time1970, time, "y' years 'M' months'"));
317 assertEquals("03/10", DurationFormatUtils.formatPeriod(time1970, time, "yy/MM"));
318
319 cal.set(1974, 0, 1, 0, 0, 0);
320 cal.set(Calendar.MILLISECOND, 0);
321 time = cal.getTime().getTime();
322 assertEquals("40", DurationFormatUtils.formatPeriod(time1970, time, "yM"));
323 assertEquals("4 years 0 months", DurationFormatUtils.formatPeriod(time1970, time, "y' years 'M' months'"));
324 assertEquals("04/00", DurationFormatUtils.formatPeriod(time1970, time, "yy/MM"));
325 assertEquals("48", DurationFormatUtils.formatPeriod(time1970, time, "M"));
326 assertEquals("48", DurationFormatUtils.formatPeriod(time1970, time, "MM"));
327 assertEquals("048", DurationFormatUtils.formatPeriod(time1970, time, "MMM"));
328 }
329
330 public void testLexx() {
331 // tests each constant
332 assertArrayEquals(new DurationFormatUtils.Token[]{
333 new DurationFormatUtils.Token(DurationFormatUtils.y, 1),
334 new DurationFormatUtils.Token(DurationFormatUtils.M, 1),
335 new DurationFormatUtils.Token(DurationFormatUtils.d, 1),
336 new DurationFormatUtils.Token(DurationFormatUtils.H, 1),
337 new DurationFormatUtils.Token(DurationFormatUtils.m, 1),
338 new DurationFormatUtils.Token(DurationFormatUtils.s, 1),
339 new DurationFormatUtils.Token(DurationFormatUtils.S, 1)}, DurationFormatUtils.lexx("yMdHmsS"));
340
341 // tests the ISO8601-like
342 assertArrayEquals(new DurationFormatUtils.Token[]{
343 new DurationFormatUtils.Token(DurationFormatUtils.H, 1),
344 new DurationFormatUtils.Token(new StringBuffer(":"), 1),
345 new DurationFormatUtils.Token(DurationFormatUtils.m, 2),
346 new DurationFormatUtils.Token(new StringBuffer(":"), 1),
347 new DurationFormatUtils.Token(DurationFormatUtils.s, 2),
348 new DurationFormatUtils.Token(new StringBuffer("."), 1),
349 new DurationFormatUtils.Token(DurationFormatUtils.S, 3)}, DurationFormatUtils.lexx("H:mm:ss.SSS"));
350
351 // test the iso extended format
352 assertArrayEquals(new DurationFormatUtils.Token[]{
353 new DurationFormatUtils.Token(new StringBuffer("P"), 1),
354 new DurationFormatUtils.Token(DurationFormatUtils.y, 4),
355 new DurationFormatUtils.Token(new StringBuffer("Y"), 1),
356 new DurationFormatUtils.Token(DurationFormatUtils.M, 1),
357 new DurationFormatUtils.Token(new StringBuffer("M"), 1),
358 new DurationFormatUtils.Token(DurationFormatUtils.d, 1),
359 new DurationFormatUtils.Token(new StringBuffer("DT"), 1),
360 new DurationFormatUtils.Token(DurationFormatUtils.H, 1),
361 new DurationFormatUtils.Token(new StringBuffer("H"), 1),
362 new DurationFormatUtils.Token(DurationFormatUtils.m, 1),
363 new DurationFormatUtils.Token(new StringBuffer("M"), 1),
364 new DurationFormatUtils.Token(DurationFormatUtils.s, 1),
365 new DurationFormatUtils.Token(new StringBuffer("."), 1),
366 new DurationFormatUtils.Token(DurationFormatUtils.S, 1),
367 new DurationFormatUtils.Token(new StringBuffer("S"), 1)}, DurationFormatUtils
368 .lexx(DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN));
369
370 // test failures in equals
371 DurationFormatUtils.Token token = new DurationFormatUtils.Token(DurationFormatUtils.y, 4);
372 assertFalse("Token equal to non-Token class. ", token.equals(new Object()));
373 assertFalse("Token equal to Token with wrong value class. ", token.equals(new DurationFormatUtils.Token(
374 new Object())));
375 assertFalse("Token equal to Token with different count. ", token.equals(new DurationFormatUtils.Token(
376 DurationFormatUtils.y, 1)));
377 DurationFormatUtils.Token numToken = new DurationFormatUtils.Token(Integer.valueOf(1), 4);
378 assertTrue("Token with Number value not equal to itself. ", numToken.equals(numToken));
379 }
380
381
382 // http://issues.apache.org/bugzilla/show_bug.cgi?id=38401
383 public void testBugzilla38401() {
384 assertEqualDuration( "0000/00/30 16:00:00 000", new int[] { 2006, 0, 26, 18, 47, 34 },
385 new int[] { 2006, 1, 26, 10, 47, 34 }, "yyyy/MM/dd HH:mm:ss SSS");
386 }
387
388 // https://issues.apache.org/jira/browse/LANG-281
389 public void testJiraLang281() {
390 assertEqualDuration( "09", new int[] { 2005, 11, 31, 0, 0, 0 },
391 new int[] { 2006, 9, 6, 0, 0, 0 }, "MM");
392 }
393
394 // Testing the under a day range in DurationFormatUtils.formatPeriod
395 public void testLowDurations() {
396 for(int hr=0; hr < 24; hr++) {
397 for(int min=0; min < 60; min++) {
398 for(int sec=0; sec < 60; sec++) {
399 assertEqualDuration( hr + ":" + min + ":" + sec,
400 new int[] { 2000, 0, 1, 0, 0, 0, 0 },
401 new int[] { 2000, 0, 1, hr, min, sec },
402 "H:m:s"
403 );
404 }
405 }
406 }
407 }
408
409 // Attempting to test edge cases in DurationFormatUtils.formatPeriod
410 public void testEdgeDurations() {
411 assertEqualDuration( "01", new int[] { 2006, 0, 15, 0, 0, 0 },
412 new int[] { 2006, 2, 10, 0, 0, 0 }, "MM");
413 assertEqualDuration( "12", new int[] { 2005, 0, 15, 0, 0, 0 },
414 new int[] { 2006, 0, 15, 0, 0, 0 }, "MM");
415 assertEqualDuration( "12", new int[] { 2005, 0, 15, 0, 0, 0 },
416 new int[] { 2006, 0, 16, 0, 0, 0 }, "MM");
417 assertEqualDuration( "11", new int[] { 2005, 0, 15, 0, 0, 0 },
418 new int[] { 2006, 0, 14, 0, 0, 0 }, "MM");
419
420 assertEqualDuration( "01 26", new int[] { 2006, 0, 15, 0, 0, 0 },
421 new int[] { 2006, 2, 10, 0, 0, 0 }, "MM dd");
422 assertEqualDuration( "54", new int[] { 2006, 0, 15, 0, 0, 0 },
423 new int[] { 2006, 2, 10, 0, 0, 0 }, "dd");
424
425 assertEqualDuration( "09 12", new int[] { 2006, 1, 20, 0, 0, 0 },
426 new int[] { 2006, 11, 4, 0, 0, 0 }, "MM dd");
427 assertEqualDuration( "287", new int[] { 2006, 1, 20, 0, 0, 0 },
428 new int[] { 2006, 11, 4, 0, 0, 0 }, "dd");
429
430 assertEqualDuration( "11 30", new int[] { 2006, 0, 2, 0, 0, 0 },
431 new int[] { 2007, 0, 1, 0, 0, 0 }, "MM dd");
432 assertEqualDuration( "364", new int[] { 2006, 0, 2, 0, 0, 0 },
433 new int[] { 2007, 0, 1, 0, 0, 0 }, "dd");
434
435 assertEqualDuration( "12 00", new int[] { 2006, 0, 1, 0, 0, 0 },
436 new int[] { 2007, 0, 1, 0, 0, 0 }, "MM dd");
437 assertEqualDuration( "365", new int[] { 2006, 0, 1, 0, 0, 0 },
438 new int[] { 2007, 0, 1, 0, 0, 0 }, "dd");
439
440 assertEqualDuration( "31", new int[] { 2006, 0, 1, 0, 0, 0 },
441 new int[] { 2006, 1, 1, 0, 0, 0 }, "dd");
442
443 assertEqualDuration( "92", new int[] { 2005, 9, 1, 0, 0, 0 },
444 new int[] { 2006, 0, 1, 0, 0, 0 }, "dd");
445 assertEqualDuration( "77", new int[] { 2005, 9, 16, 0, 0, 0 },
446 new int[] { 2006, 0, 1, 0, 0, 0 }, "dd");
447
448 // test month larger in start than end
449 assertEqualDuration( "136", new int[] { 2005, 9, 16, 0, 0, 0 },
450 new int[] { 2006, 2, 1, 0, 0, 0 }, "dd");
451 // test when start in leap year
452 assertEqualDuration( "136", new int[] { 2004, 9, 16, 0, 0, 0 },
453 new int[] { 2005, 2, 1, 0, 0, 0 }, "dd");
454 // test when end in leap year
455 assertEqualDuration( "137", new int[] { 2003, 9, 16, 0, 0, 0 },
456 new int[] { 2004, 2, 1, 0, 0, 0 }, "dd");
457 // test when end in leap year but less than end of feb
458 assertEqualDuration( "135", new int[] { 2003, 9, 16, 0, 0, 0 },
459 new int[] { 2004, 1, 28, 0, 0, 0 }, "dd");
460
461 assertEqualDuration( "364", new int[] { 2007, 0, 2, 0, 0, 0 },
462 new int[] { 2008, 0, 1, 0, 0, 0 }, "dd");
463 assertEqualDuration( "729", new int[] { 2006, 0, 2, 0, 0, 0 },
464 new int[] { 2008, 0, 1, 0, 0, 0 }, "dd");
465
466 assertEqualDuration( "365", new int[] { 2007, 2, 2, 0, 0, 0 },
467 new int[] { 2008, 2, 1, 0, 0, 0 }, "dd");
468 assertEqualDuration( "333", new int[] { 2007, 1, 2, 0, 0, 0 },
469 new int[] { 2008, 0, 1, 0, 0, 0 }, "dd");
470
471 assertEqualDuration( "28", new int[] { 2008, 1, 2, 0, 0, 0 },
472 new int[] { 2008, 2, 1, 0, 0, 0 }, "dd");
473 assertEqualDuration( "393", new int[] { 2007, 1, 2, 0, 0, 0 },
474 new int[] { 2008, 2, 1, 0, 0, 0 }, "dd");
475
476 assertEqualDuration( "369", new int[] { 2004, 0, 29, 0, 0, 0 },
477 new int[] { 2005, 1, 1, 0, 0, 0 }, "dd");
478
479 assertEqualDuration( "338", new int[] { 2004, 1, 29, 0, 0, 0 },
480 new int[] { 2005, 1, 1, 0, 0, 0 }, "dd");
481
482 assertEqualDuration( "28", new int[] { 2004, 2, 8, 0, 0, 0 },
483 new int[] { 2004, 3, 5, 0, 0, 0 }, "dd");
484
485 assertEqualDuration( "48", new int[] { 1992, 1, 29, 0, 0, 0 },
486 new int[] { 1996, 1, 29, 0, 0, 0 }, "M");
487
488
489 // this seems odd - and will fail if I throw it in as a brute force
490 // below as it expects the answer to be 12. It's a tricky edge case
491 assertEqualDuration( "11", new int[] { 1996, 1, 29, 0, 0, 0 },
492 new int[] { 1997, 1, 28, 0, 0, 0 }, "M");
493 // again - this seems odd
494 assertEqualDuration( "11 28", new int[] { 1996, 1, 29, 0, 0, 0 },
495 new int[] { 1997, 1, 28, 0, 0, 0 }, "M d");
496
497 }
498
499 public void testDurationsByBruteForce() {
500 bruteForce(2006, 0, 1, "d", Calendar.DAY_OF_MONTH);
501 bruteForce(2006, 0, 2, "d", Calendar.DAY_OF_MONTH);
502 bruteForce(2007, 1, 2, "d", Calendar.DAY_OF_MONTH);
503 bruteForce(2004, 1, 29, "d", Calendar.DAY_OF_MONTH);
504 bruteForce(1996, 1, 29, "d", Calendar.DAY_OF_MONTH);
505
506 bruteForce(1969, 1, 28, "M", Calendar.MONTH); // tests for 48 years
507 //bruteForce(1996, 1, 29, "M", Calendar.MONTH); // this will fail
508 }
509
510 private static final int FOUR_YEARS = 365 * 3 + 366;
511
512 // Takes a minute to run, so generally turned off
513 // public void testBrutally() {
514 // Calendar c = Calendar.getInstance();
515 // c.set(2004, 0, 1, 0, 0, 0);
516 // for (int i=0; i < FOUR_YEARS; i++) {
517 // bruteForce(c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH), "d", Calendar.DAY_OF_MONTH );
518 // c.add(Calendar.DAY_OF_MONTH, 1);
519 // }
520 // }
521
522 private void bruteForce(int year, int month, int day, String format, int calendarType) {
523 String msg = year + "-" + month + "-" + day + " to ";
524 Calendar c = Calendar.getInstance();
525 c.set(year, month, day, 0, 0, 0);
526 int[] array1 = new int[] { year, month, day, 0, 0, 0 };
527 int[] array2 = new int[] { year, month, day, 0, 0, 0 };
528 for (int i=0; i < FOUR_YEARS; i++) {
529 array2[0] = c.get(Calendar.YEAR);
530 array2[1] = c.get(Calendar.MONTH);
531 array2[2] = c.get(Calendar.DAY_OF_MONTH);
532 String tmpMsg = msg + array2[0] + "-" + array2[1] + "-" + array2[2] + " at ";
533 assertEqualDuration( tmpMsg + i, Integer.toString(i), array1, array2, format );
534 c.add(calendarType, 1);
535 }
536 }
537
538 private void assertEqualDuration(String expected, int[] start, int[] end, String format) {
539 assertEqualDuration(null, expected, start, end, format);
540 }
541 private void assertEqualDuration(String message, String expected, int[] start, int[] end, String format) {
542 Calendar cal1 = Calendar.getInstance();
543 cal1.set(start[0], start[1], start[2], start[3], start[4], start[5]);
544 cal1.set(Calendar.MILLISECOND, 0);
545 Calendar cal2 = Calendar.getInstance();
546 cal2.set(end[0], end[1], end[2], end[3], end[4], end[5]);
547 cal2.set(Calendar.MILLISECOND, 0);
548 long milli1 = cal1.getTime().getTime();
549 long milli2 = cal2.getTime().getTime();
550 String result = DurationFormatUtils.formatPeriod(milli1, milli2, format);
551 if (message == null) {
552 assertEquals(expected, result);
553 } else {
554 assertEquals(message, expected, result);
555 }
556 }
557
558 private void assertArrayEquals(DurationFormatUtils.Token[] obj1, DurationFormatUtils.Token[] obj2) {
559 assertEquals("Arrays are unequal length. ", obj1.length, obj2.length);
560 for (int i = 0; i < obj1.length; i++) {
561 assertTrue("Index " + i + " not equal, " + obj1[i] + " vs " + obj2[i], obj1[i].equals(obj2[i]));
562 }
563 }
564
565 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import java.text.SimpleDateFormat;
19 import java.util.Calendar;
20 import java.util.Date;
21 import java.util.GregorianCalendar;
22 import java.util.Locale;
23 import java.util.TimeZone;
24
25 import junit.framework.TestCase;
26
27 import org.apache.commons.lang3.SerializationUtils;
28
29 /**
30 * Unit tests {@link org.apache.commons.lang3.time.FastDateFormat}.
31 *
32 * @since 2.0
33 * @version $Id: FastDateFormatTest.java 1146138 2011-07-13 17:01:37Z joehni $
34 */
35 public class FastDateFormatTest extends TestCase {
36
37 public FastDateFormatTest(String name) {
38 super(name);
39 }
40
41 public void test_getInstance() {
42 FastDateFormat format1 = FastDateFormat.getInstance();
43 FastDateFormat format2 = FastDateFormat.getInstance();
44 assertSame(format1, format2);
45 assertEquals(new SimpleDateFormat().toPattern(), format1.getPattern());
46 }
47
48 public void test_getInstance_String() {
49 FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy");
50 FastDateFormat format2 = FastDateFormat.getInstance("MM-DD-yyyy");
51 FastDateFormat format3 = FastDateFormat.getInstance("MM-DD-yyyy");
52
53 assertTrue(format1 != format2); // -- junit 3.8 version -- assertFalse(format1 == format2);
54 assertSame(format2, format3);
55 assertEquals("MM/DD/yyyy", format1.getPattern());
56 assertEquals(TimeZone.getDefault(), format1.getTimeZone());
57 assertEquals(TimeZone.getDefault(), format2.getTimeZone());
58 }
59
60 public void test_getInstance_String_TimeZone() {
61 Locale realDefaultLocale = Locale.getDefault();
62 TimeZone realDefaultZone = TimeZone.getDefault();
63 try {
64 Locale.setDefault(Locale.US);
65 TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
66
67 FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy",
68 TimeZone.getTimeZone("Atlantic/Reykjavik"));
69 FastDateFormat format2 = FastDateFormat.getInstance("MM/DD/yyyy");
70 FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
71 FastDateFormat format4 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
72 FastDateFormat format5 = FastDateFormat.getInstance("MM-DD-yyyy", TimeZone.getDefault());
73 FastDateFormat format6 = FastDateFormat.getInstance("MM-DD-yyyy");
74
75 assertTrue(format1 != format2); // -- junit 3.8 version -- assertFalse(format1 == format2);
76 assertEquals(TimeZone.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
77 assertEquals(TimeZone.getDefault(), format2.getTimeZone());
78 assertSame(format3, format4);
79 assertTrue(format3 != format5); // -- junit 3.8 version -- assertFalse(format3 == format5);
80 assertTrue(format4 != format6); // -- junit 3.8 version -- assertFalse(format3 == format5);
81
82 } finally {
83 Locale.setDefault(realDefaultLocale);
84 TimeZone.setDefault(realDefaultZone);
85 }
86 }
87
88 public void test_getInstance_String_Locale() {
89 Locale realDefaultLocale = Locale.getDefault();
90 try {
91 Locale.setDefault(Locale.US);
92 FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy", Locale.GERMANY);
93 FastDateFormat format2 = FastDateFormat.getInstance("MM/DD/yyyy");
94 FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy", Locale.GERMANY);
95
96 assertTrue(format1 != format2); // -- junit 3.8 version -- assertFalse(format1 == format2);
97 assertSame(format1, format3);
98 assertEquals(Locale.GERMANY, format1.getLocale());
99
100 } finally {
101 Locale.setDefault(realDefaultLocale);
102 }
103 }
104
105 public void test_changeDefault_Locale_DateInstance() {
106 Locale realDefaultLocale = Locale.getDefault();
107 try {
108 Locale.setDefault(Locale.US);
109 FastDateFormat format1 = FastDateFormat.getDateInstance(FastDateFormat.FULL, Locale.GERMANY);
110 FastDateFormat format2 = FastDateFormat.getDateInstance(FastDateFormat.FULL);
111 Locale.setDefault(Locale.GERMANY);
112 FastDateFormat format3 = FastDateFormat.getDateInstance(FastDateFormat.FULL);
113
114 assertSame(Locale.GERMANY, format1.getLocale());
115 assertSame(Locale.US, format2.getLocale());
116 assertSame(Locale.GERMANY, format3.getLocale());
117 assertTrue(format1 != format2); // -- junit 3.8 version -- assertFalse(format1 == format2);
118 assertTrue(format2 != format3);
119
120 } finally {
121 Locale.setDefault(realDefaultLocale);
122 }
123 }
124
125 public void test_changeDefault_Locale_DateTimeInstance() {
126 Locale realDefaultLocale = Locale.getDefault();
127 try {
128 Locale.setDefault(Locale.US);
129 FastDateFormat format1 = FastDateFormat.getDateTimeInstance(FastDateFormat.FULL, FastDateFormat.FULL, Locale.GERMANY);
130 FastDateFormat format2 = FastDateFormat.getDateTimeInstance(FastDateFormat.FULL, FastDateFormat.FULL);
131 Locale.setDefault(Locale.GERMANY);
132 FastDateFormat format3 = FastDateFormat.getDateTimeInstance(FastDateFormat.FULL, FastDateFormat.FULL);
133
134 assertSame(Locale.GERMANY, format1.getLocale());
135 assertSame(Locale.US, format2.getLocale());
136 assertSame(Locale.GERMANY, format3.getLocale());
137 assertTrue(format1 != format2); // -- junit 3.8 version -- assertFalse(format1 == format2);
138 assertTrue(format2 != format3);
139
140 } finally {
141 Locale.setDefault(realDefaultLocale);
142 }
143 }
144
145 public void test_getInstance_String_TimeZone_Locale() {
146 Locale realDefaultLocale = Locale.getDefault();
147 TimeZone realDefaultZone = TimeZone.getDefault();
148 try {
149 Locale.setDefault(Locale.US);
150 TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
151
152 FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy",
153 TimeZone.getTimeZone("Atlantic/Reykjavik"), Locale.GERMANY);
154 FastDateFormat format2 = FastDateFormat.getInstance("MM/DD/yyyy", Locale.GERMANY);
155 FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy",
156 TimeZone.getDefault(), Locale.GERMANY);
157
158 assertTrue(format1 != format2); // -- junit 3.8 version -- assertNotSame(format1, format2);
159 assertEquals(TimeZone.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
160 assertEquals(TimeZone.getDefault(), format2.getTimeZone());
161 assertEquals(TimeZone.getDefault(), format3.getTimeZone());
162 assertEquals(Locale.GERMANY, format1.getLocale());
163 assertEquals(Locale.GERMANY, format2.getLocale());
164 assertEquals(Locale.GERMANY, format3.getLocale());
165
166 } finally {
167 Locale.setDefault(realDefaultLocale);
168 TimeZone.setDefault(realDefaultZone);
169 }
170 }
171
172 public void testFormat() {
173 Locale realDefaultLocale = Locale.getDefault();
174 TimeZone realDefaultZone = TimeZone.getDefault();
175 try {
176 Locale.setDefault(Locale.US);
177 TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
178
179 GregorianCalendar cal1 = new GregorianCalendar(2003, 0, 10, 15, 33, 20);
180 GregorianCalendar cal2 = new GregorianCalendar(2003, 6, 10, 9, 00, 00);
181 Date date1 = cal1.getTime();
182 Date date2 = cal2.getTime();
183 long millis1 = date1.getTime();
184 long millis2 = date2.getTime();
185
186 FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
187 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
188 assertEquals(sdf.format(date1), fdf.format(date1));
189 assertEquals("2003-01-10T15:33:20", fdf.format(date1));
190 assertEquals("2003-01-10T15:33:20", fdf.format(cal1));
191 assertEquals("2003-01-10T15:33:20", fdf.format(millis1));
192 assertEquals("2003-07-10T09:00:00", fdf.format(date2));
193 assertEquals("2003-07-10T09:00:00", fdf.format(cal2));
194 assertEquals("2003-07-10T09:00:00", fdf.format(millis2));
195
196 fdf = FastDateFormat.getInstance("Z");
197 assertEquals("-0500", fdf.format(date1));
198 assertEquals("-0500", fdf.format(cal1));
199 assertEquals("-0500", fdf.format(millis1));
200
201 assertEquals("-0400", fdf.format(date2));
202 assertEquals("-0400", fdf.format(cal2));
203 assertEquals("-0400", fdf.format(millis2));
204
205 fdf = FastDateFormat.getInstance("ZZ");
206 assertEquals("-05:00", fdf.format(date1));
207 assertEquals("-05:00", fdf.format(cal1));
208 assertEquals("-05:00", fdf.format(millis1));
209
210 assertEquals("-04:00", fdf.format(date2));
211 assertEquals("-04:00", fdf.format(cal2));
212 assertEquals("-04:00", fdf.format(millis2));
213
214 String pattern = "GGGG GGG GG G yyyy yyy yy y MMMM MMM MM M" +
215 " dddd ddd dd d DDDD DDD DD D EEEE EEE EE E aaaa aaa aa a zzzz zzz zz z";
216 fdf = FastDateFormat.getInstance(pattern);
217 sdf = new SimpleDateFormat(pattern);
218 // SDF bug fix starting with Java 7
219 assertEquals(sdf.format(date1).replaceAll("2003 03 03 03", "2003 2003 03 2003"), fdf.format(date1));
220 assertEquals(sdf.format(date2).replaceAll("2003 03 03 03", "2003 2003 03 2003"), fdf.format(date2));
221 } finally {
222 Locale.setDefault(realDefaultLocale);
223 TimeZone.setDefault(realDefaultZone);
224 }
225 }
226
227 /**
228 * Test case for {@link FastDateFormat#getDateInstance(int, java.util.Locale)}.
229 */
230 public void testShortDateStyleWithLocales() {
231 Locale usLocale = Locale.US;
232 Locale swedishLocale = new Locale("sv", "SE");
233 Calendar cal = Calendar.getInstance();
234 cal.set(2004, 1, 3);
235 FastDateFormat fdf = FastDateFormat.getDateInstance(FastDateFormat.SHORT, usLocale);
236 assertEquals("2/3/04", fdf.format(cal));
237
238 fdf = FastDateFormat.getDateInstance(FastDateFormat.SHORT, swedishLocale);
239 assertEquals("2004-02-03", fdf.format(cal));
240
241 }
242
243 /**
244 * Tests that pre-1000AD years get padded with yyyy
245 */
246 public void testLowYearPadding() {
247 Calendar cal = Calendar.getInstance();
248 FastDateFormat format = FastDateFormat.getInstance("yyyy/MM/DD");
249
250 cal.set(1,0,1);
251 assertEquals("0001/01/01", format.format(cal));
252 cal.set(10,0,1);
253 assertEquals("0010/01/01", format.format(cal));
254 cal.set(100,0,1);
255 assertEquals("0100/01/01", format.format(cal));
256 cal.set(999,0,1);
257 assertEquals("0999/01/01", format.format(cal));
258 }
259 /**
260 * Show Bug #39410 is solved
261 */
262 public void testMilleniumBug() {
263 Calendar cal = Calendar.getInstance();
264 FastDateFormat format = FastDateFormat.getInstance("dd.MM.yyyy");
265
266 cal.set(1000,0,1);
267 assertEquals("01.01.1000", format.format(cal));
268 }
269
270 /**
271 * testLowYearPadding showed that the date was buggy
272 * This test confirms it, getting 366 back as a date
273 */
274 public void testSimpleDate() {
275 Calendar cal = Calendar.getInstance();
276 FastDateFormat format = FastDateFormat.getInstance("yyyy/MM/dd");
277
278 cal.set(2004,11,31);
279 assertEquals("2004/12/31", format.format(cal));
280 cal.set(999,11,31);
281 assertEquals("0999/12/31", format.format(cal));
282 cal.set(1,2,2);
283 assertEquals("0001/03/02", format.format(cal));
284 }
285
286 public void testLang303() {
287 Calendar cal = Calendar.getInstance();
288 cal.set(2004,11,31);
289
290 FastDateFormat format = FastDateFormat.getInstance("yyyy/MM/dd");
291 String output = format.format(cal);
292
293 format = (FastDateFormat) SerializationUtils.deserialize( SerializationUtils.serialize( format ) );
294 assertEquals(output, format.format(cal));
295 }
296
297 public void testLang538() {
298 // more commonly constructed with: cal = new GregorianCalendar(2009, 9, 16, 8, 42, 16)
299 // for the unit test to work in any time zone, constructing with GMT-8 rather than default locale time zone
300 GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT-8"));
301 cal.clear();
302 cal.set(2009, 9, 16, 8, 42, 16);
303
304 FastDateFormat format = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("GMT"));
305 assertEquals("dateTime", "2009-10-16T16:42:16.000Z", format.format(cal.getTime()));
306 assertEquals("dateTime", "2009-10-16T08:42:16.000Z", format.format(cal));
307 }
308
309 public void testLang645() {
310 Locale locale = new Locale("sv", "SE");
311
312 Calendar cal = Calendar.getInstance();
313 cal.set(2010, 0, 1, 12, 0, 0);
314 Date d = cal.getTime();
315
316 FastDateFormat fdf = FastDateFormat.getInstance("EEEE', week 'ww", locale);
317
318 assertEquals("fredag, week 53", fdf.format(d));
319 }
320 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.time;
17
18 import junit.framework.Assert;
19 import junit.framework.TestCase;
20
21 /**
22 * TestCase for StopWatch.
23 *
24 * @version $Id: StopWatchTest.java 1088899 2011-04-05 05:31:27Z bayard $
25 */
26 public class StopWatchTest extends TestCase {
27
28 public StopWatchTest(String s) {
29 super(s);
30 }
31
32 //-----------------------------------------------------------------------
33 public void testStopWatchSimple(){
34 StopWatch watch = new StopWatch();
35 watch.start();
36 try {Thread.sleep(550);} catch (InterruptedException ex) {}
37 watch.stop();
38 long time = watch.getTime();
39 assertEquals(time, watch.getTime());
40
41 assertTrue(time >= 500);
42 assertTrue(time < 700);
43
44 watch.reset();
45 assertEquals(0, watch.getTime());
46 }
47
48 public void testStopWatchSimpleGet(){
49 StopWatch watch = new StopWatch();
50 assertEquals(0, watch.getTime());
51 assertEquals("0:00:00.000", watch.toString());
52
53 watch.start();
54 try {Thread.sleep(500);} catch (InterruptedException ex) {}
55 assertTrue(watch.getTime() < 2000);
56 }
57
58 public void testStopWatchSplit(){
59 StopWatch watch = new StopWatch();
60 watch.start();
61 try {Thread.sleep(550);} catch (InterruptedException ex) {}
62 watch.split();
63 long splitTime = watch.getSplitTime();
64 String splitStr = watch.toSplitString();
65 try {Thread.sleep(550);} catch (InterruptedException ex) {}
66 watch.unsplit();
67 try {Thread.sleep(550);} catch (InterruptedException ex) {}
68 watch.stop();
69 long totalTime = watch.getTime();
70
71 assertEquals("Formatted split string not the correct length",
72 splitStr.length(), 11);
73 assertTrue(splitTime >= 500);
74 assertTrue(splitTime < 700);
75 assertTrue(totalTime >= 1500);
76 assertTrue(totalTime < 1900);
77 }
78
79 public void testStopWatchSuspend(){
80 StopWatch watch = new StopWatch();
81 watch.start();
82 try {Thread.sleep(550);} catch (InterruptedException ex) {}
83 watch.suspend();
84 long suspendTime = watch.getTime();
85 try {Thread.sleep(550);} catch (InterruptedException ex) {}
86 watch.resume();
87 try {Thread.sleep(550);} catch (InterruptedException ex) {}
88 watch.stop();
89 long totalTime = watch.getTime();
90
91 assertTrue(suspendTime >= 500);
92 assertTrue(suspendTime < 700);
93 assertTrue(totalTime >= 1000);
94 assertTrue(totalTime < 1300);
95 }
96
97 public void testLang315() {
98 StopWatch watch = new StopWatch();
99 watch.start();
100 try {Thread.sleep(200);} catch (InterruptedException ex) {}
101 watch.suspend();
102 long suspendTime = watch.getTime();
103 try {Thread.sleep(200);} catch (InterruptedException ex) {}
104 watch.stop();
105 long totalTime = watch.getTime();
106 assertTrue( suspendTime == totalTime );
107 }
108
109 // test bad states
110 public void testBadStates() {
111 StopWatch watch = new StopWatch();
112 try {
113 watch.stop();
114 fail("Calling stop on an unstarted StopWatch should throw an exception. ");
115 } catch(IllegalStateException ise) {
116 // expected
117 }
118
119 try {
120 watch.stop();
121 fail("Calling stop on an unstarted StopWatch should throw an exception. ");
122 } catch(IllegalStateException ise) {
123 // expected
124 }
125
126 try {
127 watch.suspend();
128 fail("Calling suspend on an unstarted StopWatch should throw an exception. ");
129 } catch(IllegalStateException ise) {
130 // expected
131 }
132
133 try {
134 watch.split();
135 fail("Calling split on a non-running StopWatch should throw an exception. ");
136 } catch(IllegalStateException ise) {
137 // expected
138 }
139
140 try {
141 watch.unsplit();
142 fail("Calling unsplit on an unsplit StopWatch should throw an exception. ");
143 } catch(IllegalStateException ise) {
144 // expected
145 }
146
147 try {
148 watch.resume();
149 fail("Calling resume on an unsuspended StopWatch should throw an exception. ");
150 } catch(IllegalStateException ise) {
151 // expected
152 }
153
154 watch.start();
155
156 try {
157 watch.start();
158 fail("Calling start on a started StopWatch should throw an exception. ");
159 } catch(IllegalStateException ise) {
160 // expected
161 }
162
163 try {
164 watch.unsplit();
165 fail("Calling unsplit on an unsplit StopWatch should throw an exception. ");
166 } catch(IllegalStateException ise) {
167 // expected
168 }
169
170 try {
171 watch.getSplitTime();
172 fail("Calling getSplitTime on an unsplit StopWatch should throw an exception. ");
173 } catch(IllegalStateException ise) {
174 // expected
175 }
176
177 try {
178 watch.resume();
179 fail("Calling resume on an unsuspended StopWatch should throw an exception. ");
180 } catch(IllegalStateException ise) {
181 // expected
182 }
183
184 watch.stop();
185
186 try {
187 watch.start();
188 fail("Calling start on a stopped StopWatch should throw an exception as it needs to be reset. ");
189 } catch(IllegalStateException ise) {
190 // expected
191 }
192 }
193
194 public void testGetStartTime() {
195 long beforeStopWatch = System.currentTimeMillis();
196 StopWatch watch = new StopWatch();
197 try {
198 watch.getStartTime();
199 fail("Calling getStartTime on an unstarted StopWatch should throw an exception");
200 } catch (IllegalStateException expected) {
201 // expected
202 }
203 watch.start();
204 try {
205 watch.getStartTime();
206 Assert.assertTrue(watch.getStartTime() >= beforeStopWatch);
207 } catch (IllegalStateException ex) {
208 fail("Start time should be available: " + ex.getMessage());
209 }
210 watch.reset();
211 try {
212 watch.getStartTime();
213 fail("Calling getStartTime on a reset, but unstarted StopWatch should throw an exception");
214 } catch (IllegalStateException expected) {
215 // expected
216 }
217 }
218
219 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.tuple;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertTrue;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.ObjectInputStream;
26 import java.io.ObjectOutputStream;
27
28 import org.junit.Test;
29
30 /**
31 * Test the Pair class.
32 * @version $Id: ImmutablePairTest.java 1091531 2011-04-12 18:29:49Z ggregory $
33 */
34 public class ImmutablePairTest {
35
36 @Test
37 public void testBasic() throws Exception {
38 ImmutablePair<Integer, String> pair = new ImmutablePair<Integer, String>(0, "foo");
39 assertEquals(0, pair.left.intValue());
40 assertEquals(0, pair.getLeft().intValue());
41 assertEquals("foo", pair.right);
42 assertEquals("foo", pair.getRight());
43 ImmutablePair<Object, String> pair2 = new ImmutablePair<Object, String>(null, "bar");
44 assertNull(pair2.left);
45 assertNull(pair2.getLeft());
46 assertEquals("bar", pair2.right);
47 assertEquals("bar", pair2.getRight());
48 }
49
50 @Test
51 public void testPairOf() throws Exception {
52 ImmutablePair<Integer, String> pair = ImmutablePair.of(0, "foo");
53 assertEquals(0, pair.left.intValue());
54 assertEquals(0, pair.getLeft().intValue());
55 assertEquals("foo", pair.right);
56 assertEquals("foo", pair.getRight());
57 ImmutablePair<Object, String> pair2 = ImmutablePair.of(null, "bar");
58 assertNull(pair2.left);
59 assertNull(pair2.getLeft());
60 assertEquals("bar", pair2.right);
61 assertEquals("bar", pair2.getRight());
62 }
63
64 @Test
65 public void testEquals() throws Exception {
66 assertEquals(ImmutablePair.of(null, "foo"), ImmutablePair.of(null, "foo"));
67 assertFalse(ImmutablePair.of("foo", 0).equals(ImmutablePair.of("foo", null)));
68 assertFalse(ImmutablePair.of("foo", "bar").equals(ImmutablePair.of("xyz", "bar")));
69
70 ImmutablePair<String, String> p = ImmutablePair.of("foo", "bar");
71 assertTrue(p.equals(p));
72 assertFalse(p.equals(new Object()));
73 }
74
75 @Test
76 public void testHashCode() throws Exception {
77 assertEquals(ImmutablePair.of(null, "foo").hashCode(), ImmutablePair.of(null, "foo").hashCode());
78 }
79
80 @Test
81 public void testToString() throws Exception {
82 assertEquals("(null,null)", ImmutablePair.of(null, null).toString());
83 assertEquals("(null,two)", ImmutablePair.of(null, "two").toString());
84 assertEquals("(one,null)", ImmutablePair.of("one", null).toString());
85 assertEquals("(one,two)", ImmutablePair.of("one", "two").toString());
86 }
87
88 @Test
89 @SuppressWarnings("unchecked")
90 public void testSerialization() throws Exception {
91 ImmutablePair<Integer, String> origPair = ImmutablePair.of(0, "foo");
92 ByteArrayOutputStream baos = new ByteArrayOutputStream();
93 ObjectOutputStream out = new ObjectOutputStream(baos);
94 out.writeObject(origPair);
95 ImmutablePair<Integer, String> deserializedPair = (ImmutablePair<Integer, String>) new ObjectInputStream(
96 new ByteArrayInputStream(baos.toByteArray())).readObject();
97 assertEquals(origPair, deserializedPair);
98 assertEquals(origPair.hashCode(), deserializedPair.hashCode());
99 }
100 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.tuple;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertTrue;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.ObjectInputStream;
26 import java.io.ObjectOutputStream;
27
28 import org.junit.Test;
29
30 /**
31 * Test the MutablePair class.
32 * @version $Id: MutablePairTest.java 1124337 2011-05-18 17:01:47Z mbenson $
33 */
34 public class MutablePairTest {
35
36 @Test
37 public void testBasic() throws Exception {
38 MutablePair<Integer, String> pair = new MutablePair<Integer, String>(0, "foo");
39 assertEquals(0, pair.getLeft().intValue());
40 assertEquals("foo", pair.getRight());
41 MutablePair<Object, String> pair2 = new MutablePair<Object, String>(null, "bar");
42 assertNull(pair2.getLeft());
43 assertEquals("bar", pair2.getRight());
44 }
45
46 @Test
47 public void testDefault() throws Exception {
48 MutablePair<Integer, String> pair = new MutablePair<Integer, String>();
49 assertNull(pair.getLeft());
50 assertNull(pair.getRight());
51 }
52
53 @Test
54 public void testMutate() throws Exception {
55 MutablePair<Integer, String> pair = new MutablePair<Integer, String>(0, "foo");
56 pair.setLeft(42);
57 pair.setRight("bar");
58 assertEquals(42, pair.getLeft().intValue());
59 assertEquals("bar", pair.getRight());
60 }
61
62 @Test
63 public void testPairOf() throws Exception {
64 MutablePair<Integer, String> pair = MutablePair.of(0, "foo");
65 assertEquals(0, pair.getLeft().intValue());
66 assertEquals("foo", pair.getRight());
67 MutablePair<Object, String> pair2 = MutablePair.of(null, "bar");
68 assertNull(pair2.getLeft());
69 assertEquals("bar", pair2.getRight());
70 }
71
72 @Test
73 public void testEquals() throws Exception {
74 assertEquals(MutablePair.of(null, "foo"), MutablePair.of(null, "foo"));
75 assertFalse(MutablePair.of("foo", 0).equals(MutablePair.of("foo", null)));
76 assertFalse(MutablePair.of("foo", "bar").equals(MutablePair.of("xyz", "bar")));
77
78 MutablePair<String, String> p = MutablePair.of("foo", "bar");
79 assertTrue(p.equals(p));
80 assertFalse(p.equals(new Object()));
81 }
82
83 @Test
84 public void testHashCode() throws Exception {
85 assertEquals(MutablePair.of(null, "foo").hashCode(), MutablePair.of(null, "foo").hashCode());
86 }
87
88 @Test
89 public void testToString() throws Exception {
90 assertEquals("(null,null)", MutablePair.of(null, null).toString());
91 assertEquals("(null,two)", MutablePair.of(null, "two").toString());
92 assertEquals("(one,null)", MutablePair.of("one", null).toString());
93 assertEquals("(one,two)", MutablePair.of("one", "two").toString());
94 }
95
96 @Test
97 @SuppressWarnings("unchecked")
98 public void testSerialization() throws Exception {
99 MutablePair<Integer, String> origPair = MutablePair.of(0, "foo");
100 ByteArrayOutputStream baos = new ByteArrayOutputStream();
101 ObjectOutputStream out = new ObjectOutputStream(baos);
102 out.writeObject(origPair);
103 MutablePair<Integer, String> deserializedPair = (MutablePair<Integer, String>) new ObjectInputStream(
104 new ByteArrayInputStream(baos.toByteArray())).readObject();
105 assertEquals(origPair, deserializedPair);
106 assertEquals(origPair.hashCode(), deserializedPair.hashCode());
107 }
108 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.commons.lang3.tuple;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertTrue;
22
23 import java.util.Calendar;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Map.Entry;
27
28 import org.junit.Test;
29
30 /**
31 * Test the Pair class.
32 *
33 * @version $Id: PairTest.java 1099414 2011-05-04 11:13:51Z scolebourne $
34 */
35 public class PairTest {
36
37 @Test
38 public void testPairOf() throws Exception {
39 Pair<Integer, String> pair = Pair.of(0, "foo");
40 assertTrue(pair instanceof ImmutablePair<?, ?>);
41 assertEquals(0, ((ImmutablePair<Integer, String>) pair).left.intValue());
42 assertEquals("foo", ((ImmutablePair<Integer, String>) pair).right);
43 Pair<Object, String> pair2 = Pair.of(null, "bar");
44 assertTrue(pair2 instanceof ImmutablePair<?, ?>);
45 assertNull(((ImmutablePair<Object, String>) pair2).left);
46 assertEquals("bar", ((ImmutablePair<Object, String>) pair2).right);
47 }
48
49 @Test
50 public void testCompatibilityBetweenPairs() throws Exception {
51 Pair<Integer, String> pair = ImmutablePair.of(0, "foo");
52 Pair<Integer, String> pair2 = MutablePair.of(0, "foo");
53 assertEquals(pair, pair2);
54 assertEquals(pair.hashCode(), pair2.hashCode());
55 HashSet<Pair<Integer, String>> set = new HashSet<Pair<Integer, String>>();
56 set.add(pair);
57 assertTrue(set.contains(pair2));
58
59 pair2.setValue("bar");
60 assertFalse(pair.equals(pair2));
61 assertFalse(pair.hashCode() == pair2.hashCode());
62 }
63
64 @Test
65 public void testMapEntry() throws Exception {
66 Pair<Integer, String> pair = ImmutablePair.of(0, "foo");
67 HashMap<Integer, String> map = new HashMap<Integer, String>();
68 map.put(0, "foo");
69 Entry<Integer, String> entry = map.entrySet().iterator().next();
70 assertEquals(pair, entry);
71 assertEquals(pair.hashCode(), entry.hashCode());
72 }
73
74 @Test
75 public void testComparable1() throws Exception {
76 Pair<String, String> pair1 = Pair.of("A", "D");
77 Pair<String, String> pair2 = Pair.of("B", "C");
78 assertEquals(true, pair1.compareTo(pair1) == 0);
79 assertEquals(true, pair1.compareTo(pair2) < 0);
80 assertEquals(true, pair2.compareTo(pair2) == 0);
81 assertEquals(true, pair2.compareTo(pair1) > 0);
82 }
83
84 @Test
85 public void testComparable2() throws Exception {
86 Pair<String, String> pair1 = Pair.of("A", "C");
87 Pair<String, String> pair2 = Pair.of("A", "D");
88 assertEquals(true, pair1.compareTo(pair1) == 0);
89 assertEquals(true, pair1.compareTo(pair2) < 0);
90 assertEquals(true, pair2.compareTo(pair2) == 0);
91 assertEquals(true, pair2.compareTo(pair1) > 0);
92 }
93
94 @Test
95 public void testToString() throws Exception {
96 Pair<String, String> pair = Pair.of("Key", "Value");
97 assertEquals("(Key,Value)", pair.toString());
98 }
99
100 @Test
101 public void testToStringCustom() throws Exception {
102 Calendar date = Calendar.getInstance();
103 date.set(2011, Calendar.APRIL, 25);
104 Pair<String, Calendar> pair = Pair.of("DOB", date);
105 assertEquals("Test created on " + "04-25-2011", pair.toString("Test created on %2$tm-%2$td-%2$tY"));
106 }
107
108 @Test
109 public void testFormattable_simple() throws Exception {
110 Pair<String, String> pair = Pair.of("Key", "Value");
111 assertEquals("(Key,Value)", String.format("%1$s", pair));
112 }
113
114 @Test
115 public void testFormattable_padded() throws Exception {
116 Pair<String, String> pair = Pair.of("Key", "Value");
117 assertEquals(" (Key,Value)", String.format("%1$20s", pair));
118 }
119
120 }
0 [{"geonameFeatureClass":"L","values":{"eu":"Mundua","ro":"Pamânt","it":"Globo","ca":"el món","tr":"Yeryüzü","no":"Jorden","hu":"Föld","lv":"Zeme","de":"Welt","el":"Υδρόγειος","fi":"Maa","la":"Terra","fr":"Monde","eo":"Mondo","en":"World","ru":"Земля","es":"el planeta","nl":"Aarde"},"geonameFeatureCode":"AREA","_id":32,"name":"","auto":true,"type":"GEO","geonameId":6295630,"valueCode":""},{"geonameFeatureClass":"L","values":{"ro":"Europa","zh":"欧洲","ca":"Europa","vi":"Châu Âu","tr":"Avrupa","no":"Europa","hu":"Európa","lv":"Eiropa","hi":"यूरोप","lt":"Europa","bs":"Evropa","ga":"an Eoraip","th":"ยุโรป","id":"Eropa","de":"Europa","fi":"Eurooppa","fr":"Europe","sv":"Europa","bg":"Европа","da":"Europa","eu":"Europa","is":"Evrópa","it":"Europa","cy":"Ewrop","ar":"أوروبا","se":"Eurohpá","he":"אירופה","cs":"Evropa","el":"Ευρώπη","nb":"Europa","pl":"Europa","la":"Europa","pt":"Europa","eo":"Eŭropo","en":"Europe","ru":"Европа","es":"Europa","ja":"ヨーロッパ","nl":"Europa"},"geonameFeatureCode":"CONT","_id":33,"name":"","auto":true,"type":"GEO","geonameId":6255148,"valueCode":""},{"geonameFeatureClass":"A","values":{"no":"Spania","nn":"Spania","fy":"Spanje","gd":"An Spàinn","ga":"An Spáinn","oc":"Espanha","arc":"ܐܣܦܢܝܐ","fi":"Espanja","fr":"Espagne","fo":"Spania","udm":"Испания","os":"Испани","he":"ספרד","gn":"Epaña","gl":"España","gv":"Yn Spaainey","pl":"Hiszpania","gu":"સ્પેઇન","lo":"ສະເປນ","ln":"Espania","vi":"Tây Ban Nha","dz":"Spain","pms":"Spagna","lv":"Spānija","lt":"Ispanija","vo":"Spanyän","de":"Spanien","mg":"Espaina","fur":"Spagne","mk":"Шпанија","ml":"സ്പെയ്ന്\u200D","ceb":"Espanya","mi":"Pāniora","uk":"Іспанія","eu":"Espainia","mr":"स्पेन","ug":"ئىسپانىيە","mt":"Spanja","ms":"Sepanyol","ur":"سپین","fa":"اسپانیا","ty":"Paniora","new":"स्पेन","na":"Pain","el":"Ισπανία","nb":"Spania","ne":"स्पेन","vls":"Spanje","eo":"Hispanio","en":"Kingdom of Spain","et":"Hispaania","es":"la Madre Patria","nl":"Spanje","vec":"Spagna","to":"Sepeni","ca":"Espanya","tl":"Espanya","tr":"İspanya","tg":"Испониё","haw":"Sepania","bs":"Španija","br":"Spagn","th":"ประเทศสเปน","bn":"স্পেন","bo":"སི་པན།","ta":"ஸ்பெயின்","sv":"Spanien","bg":"Испания","ka":"ესპანეთი","st":"Spain","sw":"Hispania","be":"Іспанія","kw":"Spayn","sl":"Španija","sk":"Španielsko","da":"Spanien","ang":"Spēonland","nds":"Spanien","ks":"Spēna","so":"Isbeyn","ku":"Spanya","sr":"Шпанија","sq":"Spanja","ko":"에스파냐","sc":"Ispagna","cy":"Sbaen","se":"Espánjja","sh":"Španija","cv":"Испани","km":"អេស្ប៉ាញ","cs":"Španělsko","li":"Spanje","co":"Spagna","default":"Spain","jbo":"sangu'e","la":"Hesperia","ru":"Испания","lb":"Spuenien","sco":"Spain","tet":"España","scn":"Spagna","hr":"Španjolska","zh":"西班牙","ro":"Spania","rm":"Spagna","ht":"Espay","hu":"Spanyolország","ast":"España","hi":"स्पेन","hsb":"Španiska","nah":"Caxtillān","war":"Espanya","lad":"Espanya","id":"Spanyol","ia":"Espania","nrm":"Espangne","hy":"Իսպանիա","qu":"Ispaña","ilo":"Espania","az":"İspaniya","is":"Spánn","it":"Spagna","tpi":"Spen","ar":"أسبانيا","io":"Hispania","pam":"Espanya","frp":"Èspagne","am":"እስፓንያ","an":"España","csb":"Szpańskô","pt":"Espanha","ja":"スペイン","ps":"اسپانيا","yi":"שפאניע","af":"Spanje"},"geonameFeatureCode":"PCLI","_id":260,"name":"","auto":true,"type":"GEO","geonameId":2510769,"valueCode":""},{"geonameFeatureClass":"A","values":{"ca":"Andalusia","tr":"Endülüs","krc":"Андалусия","no":"Andalucía","fy":"Andalûsje","bs":"Andaluzija","br":"Andalouzia","ext":"Andaluzia","ga":"An Andalúis","th":"แคว้นอันดาลูซีอา","bn":"আন্দালুসিয়া","oc":"Andalosia","ka":"ანდალუსია","sv":"Andalusien","fr":"Andalousie","bg":"Андалусия","glk":"آندالوسیا","be":"Андалусія","kw":"Andalousi","sk":"Andalúzia","os":"Андалуси","da":"Andalusien","sr":"Андалузија","ku":"Endulus","ko":"안달루시아 지방","he":"אנדלוסיה","sh":"Andaluzija","arz":"اندلوسيا","cs":"Andalusie","default":"Andalusia","stq":"Andalusien","la":"Vandalitia","pl":"Andaluzja","ru":"Андалусия","lb":"Andalusien","tet":"Andaluzia","got":"𐍅𐌰𐌽𐌳𐌰𐌻𐌹𐍄𐌾𐌰","hr":"Andaluzija","zh":"安達魯西亞","ro":"Andaluzia","hu":"Andalúzia","pms":"Andalusìa","lv":"Andalūzija","lt":"Andalūzija","nah":"Andalucia","lad":"Andaluziya","de":"Andalusien","als":"Andalusien","qu":"Andalusiya","hy":"Անդալուզիա","eu":"Andaluzia","is":"Andalúsía","uk":"Андалусія","az":"Andalusiya","mr":"आंदालुसिया","ug":"Andalusiye","fa":"اندلس","ar":"أندلوسيا","rmy":"Andalusiya","io":"Andaluzia","el":"Ανδαλουσία","frp":"Andalosie","pt":"Andaluzia","eo":"Andaluzio","en":"Andalusia","et":"Andaluusia","es":"Andalucía","ja":"アンダルシア州","nl":"Andalusië","af":"Andalusië","vec":"Andalusìa"},"geonameFeatureCode":"ADM1","_id":261,"name":"","auto":true,"type":"GEO","geonameId":2593109,"valueCode":""},{"geonameFeatureClass":"A","values":{"de":"Granada","default":"Province of Granada","fr":"Grenade","en":"Province of Granada","es":"Provincia de Granada","ja":"グラナダ"},"geonameFeatureCode":"ADM2","_id":262,"name":"","auto":true,"type":"GEO","geonameId":2517115,"valueCode":""},{"geonameFeatureClass":"A","values":{"default":"Monachil"},"geonameFeatureCode":"ADM3","_id":263,"name":"","auto":true,"type":"GEO","geonameId":6357744,"valueCode":""},{"geonameFeatureClass":"P","values":{"default":"Sierra Nevada"},"geonameFeatureCode":"PPL","_id":264,"name":"","auto":true,"type":"GEO","geonameId":6544329,"valueCode":""}]