/* * Copyright (c) 2007, Dennis M. Sosnoski All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following * disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of * JiBX nor the names of its contributors may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jibx.binding.generator; import org.jibx.binding.classes.ClassItem; import org.jibx.binding.util.StringArray; import org.jibx.runtime.EnumSet; import org.jibx.runtime.IUnmarshallingContext; /** * Member field or property customization information. * * @author Dennis M. Sosnoski */ public abstract class MemberCustom extends CustomBase { /** Enumeration of allowed attribute names */ public static final StringArray s_allowedAttributes = new StringArray(new String[] { "actual-type", "attribute", "create-type", "element", "factory", "required" }); // values specific to member level private String m_baseName; // internal use, not included in binding private String m_statedType; // internal use, not included in binding private String m_workingType; // internal use, not included in binding private boolean m_isPrimitive; // internal use, not included in binding private Integer m_style; // internal use, not included in binding private String m_xmlName; private String m_actualType; private String m_createType; private String m_factoryMethod; private Boolean m_required; /** * Constructor. * * @param parent */ protected MemberCustom(SharedNestingBase parent) { super(parent); } /** * Constructor with name known. * * @param parent * @param name */ protected MemberCustom(SharedNestingBase parent, String name) { this(parent); m_baseName = name; } /** * Get member (field or property) name. In the case of a field, this is the name with any prefix or suffix stripped; * in the case of a property, it's the property name. For both field and property names, the initial letter is * converted to lowercase unless the second letter is lowercase. * * @return name */ public String getBaseName() { return m_baseName; } /** * Set member (field or property) name. This is only for use by subclasses. * * @param name */ protected void setBaseName(String name) { m_baseName = name; } /** * Get stated type of member. * * @return stated type */ public String getStatedType() { return m_statedType; } /** * Get working type of member. * * @return working type */ public String getWorkingType() { return m_workingType; } /** * Convert case of member name derived from method or field name. If the supplied name starts with an uppercase * letter followed by a lowercase letter, the initial letter is converted to lowercase in order to obtain a standard * form of the name. * * @param name * @return converted name */ public static String convertMemberNameCase(String name) { if (name.length() > 0) { char lead = name.charAt(0); if (name.length() > 1) { if (Character.isUpperCase(lead) && Character.isLowerCase(name.charAt(1))) { StringBuffer buff = new StringBuffer(name); buff.setCharAt(0, Character.toLowerCase(lead)); name = buff.toString(); } } else { name = name.toLowerCase(); } } return name; } /** * Get the member name for a property from the read method name. This means stripping off the leading "get" or "is" * prefix, then case-converting the result. * * @param name * @return member name * @see #convertMemberNameCase(String) * @see #memberNameFromSetMethod(String) * @see #memberNameFromField(String, String[], String[]) */ public static String memberNameFromGetMethod(String name) { if (name.startsWith("get")) { name = name.substring(3); } else if (name.startsWith("is")) { name = name.substring(2); } return convertMemberNameCase(name); } /** * Get the member name for a property from the write method name. This means stripping off the leading "set" prefix, * then case-converting the result. * * @param name * @return member name * @see #convertMemberNameCase(String) * @see #memberNameFromGetMethod(String) * @see #memberNameFromField(String, String[], String[]) */ public static String memberNameFromSetMethod(String name) { if (name.startsWith("set")) { name = name.substring(3); } return convertMemberNameCase(name); } /** * Get the member name for a field from the field name. This means stripping off and leading field name prefix * and/or trailing suffix, then case-converting the result. * * @param name * @param prefs field prefixes to be stripped * @param suffs field suffixes to be stripped * @return member name * @see #convertMemberNameCase(String) * @see #memberNameFromGetMethod(String) * @see #memberNameFromSetMethod(String) */ public static String memberNameFromField(String name, String[] prefs, String[] suffs) { if (prefs != null) { for (int i = 0; i < prefs.length; i++) { if (name.startsWith(prefs[i])) { name = name.substring(prefs[i].length()); break; } } } if (suffs != null) { for (int i = 0; i < suffs.length; i++) { if (name.endsWith(prefs[i])) { name = name.substring(name.length() - prefs[i].length()); break; } } } return convertMemberNameCase(name); } /** * Get style code. * * @return value from {@link NestingBase#s_valueStyleEnum} enumeration */ public int getStyle() { if (m_style == null) { return ((NestingBase)getParent()).getValueStyle(m_workingType); } else { return m_style.intValue(); } } /** * Get XML element or attribute name. * * @return name (null if none) */ public String getXmlName() { return m_xmlName; } /** * Get member actual type. * * @return member actual type (null if none) */ public String getActualType() { return m_actualType; } /** * Get member create type. * * @return type used for creating new instance (null if none) */ public String getCreateType() { return m_createType; } /** * Get factory method. * * @return method used for creating new instance (null if none) */ public String getFactoryMethod() { return m_factoryMethod; } /** * Check if value is required. * * @return true if required, false if not */ public boolean isRequired() { if (m_required == null) { if (m_isPrimitive) { return getParent().isPrimitiveRequired(m_workingType); } else { return getParent().isObjectRequired(m_workingType); } } else { return m_required.booleanValue(); } } /** * Set element name method. This is intended for use during unmarshalling. TODO: add validation * * @param text * @param ictx */ private void setElement(String text, IUnmarshallingContext ictx) { m_xmlName = text; m_style = new Integer(NestingBase.ELEMENT_VALUE_STYLE); } /** * Set attribute name method. This is intended for use during unmarshalling. TODO: add validation * * @param text * @param ictx */ private void setAttribute(String text, IUnmarshallingContext ictx) { m_xmlName = text; m_style = new Integer(NestingBase.ATTRIBUTE_VALUE_STYLE); } /** * Style get text method. This is intended for use during marshalling. TODO: add validation * * @return text */ private String getStyleText() { if (m_style == null) { return null; } else { return NestingBase.s_valueStyleEnum.getName(m_style.intValue()); } } // // Methods overridden by subclasses /** * Check if member represents a property. * * @return true if property, false if not */ public abstract boolean isProperty(); /** * Check if a private member. * * @return true if private, false if not */ public abstract boolean isPrivate(); /** * Check if collection member. * * @return true if collection, false if not */ public boolean isCollection() { return false; } /** * Get field name. * * @return field name (null if none) */ public String getFieldName() { return null; } /** * Get 'get' method name. * * @return 'get' method name (null if none) */ public String getGetName() { return null; } /** * Get 'set' method name. * * @return 'set' method name (null if none) */ public String getSetName() { return null; } /** * Get collection item type. * * @return item type (null if none) */ public String getItemType() { return null; } /** * Get collection item element name. * * @return item name (null if none) */ public String getItemName() { return null; } /** * Complete customization information based on supplied type. If the type information has not previously been set, * this will set it. It will also derive the appropriate XML name, if not previously set. * * @param type (null if none available) * @param req required member flag (null if unspecified) * @param style representation style (null if unspecified) */ /* package */void complete(String type, Boolean req, Integer style) { m_statedType = type; if (m_actualType == null) { if (type == null) { m_workingType = "java.lang.Object"; } else { m_workingType = type; } } else { m_workingType = m_actualType; } if (m_xmlName == null) { m_xmlName = getParent().convertName(m_baseName); } m_isPrimitive = ClassItem.isPrimitive(m_workingType); // TODO: check consistency of setting if (m_required == null) { m_required = req; } if (m_style == null) { m_style = style; } if (!m_isPrimitive && m_createType == null && m_factoryMethod == null) { ClassCustom cust = getGlobal().getClassCustomization(m_workingType); if (cust != null) { m_createType = cust.getCreateType(); m_factoryMethod = cust.getFactoryMethod(); } } } /** * Gets the parent class link from the unmarshalling stack. This method is for use by factories during * unmarshalling. * * @param ictx unmarshalling context * @return containing class */ protected static ClassCustom getContainingClass(IUnmarshallingContext ictx) { return (ClassCustom)getContainingObject(ictx); } }