001 /*
002 * SPDX-License-Identifier: Apache-2.0
003 *
004 * Copyright 2006-2020 the original author or authors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.kordamp.json.util;
019
020 import org.apache.commons.lang3.StringUtils;
021 import org.kordamp.json.JSONException;
022
023 /**
024 * Transforms a string into a valid Java identifier.<br>
025 * There are five predefined strategies:
026 * <ul>
027 * <li>NOOP: does not perform transformation.</li>
028 * <li>CAMEL_CASE: follows the camel case convention, deletes non
029 * JavaIndentifierPart chars.</li>
030 * <li>UNDERSCORE: transform whitespace and non JavaIdentifierPart chars to
031 * '_'.</li>
032 * <li>WHITESPACE: deletes whitespace and non JavaIdentifierPart chars.</li>
033 * <li>STRICT: always throws a JSONException, does not perform transformation.</li>
034 * </ul>
035 *
036 * @author Andres Almiray
037 */
038 public abstract class JavaIdentifierTransformer {
039 /**
040 * CamelCase transformer 'camel case' => 'camelCase'
041 */
042 public static final JavaIdentifierTransformer CAMEL_CASE = new CamelCaseJavaIdentifierTransformer();
043 /**
044 * Noop transformer '@invalid' => '@invalid'
045 */
046 public static final JavaIdentifierTransformer NOOP = new NoopJavaIdentifierTransformer();
047 /**
048 * Strict transformer '@invalid' => JSONException
049 */
050 public static final JavaIdentifierTransformer STRICT = new StrictJavaIdentifierTransformer();
051 /**
052 * Underscore transformer 'under score' => 'under_score'
053 */
054 public static final JavaIdentifierTransformer UNDERSCORE = new UnderscoreJavaIdentifierTransformer();
055 /**
056 * Whitespace transformer 'white space' => 'whitespace'
057 */
058 public static final JavaIdentifierTransformer WHITESPACE = new WhiteSpaceJavaIdentifierTransformer();
059
060 public abstract String transformToJavaIdentifier(String str);
061
062 /**
063 * Removes all non JavaIdentifier chars from the start of the string.
064 *
065 * @throws JSONException if the resulting string has zero length.
066 */
067 protected final String shaveOffNonJavaIdentifierStartChars(String str) {
068 String str2 = str;
069 // shave off first char if not valid
070 boolean ready = false;
071 while (!ready) {
072 if (!Character.isJavaIdentifierStart(str2.charAt(0))) {
073 str2 = str2.substring(1);
074 if (str2.length() == 0) {
075 throw new JSONException("Can't convert '" + str + "' to a valid Java identifier");
076 }
077 } else {
078 ready = true;
079 }
080 }
081 return str2;
082 }
083
084 private static final class CamelCaseJavaIdentifierTransformer extends JavaIdentifierTransformer {
085 public String transformToJavaIdentifier(String str) {
086 if (str == null) {
087 return null;
088 }
089
090 String str2 = shaveOffNonJavaIdentifierStartChars(str);
091
092 char[] chars = str2.toCharArray();
093 int pos = 0;
094 StringBuffer buf = new StringBuffer();
095 boolean toUpperCaseNextChar = false;
096 while (pos < chars.length) {
097 if (!Character.isJavaIdentifierPart(chars[pos])
098 || Character.isWhitespace(chars[pos])) {
099 toUpperCaseNextChar = true;
100 } else {
101 if (toUpperCaseNextChar) {
102 buf.append(Character.toUpperCase(chars[pos]));
103 toUpperCaseNextChar = false;
104 } else {
105 buf.append(chars[pos]);
106 }
107 }
108 pos++;
109 }
110 return buf.toString();
111 }
112 }
113
114 private static final class NoopJavaIdentifierTransformer extends JavaIdentifierTransformer {
115 public String transformToJavaIdentifier(String str) {
116 return str;
117 }
118 }
119
120 private static final class StrictJavaIdentifierTransformer extends JavaIdentifierTransformer {
121 public String transformToJavaIdentifier(String str) {
122 throw new JSONException("'" + str + "' is not a valid Java identifier.");
123 }
124 }
125
126 private static final class UnderscoreJavaIdentifierTransformer extends JavaIdentifierTransformer {
127 public String transformToJavaIdentifier(String str) {
128 if (str == null) {
129 return null;
130 }
131 String str2 = shaveOffNonJavaIdentifierStartChars(str);
132
133 char[] chars = str2.toCharArray();
134 int pos = 0;
135 StringBuffer buf = new StringBuffer();
136 boolean toUnderScorePreviousChar = false;
137 while (pos < chars.length) {
138 if (!Character.isJavaIdentifierPart(chars[pos])
139 || Character.isWhitespace(chars[pos])) {
140 toUnderScorePreviousChar = true;
141 } else {
142 if (toUnderScorePreviousChar) {
143 buf.append("_");
144 toUnderScorePreviousChar = false;
145 }
146 buf.append(chars[pos]);
147 }
148 pos++;
149 }
150 if (buf.charAt(buf.length() - 1) == '_') {
151 buf.deleteCharAt(buf.length() - 1);
152 }
153 return buf.toString();
154 }
155 }
156
157 private static final class WhiteSpaceJavaIdentifierTransformer extends JavaIdentifierTransformer {
158 public String transformToJavaIdentifier(String str) {
159 if (str == null) {
160 return null;
161 }
162 String str2 = shaveOffNonJavaIdentifierStartChars(str);
163 str2 = StringUtils.deleteWhitespace(str2);
164 char[] chars = str2.toCharArray();
165 int pos = 0;
166 StringBuffer buf = new StringBuffer();
167 while (pos < chars.length) {
168 if (Character.isJavaIdentifierPart(chars[pos])) {
169 buf.append(chars[pos]);
170 }
171 pos++;
172 }
173 return buf.toString();
174 }
175 }
176 }
|