001: /*
002: Copyright (c) 2007, Dennis M. Sosnoski
003: All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without modification,
006: are permitted provided that the following conditions are met:
007:
008: * Redistributions of source code must retain the above copyright notice, this
009: list of conditions and the following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: * Neither the name of JiBX nor the names of its contributors may be used
014: to endorse or promote products derived from this software without specific
015: prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028:
029: package org.jibx.binding.generator;
030:
031: import java.util.Collection;
032:
033: import org.jibx.binding.classes.ClassItem;
034: import org.jibx.runtime.IUnmarshallingContext;
035:
036: /**
037: * Member field or property customization information.
038: */
039: public abstract class MemberCustom extends CustomBase {
040: // values specific to member level
041: private String m_baseName; // internal use, not included in binding
042: private String m_statedType; // internal use, not included in binding
043: private String m_workingType; // internal use, not included in binding
044: private boolean m_primitive; // internal use, not included in binding
045: private Integer m_style; // internal use, not included in binding
046: private String m_xmlName;
047: private String m_actualType;
048: private String m_createType;
049: private String m_factoryMethod;
050: private Boolean m_required;
051:
052: /**
053: * Constructor.
054: *
055: * @param parent
056: */
057: protected MemberCustom(SharedNestingBase parent) {
058: super (parent);
059: }
060:
061: /**
062: * Constructor with name known.
063: *
064: * @param parent
065: * @param name
066: */
067: protected MemberCustom(SharedNestingBase parent, String name) {
068: this (parent);
069: m_baseName = name;
070: }
071:
072: /**
073: * Get member (field or property) name. In the case of a field, this is the
074: * name with any prefix or suffix stripped; in the case of a property, it's
075: * the property name. For both field and property names, the initial letter
076: * is converted to lowercase unless the second letter is lowercase.
077: *
078: * @return name
079: */
080: public String getBaseName() {
081: return m_baseName;
082: }
083:
084: /**
085: * Set member (field or property) name. This is only for use by subclasses.
086: *
087: * @param name
088: */
089: protected void setBaseName(String name) {
090: m_baseName = name;
091: }
092:
093: /**
094: * Get stated type of member.
095: *
096: * @return stated type
097: */
098: public String getStatedType() {
099: return m_statedType;
100: }
101:
102: /**
103: * Get working type of member.
104: *
105: * @return working type
106: */
107: public String getWorkingType() {
108: return m_workingType;
109: }
110:
111: /**
112: * Convert case of member name derived from method or field name. If the
113: * supplied name starts with an uppercase letter followed by a lowercase
114: * letter, the initial letter is converted to lowercase in order to obtain a
115: * standard form of the name.
116: *
117: * @param name
118: * @return converted name
119: */
120: public static String convertMemberNameCase(String name) {
121: if (name.length() > 0) {
122: char lead = name.charAt(0);
123: if (name.length() > 1) {
124: if (Character.isUpperCase(lead)
125: && Character.isLowerCase(name.charAt(1))) {
126: StringBuffer buff = new StringBuffer(name);
127: buff.setCharAt(0, Character.toLowerCase(lead));
128: name = buff.toString();
129: }
130: } else {
131: name = name.toLowerCase();
132: }
133: }
134: return name;
135: }
136:
137: /**
138: * Get the member name for a property from the read method name. This means
139: * stripping off the leading "get" or "is" prefix, then case-converting the
140: * result.
141: *
142: * @param name
143: * @return member name
144: * @see #convertMemberNameCase(String)
145: * @see #memberNameFromSetMethod(String)
146: * @see #memberNameFromField(String, String[], String[])
147: */
148: public static String memberNameFromGetMethod(String name) {
149: if (name.startsWith("get")) {
150: name = name.substring(3);
151: } else if (name.startsWith("is")) {
152: name = name.substring(2);
153: }
154: return convertMemberNameCase(name);
155: }
156:
157: /**
158: * Get the member name for a property from the write method name. This means
159: * stripping off the leading "set" prefix, then case-converting the result.
160: *
161: * @param name
162: * @return member name
163: * @see #convertMemberNameCase(String)
164: * @see #memberNameFromGetMethod(String)
165: * @see #memberNameFromField(String, String[], String[])
166: */
167: public static String memberNameFromSetMethod(String name) {
168: if (name.startsWith("set")) {
169: name = name.substring(3);
170: }
171: return convertMemberNameCase(name);
172: }
173:
174: /**
175: * Get the member name for a field from the field name. This means stripping
176: * off and leading field name prefix and/or trailing suffix, then
177: * case-converting the result.
178: *
179: * @param name
180: * @param prefs field prefixes to be stripped
181: * @param suffs field suffixes to be stripped
182: * @return member name
183: * @see #convertMemberNameCase(String)
184: * @see #memberNameFromGetMethod(String)
185: * @see #memberNameFromSetMethod(String)
186: */
187: public static String memberNameFromField(String name,
188: String[] prefs, String[] suffs) {
189: if (prefs != null) {
190: for (int i = 0; i < prefs.length; i++) {
191: if (name.startsWith(prefs[i])) {
192: name = name.substring(prefs[i].length());
193: break;
194: }
195: }
196: }
197: if (suffs != null) {
198: for (int i = 0; i < suffs.length; i++) {
199: if (name.endsWith(prefs[i])) {
200: name = name.substring(name.length()
201: - prefs[i].length());
202: break;
203: }
204: }
205: }
206: return convertMemberNameCase(name);
207: }
208:
209: /**
210: * Get style code.
211: *
212: * @return value from {@link NestingBase#s_valueStyleEnum} enumeration
213: */
214: public int getStyle() {
215: if (m_style == null) {
216: return ((NestingBase) getParent())
217: .getValueStyle(m_workingType);
218: } else {
219: return m_style.intValue();
220: }
221: }
222:
223: /**
224: * Get XML element or attribute name.
225: *
226: * @return name (<code>null</code> if none)
227: */
228: public String getXmlName() {
229: return m_xmlName;
230: }
231:
232: /**
233: * Get member actual type.
234: *
235: * @return member actual type (<code>null</code> if none)
236: */
237: public String getActualType() {
238: return m_actualType;
239: }
240:
241: /**
242: * Get member create type.
243: *
244: * @return type used for creating new instance (<code>null</code> if none)
245: */
246: public String getCreateType() {
247: return m_createType;
248: }
249:
250: /**
251: * Get factory method.
252: *
253: * @return method used for creating new instance (<code>null</code> if none)
254: */
255: public String getFactoryMethod() {
256: return m_factoryMethod;
257: }
258:
259: /**
260: * Check if value is required.
261: *
262: * @return <code>true</code> if required, <code>false</code> if not
263: */
264: public boolean isRequired() {
265: if (m_required == null) {
266: if (m_primitive) {
267: return getParent().isPrimitiveRequired(m_workingType);
268: } else {
269: return getParent().isObjectRequired(m_workingType);
270: }
271: } else {
272: return m_required.booleanValue();
273: }
274: }
275:
276: /**
277: * Set element name method. This is intended for use during unmarshalling.
278: * TODO: add validation
279: *
280: * @param text
281: * @param ictx
282: */
283: private void setElement(String text, IUnmarshallingContext ictx) {
284: m_xmlName = text;
285: m_style = new Integer(NestingBase.ELEMENT_VALUE_STYLE);
286: }
287:
288: /**
289: * Set attribute name method. This is intended for use during unmarshalling.
290: * TODO: add validation
291: *
292: * @param text
293: * @param ictx
294: */
295: private void setAttribute(String text, IUnmarshallingContext ictx) {
296: m_xmlName = text;
297: m_style = new Integer(NestingBase.ATTRIBUTE_VALUE_STYLE);
298: }
299:
300: /**
301: * Style get text method. This is intended for use during marshalling.
302: *
303: * @return text
304: */
305: private String getStyleText() {
306: if (m_style == null) {
307: return null;
308: } else {
309: return NestingBase.s_valueStyleEnum.getName(m_style
310: .intValue());
311: }
312: }
313:
314: //
315: // Methods overridden by subclasses
316:
317: /**
318: * Check if collection member.
319: *
320: * @return <code>true</code> if collection, <code>false</code> if not
321: */
322: public boolean isCollection() {
323: return false;
324: }
325:
326: /**
327: * Get field name.
328: *
329: * @return field name (<code>null</code> if none)
330: */
331: public String getFieldName() {
332: return null;
333: }
334:
335: /**
336: * Get 'get' method name.
337: *
338: * @return 'get' method name (<code>null</code> if none)
339: */
340: public String getGetName() {
341: return null;
342: }
343:
344: /**
345: * Get 'set' method name.
346: *
347: * @return 'set' method name (<code>null</code> if none)
348: */
349: public String getSetName() {
350: return null;
351: }
352:
353: /**
354: * Get collection item type.
355: *
356: * @return item type (<code>null</code> if none)
357: */
358: public String getItemType() {
359: return null;
360: }
361:
362: /**
363: * Get collection item element name.
364: *
365: * @return item name (<code>null</code> if none)
366: */
367: public String getItemName() {
368: return null;
369: }
370:
371: /**
372: * Complete customization information based on supplied type. If the type
373: * information has not previously been set, this will set it. It will also
374: * derive the appropriate XML name, if not previously set.
375: *
376: * @param type (<code>null</code> if none available)
377: * @param req required member flag (<code>null</code> if unknown)
378: */
379: /*package*/void complete(String type, Boolean req) {
380: m_statedType = type;
381: if (m_actualType == null) {
382: if (type == null) {
383: m_workingType = "java.lang.Object";
384: } else {
385: m_workingType = type;
386: }
387: } else {
388: m_workingType = m_actualType;
389: }
390: if (m_xmlName == null) {
391: m_xmlName = getParent().convertName(m_baseName);
392: }
393: m_primitive = ClassItem.isPrimitive(m_workingType);
394: // TODO: check consistency of setting
395: if (m_required == null) {
396: m_required = req;
397: }
398: if (!m_primitive && m_createType == null
399: && m_factoryMethod == null) {
400: ClassCustom cust = getGlobal().getClassCustomization(
401: m_workingType);
402: if (cust != null) {
403: m_createType = cust.getCreateType();
404: m_factoryMethod = cust.getFactoryMethod();
405: }
406: }
407: }
408:
409: /**
410: * Gets the parent element link from the unmarshalling stack. This method is
411: * for use by factories during unmarshalling.
412: *
413: * @param ictx unmarshalling context
414: * @return containing class
415: */
416: protected static ClassCustom getContainingClass(
417: IUnmarshallingContext ictx) {
418: Object parent = ictx.getStackTop();
419: int depth = 0;
420: if (parent instanceof Collection) {
421: parent = ictx.getStackObject(++depth);
422: }
423: return (ClassCustom) parent;
424: }
425: }
|