Java tutorial
/* * Copyright (c) 2007 NTT DATA Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jp.terasoluna.fw.beans; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import jp.terasoluna.fw.beans.jxpath.BeanPointerFactoryEx; import jp.terasoluna.fw.beans.jxpath.DynamicPointerFactoryEx; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.JXPathException; import org.apache.commons.jxpath.Pointer; import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * JXPath??IndexBeanWrapper? * <p> * JavaBean?Map?DynaBean???????? ???????? ??List??????? * <h5>?????</h5> * <ul> * <li></li> * <li>??</li> * <li>JavaBean</li> * <li>JavaBean??List</li> * <li>Map</li> * </ul> * </p> * <p> * Map????Map??? ??Map?????? * <ul> * <li>/ </li> * <li>[ ?????</li> * <li>] ????</li> * <li>. </li> * <li>' </li> * <li>" </li> * <li>( ?????</li> * <li>) ????</li> * </ul> * </p> * <hr> * <h4>??</h4> * <p> * ???Employee?firstName?? * * <pre> * public class Employee { * private String firstName; * * public void setFirstName(String firstName) { * this.firstName = firstName; * } * * public String getFirstName() { * return firstName; * } * } * </pre> * </p> * <p> * <u>??JavaBean?</u> * * <pre> * // ??Employee * Employee emp = new Employee(); * emp.setFirstName("??"); * * IndexedBeanWrapper bw = new JXPathIndexedBeanWrapperImpl(emp); * </pre> * </p> * <p> * <u>firstName??</u> ?String????? * * <pre> * Map<String, Object> map = bw.getIndexedPropertyValues( * "<strong>firstName</strong>"); * </pre> * * ??????Map?? ?????????? * * <pre> * System.out.println("Map?Map?"); * System.out.println("========================"); * Set<String> keyset = map.keySet(); * for (String key : keyset) { * System.out.print(key + ":"); * System.out.println(map.get(key).toString()); * } * </pre> * * ?????? * * <pre> * Map?Map? * ======================== * firstName:?? * </pre> * </p> * <hr> * <h4>???</h4> * <p> * ???Address??numbers?? * * <pre> * public class Address { * private int[] numbers; * * public void setNumbers(int[] numbers) { * this.numbers = numbers; * } * * public int[] getNumbers() { * return numbers; * } * } * </pre> * </p> * <p> * <u>??JavaBean?</u> * * <pre> * // Employee???Address * Address address = new Address(); * address.setNumbers(new int[] { 1, 2, 3 }); * * IndexedBeanWrapper bw = new JXPathIndexedBeanWrapperImpl(address); * </pre> * </p> * <p> * <u>numbers??</u> <em>'numbers[]'???????????? * ????????????</em> * * <pre> * Map<String, Object> map = bw.getIndexedPropertyValues( * "<strong>numbers</strong>"); * </pre> * </p> * ??????Map?? ?????????? * * <pre> * System.out.println("Map?Map?"); * System.out.println("========================"); * Set<String> keyset = map.keySet(); * for (String key : keyset) { * System.out.print(key + ":"); * System.out.println(map.get(key).toString()); * } * </pre> * * ?????? * * <pre> * Map?Map? * ======================== * numbers[0]:1 * numbers[1]:2 * numbers[2]:3 * </pre> * * List????????????? * </p> * <hr> * <h4>?????</h4> * <p> * ???Employee?? ???Address?streetNumber?? * * <pre> * public class Employee { * private Address homeAddress; * * public void setHomeAddress(Address homeAddress) { * this.homeAddress = homeAddress; * } * * public Address getHomeAddress() { * return homeAddress; * } * } * * public class Address { * private String streetNumber; * * public void setStreetNumber(String streetNumber) { * this.streetNumber = streetNumber; * } * * public String getStreetNumber() { * return streetNumber; * } * } * </pre> * </p> * <p> * <u>??JavaBean?</u> * * <pre> * // Employee???Address * Address address = new Address(); * address.setStreetNumber("?"); * * // Employee * Employee emp = new Employee(); * emp.setHomeAddress(address); * * IndexedBeanWrapper bw = new JXPathIndexedBeanWrapperImpl(emp); * </pre> * </p> * <p> * <u>Employee?homeAddress????? streetNumber??</u> ??????????'.'? ???? * * <pre> * Map<String, Object> map = bw.getIndexedPropertyValues( * "<strong>homeAddress.streetNumber</strong>"); * </pre> * </p> * ??????Map?? ?????????? * * <pre> * System.out.println("Map?Map?"); * System.out.println("========================"); * Set<String> keyset = map.keySet(); * for (String key : keyset) { * System.out.print(key + ":"); * System.out.println(map.get(key).toString()); * } * </pre> * * ?????? * * <pre> * Map?Map? * ======================== * homeAddress.streetNumber:? * </pre> * * ?????List????????????? * </p> * <hr> * <h4>Map??</h4> * <p> * ???Employee?MapaddressMap?? * * <pre> * public class Employee { * private Map addressMap; * * public void setAddressMap(Map addressMap) { * this.addressMap = addressMap; * } * * public Map getAddressMap() { * return addressMap; * } * } * </pre> * </p> * <p> * <u>??JavaBean?</u> * * <pre> * // Employee???Map * Map addressMap = new HashMap(); * addressMap.put("home", "address1"); * * // Employee * Employee emp = new Employee(); * emp.setAddressMap(addressMap); * * IndexedBeanWrapper bw = new JXPathIndexedBeanWrapperImpl(emp); * </pre> * </p> * <p> * <u>Employee?addressMap???home??</u> Map???????????????? * * <pre> * Map<String, Object> map = bw.getIndexedPropertyValues( * "<strong>addressMap(home)</strong>"); * </pre> * </p> * ??????Map?? ?????????? * * <pre> * System.out.println("Map?Map?"); * System.out.println("========================"); * Set<String> keyset = map.keySet(); * for (String key : keyset) { * System.out.print(key + ":"); * System.out.println(map.get(key).toString()); * } * </pre> * * ?????? * * <pre> * Map?Map? * ======================== * addressMap(home):address1 * </pre> * * Map????()????????? * </p> * <hr> * <h4>Map??</h4> * <p> * ?JavaBean????????Map?????? * <p> * <u>??Map?</u> * * <pre> * // Employee???Map * Map addressMap = new HashMap(); * addressMap.put("home", "address1"); * * IndexedBeanWrapper bw = new JXPathIndexedBeanWrapperImpl(addressMap); * </pre> * </p> * <p> * <u>addressMap???home??</u> * * <pre> * Map<String, Object> map = bw.getIndexedPropertyValues( * "<strong>home</strong>"); * </pre> * </p> * ??????Map?? ?????????? * * <pre> * System.out.println("Map?Map?"); * System.out.println("========================"); * Set<String> keyset = map.keySet(); * for (String key : keyset) { * System.out.print(key + ":"); * System.out.println(map.get(key).toString()); * } * </pre> * * ?????? * * <pre> * Map?Map? * ======================== * home:address1 * </pre> * * Map?????List? ????????? * </p> * <hr> * <h4>DynaBean??</h4> * <p> * ?JavaBean????????DynaBean?????? * <p> * <u>??DynaBean?</u> * * <pre> * // DynaBean??JavaBean * Address address = new Address(); * address.setStreetNumber("?"); * * // DynaBean * DynaBean dynaBean = new WrapDynaBean(address); * * IndexedBeanWrapper bw = new JXPathIndexedBeanWrapperImpl(dynaBean); * * -------------------------------------------------------- * ?????Address?????? * * public class Address { * private String streetNumber; * * public void setStreetNumber(String streetNumber) { * this.streetNumber = streetNumber; * } * public String getStreetNumber() { * return streetNumber; * } * } * </pre> * </p> * <p> * <u>DynaBean?streetNumber??</u> * * <pre> * Map<String, Object> map = bw.getIndexedPropertyValues( * "<strong>streetNumber</strong>"); * </pre> * </p> * ??????Map?? ?????????? * * <pre> * System.out.println("Map?Map?"); * System.out.println("========================"); * Set<String> keyset = map.keySet(); * for (String key : keyset) { * System.out.print(key + ":"); * System.out.println(map.get(key).toString()); * } * </pre> * * ?????? * * <pre> * Map?Map? * ======================== * streetNumber:? * </pre> * </p> */ public class JXPathIndexedBeanWrapperImpl implements IndexedBeanWrapper { /** * */ private static Log log = LogFactory.getLog(JXPathIndexedBeanWrapperImpl.class); /** * JXPath */ protected JXPathContext context = null; /** * ?? * <p> * ??NodePointer? NodePointer?static?????? ?NodePointer???? * ???NullPointerException????? * </p> */ static { JXPathContextReferenceImpl.addNodePointerFactory(new BeanPointerFactoryEx()); JXPathContextReferenceImpl.addNodePointerFactory(new DynamicPointerFactoryEx()); } /** * * @param target ? */ public JXPathIndexedBeanWrapperImpl(Object target) { // ??JavaBean?Null??? if (target == null) { log.error("TargetBean is null!"); throw new IllegalArgumentException("TargetBean is null!"); } context = JXPathContext.newContext(target); } /** * ??????? * @param propertyName ?? * @return ??????Map?? */ @Override public Map<String, Object> getIndexedPropertyValues(String propertyName) { // ???Null if (StringUtils.isEmpty(propertyName)) { String message = "PropertyName is empty!"; log.error(message); throw new IllegalArgumentException(message); } // ????? if (StringUtils.indexOfAny(propertyName, new char[] { '/', '"', '\'' }) != -1) { String message = "Invalid character has found within property name." + " '" + propertyName + "' " + "Cannot use [ / \" ' ]"; log.error(message); throw new IllegalArgumentException(message); } // ??[]?[]???? String stringIndex = extractIndex(propertyName); if (stringIndex.length() > 0) { try { Integer.parseInt(stringIndex); } catch (NumberFormatException e) { String message = "Invalid character has found within property name." + " '" + propertyName + "' " + "Cannot use [ [] ]"; log.error(message); throw new IllegalArgumentException(message); } } Map<String, Object> result = new LinkedHashMap<String, Object>(); String requestXpath = toXPath(propertyName); // JXPath?? Iterator<?> ite = null; try { ite = context.iteratePointers(requestXpath); } catch (JXPathException e) { // ???? String message = "Invalid property name. " + "PropertyName: '" + propertyName + "'" + "XPath: '" + requestXpath + "'"; log.error(message, e); throw new IllegalArgumentException(message, e); } // XPath Java property while (ite.hasNext()) { Pointer p = (Pointer) ite.next(); result.put(this.toPropertyName(p.asPath()), p.getValue()); } return result; } /** * ??XPath????? * @param propertyName ? * @return XPath? */ protected String toXPath(String propertyName) { StringBuilder builder = new StringBuilder("/"); String[] properties = StringUtils.split(propertyName, '.'); if (properties == null || properties.length == 0) { String message = "Property name is null or blank."; log.error(message); throw new IllegalArgumentException(message); } for (String property : properties) { // ? if (builder.length() > 1) { builder.append('/'); } // Map if (isMapProperty(property)) { builder.append(escapeMapProperty(property)); // JavaBean ??? Primitive } else { builder.append(extractAttributeName(property)); } // ? builder.append(extractIncrementIndex(property)); } return builder.toString(); } /** * ????? * @param property Java?? * @return String XPath??? */ protected String extractIncrementIndex(String property) { return extractIncrementIndex(property, 1); } /** * ????? * @param property ?? * @param increment ? * @return String ??? */ protected String extractIncrementIndex(String property, int increment) { String stringIndex = extractIndex(property); if ("".equals(stringIndex)) { return ""; } // ?????????? try { int index = Integer.parseInt(stringIndex); return new StringBuilder().append('[').append(index + increment).append(']').toString(); } catch (NumberFormatException e) { // ??[]???? return ""; } } /** * ??? * @param property ?? * @return ? */ protected String extractIndex(String property) { int start = property.lastIndexOf('['); int end = property.lastIndexOf(']'); // []?????????? if (start == -1 && end == -1) { return ""; } // ']aaa[' ???[]????????[]???????? if (start == -1 || end == -1 || start > end) { String message = "Cannot get Index. " + "Invalid property name. '" + property + "'"; log.error(message); throw new IllegalArgumentException(message); } return property.substring(start + 1, end); } /** * MapXPath??? * @param property Java?? * @return String XPath */ protected String escapeMapProperty(String property) { // aaa(bbb) aaa/bbb String mapPropertyName = extractMapPropertyName(property); String mapKey = extractMapPropertyKey(property); return mapPropertyName + "/" + mapKey; } /** * Map????? * @param property Java?? * @return String XPath */ protected String extractMapPropertyName(String property) { int pos = property.indexOf('('); // '('????? if (pos == -1) { String message = "Cannot get Map attribute. " + "Invalid property name. '" + property + "'"; log.error(message); throw new IllegalArgumentException(message); } return property.substring(0, pos); } /** * Map????? * @param property Java?? * @return String XPath */ protected String extractMapPropertyKey(String property) { // aaa(bbb) bbb int start = property.indexOf('('); int end = property.indexOf(')'); // '()'???????()??????? if (start == -1 || end == -1 || start > end) { String message = "Cannot get Map key. " + "Invalid property name. '" + property + "'"; log.error(message); throw new IllegalArgumentException(message); } return property.substring(start + 1, end); } /** * Map????? * @param property Java?? * @return boolean Map??true????false? */ protected boolean isMapProperty(String property) { // '()'???Map if (property.indexOf('(') != -1 && property.indexOf(')') != -1) { return true; } return false; } /** * XPath??????? * @param xpath XPath? * @return ? */ protected String toPropertyName(String xpath) { StringBuilder builder = new StringBuilder(""); String[] nodes = StringUtils.split(xpath, '/'); if (nodes == null || nodes.length == 0) { String message = "XPath is null or blank."; log.error(message); throw new IllegalArgumentException(message); } for (int i = 0; i < nodes.length; i++) { String node = nodes[i]; // Map if (i == 0 && isMapObject(node)) { builder.append(extractMapKey(node)); builder.append(extractDecrementIndex(node)); continue; } // ? if (builder.length() > 0) { builder.append('.'); } // Map if (isMapAttribute(node)) { builder.append(extractMapAttributeName(node)); builder.append('('); builder.append(extractMapKey(node)); builder.append(')'); // JavaBean ??? primitive } else { builder.append(extractAttributeName(node)); } // ? builder.append(extractDecrementIndex(node)); } return builder.toString(); } /** * ???? ??????? * @param node XPath? * @return ?? */ protected String extractAttributeName(String node) { int pos = node.lastIndexOf('['); if (pos == -1) { return node; } // ???? return node.substring(0, pos); } /** * Map????? * @param node XPath? * @return ?? */ protected String extractMapAttributeName(String node) { // ??'['???Map????? int pos = node.indexOf('['); // '['????? if (pos == -1) { String message = "Cannot get Map attribute. " + "Invalid property name. '" + node + "'"; log.error(message); throw new IllegalArgumentException(message); } return node.substring(0, pos); } /** * Map?? * @param node XPath? * @return ?? */ protected String extractMapKey(String node) { // aaa[@name='bbb'] bbb int start = node.indexOf('['); int end = node.indexOf(']'); // '[]'???????[]??????? if (start == -1 || end == -1 || start > end) { String message = "Cannot get Map key. " + "Invalid property name. '" + node + "'"; log.error(message); throw new IllegalArgumentException(message); } return node.substring(start + "[@name='".length(), end - "'".length()); } /** * ????? * @param node XPath? * @return ?? */ protected String extractDecrementIndex(String node) { return extractIncrementIndex(node, -1); } /** * Map??????? * @param node XPath? * @return Map??true????false? */ protected boolean isMapAttribute(String node) { // '[@name'???Map if (node.indexOf("[@name") != -1) { return true; } return false; } /** * Map????? * @param node XPath? * @return Map??true????false? */ protected boolean isMapObject(String node) { // '.[@name'????Map if (node.startsWith(".[@name")) { return true; } return false; } }