001/* 002 * (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 */ 020 021package org.nuxeo.common.xmap; 022 023import org.nuxeo.common.xmap.annotation.XNode; 024import org.w3c.dom.Element; 025 026/** 027 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 028 */ 029public class XAnnotatedMember { 030 031 protected final XAccessor accessor; 032 033 protected Path path; 034 035 protected boolean trim; 036 037 /** The Java type of the described element. */ 038 protected Class type; 039 040 /** Not null if the described object is an xannotated object. */ 041 protected XAnnotatedObject xao; 042 043 /** 044 * The value factory used to transform strings in objects compatible with this member type. In the case of 045 * collection types this factory is used for collection components. 046 */ 047 protected XValueFactory valueFactory; 048 049 private final XMap xmap; 050 051 protected XAnnotatedMember(XMap xmap, XAccessor accessor) { 052 this.xmap = xmap; 053 this.accessor = accessor; 054 } 055 056 public XAnnotatedMember(XMap xmap, XAccessor setter, XNode anno) { 057 this.xmap = xmap; 058 accessor = setter; 059 path = new Path(anno.value()); 060 trim = anno.trim(); 061 type = setter.getType(); 062 valueFactory = xmap.getValueFactory(type); 063 if (valueFactory == null && type.isEnum()) { 064 valueFactory = new XValueFactory() { 065 @Override 066 public String serialize(Context arg0, Object arg1) { 067 return ((Enum<?>) arg1).name(); 068 } 069 070 @SuppressWarnings("unchecked") 071 @Override 072 public Object deserialize(Context arg0, String arg1) { 073 return Enum.valueOf(type, arg1); 074 } 075 }; 076 xmap.setValueFactory(type, valueFactory); 077 } 078 xao = xmap.register(type); 079 } 080 081 protected void setValue(Object instance, Object value) { 082 try { 083 accessor.setValue(instance, value); 084 } catch (IllegalArgumentException e) { 085 throw new IllegalArgumentException( 086 String.format("%s, setter=%s, value=%s", e.getMessage(), accessor, value), e); 087 } 088 } 089 090 public void toXML(Object instance, Element parent) { 091 Element e = XMLBuilder.getOrCreateElement(parent, path); 092 Object v = accessor.getValue(instance); 093 if (xao == null) { 094 if (v != null && valueFactory != null) { 095 String value = valueFactory.serialize(null, v); 096 if (value != null) { 097 098 XMLBuilder.fillField(e, value, path.attribute); 099 } 100 } 101 } else { 102 XMLBuilder.toXML(v, e, xao); 103 } 104 } 105 106 public void process(Context ctx, Element element) { 107 Object value = getValue(ctx, element); 108 if (value != null) { 109 setValue(ctx.getObject(), value); 110 } 111 } 112 113 protected Object getValue(Context ctx, Element base) { 114 if (xao != null) { 115 Element el = (Element) DOMHelper.getElementNode(base, path); 116 if (el == null) { 117 return null; 118 } else { 119 return xao.newInstance(ctx, el); 120 } 121 } 122 // scalar field 123 if (type == Element.class) { 124 // allow DOM elements as values 125 return base; 126 } 127 String val = DOMHelper.getNodeValue(base, path); 128 if (val != null) { 129 if (trim) { 130 val = val.trim(); 131 } 132 if (valueFactory == null) { 133 throw new NullPointerException("Missing XValueFactory for " + type); 134 } 135 return valueFactory.deserialize(ctx, val); 136 } 137 return null; 138 } 139 140}