PageRenderTime 39ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/spring-beans/src/main/java/org/springframework/beans/PropertyAccessorUtils.java

https://gitlab.com/zouxc/spring-framework
Java | 185 lines | 99 code | 12 blank | 74 comment | 32 complexity | 8744f5a9cf3e9c200e954bfe8f04e4b5 MD5 | raw file
  1. /*
  2. * Copyright 2002-2012 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * 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.springframework.beans;
  17. /**
  18. * Utility methods for classes that perform bean property access
  19. * according to the {@link PropertyAccessor} interface.
  20. *
  21. * @author Juergen Hoeller
  22. * @since 1.2.6
  23. */
  24. public abstract class PropertyAccessorUtils {
  25. /**
  26. * Return the actual property name for the given property path.
  27. * @param propertyPath the property path to determine the property name
  28. * for (can include property keys, for example for specifying a map entry)
  29. * @return the actual property name, without any key elements
  30. */
  31. public static String getPropertyName(String propertyPath) {
  32. int separatorIndex = (propertyPath.endsWith(PropertyAccessor.PROPERTY_KEY_SUFFIX) ?
  33. propertyPath.indexOf(PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR) : -1);
  34. return (separatorIndex != -1 ? propertyPath.substring(0, separatorIndex) : propertyPath);
  35. }
  36. /**
  37. * Check whether the given property path indicates an indexed or nested property.
  38. * @param propertyPath the property path to check
  39. * @return whether the path indicates an indexed or nested property
  40. */
  41. public static boolean isNestedOrIndexedProperty(String propertyPath) {
  42. if (propertyPath == null) {
  43. return false;
  44. }
  45. for (int i = 0; i < propertyPath.length(); i++) {
  46. char ch = propertyPath.charAt(i);
  47. if (ch == PropertyAccessor.NESTED_PROPERTY_SEPARATOR_CHAR ||
  48. ch == PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR) {
  49. return true;
  50. }
  51. }
  52. return false;
  53. }
  54. /**
  55. * Determine the first nested property separator in the
  56. * given property path, ignoring dots in keys (like "map[my.key]").
  57. * @param propertyPath the property path to check
  58. * @return the index of the nested property separator, or -1 if none
  59. */
  60. public static int getFirstNestedPropertySeparatorIndex(String propertyPath) {
  61. return getNestedPropertySeparatorIndex(propertyPath, false);
  62. }
  63. /**
  64. * Determine the first nested property separator in the
  65. * given property path, ignoring dots in keys (like "map[my.key]").
  66. * @param propertyPath the property path to check
  67. * @return the index of the nested property separator, or -1 if none
  68. */
  69. public static int getLastNestedPropertySeparatorIndex(String propertyPath) {
  70. return getNestedPropertySeparatorIndex(propertyPath, true);
  71. }
  72. /**
  73. * Determine the first (or last) nested property separator in the
  74. * given property path, ignoring dots in keys (like "map[my.key]").
  75. * @param propertyPath the property path to check
  76. * @param last whether to return the last separator rather than the first
  77. * @return the index of the nested property separator, or -1 if none
  78. */
  79. private static int getNestedPropertySeparatorIndex(String propertyPath, boolean last) {
  80. boolean inKey = false;
  81. int length = propertyPath.length();
  82. int i = (last ? length - 1 : 0);
  83. while (last ? i >= 0 : i < length) {
  84. switch (propertyPath.charAt(i)) {
  85. case PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR:
  86. case PropertyAccessor.PROPERTY_KEY_SUFFIX_CHAR:
  87. inKey = !inKey;
  88. break;
  89. case PropertyAccessor.NESTED_PROPERTY_SEPARATOR_CHAR:
  90. if (!inKey) {
  91. return i;
  92. }
  93. }
  94. if (last) {
  95. i--;
  96. }
  97. else {
  98. i++;
  99. }
  100. }
  101. return -1;
  102. }
  103. /**
  104. * Determine whether the given registered path matches the given property path,
  105. * either indicating the property itself or an indexed element of the property.
  106. * @param propertyPath the property path (typically without index)
  107. * @param registeredPath the registered path (potentially with index)
  108. * @return whether the paths match
  109. */
  110. public static boolean matchesProperty(String registeredPath, String propertyPath) {
  111. if (!registeredPath.startsWith(propertyPath)) {
  112. return false;
  113. }
  114. if (registeredPath.length() == propertyPath.length()) {
  115. return true;
  116. }
  117. if (registeredPath.charAt(propertyPath.length()) != PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR) {
  118. return false;
  119. }
  120. return (registeredPath.indexOf(PropertyAccessor.PROPERTY_KEY_SUFFIX_CHAR, propertyPath.length() + 1) ==
  121. registeredPath.length() - 1);
  122. }
  123. /**
  124. * Determine the canonical name for the given property path.
  125. * Removes surrounding quotes from map keys:<br>
  126. * {@code map['key']} -> {@code map[key]}<br>
  127. * {@code map["key"]} -> {@code map[key]}
  128. * @param propertyName the bean property path
  129. * @return the canonical representation of the property path
  130. */
  131. public static String canonicalPropertyName(String propertyName) {
  132. if (propertyName == null) {
  133. return "";
  134. }
  135. StringBuilder sb = new StringBuilder(propertyName);
  136. int searchIndex = 0;
  137. while (searchIndex != -1) {
  138. int keyStart = sb.indexOf(PropertyAccessor.PROPERTY_KEY_PREFIX, searchIndex);
  139. searchIndex = -1;
  140. if (keyStart != -1) {
  141. int keyEnd = sb.indexOf(
  142. PropertyAccessor.PROPERTY_KEY_SUFFIX, keyStart + PropertyAccessor.PROPERTY_KEY_PREFIX.length());
  143. if (keyEnd != -1) {
  144. String key = sb.substring(keyStart + PropertyAccessor.PROPERTY_KEY_PREFIX.length(), keyEnd);
  145. if ((key.startsWith("'") && key.endsWith("'")) || (key.startsWith("\"") && key.endsWith("\""))) {
  146. sb.delete(keyStart + 1, keyStart + 2);
  147. sb.delete(keyEnd - 2, keyEnd - 1);
  148. keyEnd = keyEnd - 2;
  149. }
  150. searchIndex = keyEnd + PropertyAccessor.PROPERTY_KEY_SUFFIX.length();
  151. }
  152. }
  153. }
  154. return sb.toString();
  155. }
  156. /**
  157. * Determine the canonical names for the given property paths.
  158. * @param propertyNames the bean property paths (as array)
  159. * @return the canonical representation of the property paths
  160. * (as array of the same size)
  161. * @see #canonicalPropertyName(String)
  162. */
  163. public static String[] canonicalPropertyNames(String[] propertyNames) {
  164. if (propertyNames == null) {
  165. return null;
  166. }
  167. String[] result = new String[propertyNames.length];
  168. for (int i = 0; i < propertyNames.length; i++) {
  169. result[i] = canonicalPropertyName(propertyNames[i]);
  170. }
  171. return result;
  172. }
  173. }