001/*
002 * Copyright 2011 Atteo.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014package org.atteo.evo.jaxb;
015
016import java.lang.annotation.Annotation;
017import java.lang.reflect.Field;
018import java.lang.reflect.Method;
019import java.lang.reflect.Type;
020import java.util.Properties;
021
022import javax.xml.bind.annotation.XmlElement;
023
024import org.atteo.evo.filtering.Filtering;
025import org.atteo.evo.filtering.PropertiesPropertyResolver;
026import org.atteo.evo.filtering.PropertyNotFoundException;
027import org.atteo.evo.filtering.PropertyResolver;
028
029import com.sun.xml.bind.v2.model.annotation.Locatable;
030import com.sun.xml.bind.v2.model.annotation.RuntimeAnnotationReader;
031import com.sun.xml.bind.v2.model.annotation.RuntimeInlineAnnotationReader;
032import com.sun.xml.bind.v2.model.core.ErrorHandler;
033
034/**
035 * Custom JAXB annotation reader which filters {@link XmlElement}
036 * {@link XmlElement#defaultValue() default values} with properties.
037 */
038public class FilteringAnnotationReader implements RuntimeAnnotationReader {
039    private RuntimeAnnotationReader delegate = new RuntimeInlineAnnotationReader();
040    private PropertyResolver propertyResolver;
041
042    public FilteringAnnotationReader(PropertyResolver propertyResolver) {
043        this.propertyResolver = propertyResolver;
044    }
045
046    public FilteringAnnotationReader(Properties properties) {
047        this(new PropertiesPropertyResolver(properties));
048    }
049
050    @Override
051    public void setErrorHandler(ErrorHandler errorHandler) {
052        delegate.setErrorHandler(errorHandler);
053    }
054
055    @Override
056    public <A extends Annotation> A getFieldAnnotation(Class<A> annotation, Field field,
057            Locatable srcpos) {
058        A original = delegate.getFieldAnnotation(annotation, field, srcpos);
059        if (annotation == XmlElement.class && original != null) {
060            final XmlElement xmlElement = (XmlElement) original;
061            final String defaultValue;
062            try {
063                String originalValue = xmlElement.defaultValue();
064                if ("\u0000".equals(originalValue)) {
065                    return original;
066                }
067                defaultValue = Filtering.filter(originalValue, propertyResolver);
068                if (defaultValue == null || defaultValue.equals(originalValue)) {
069                    return original;
070                }
071            } catch (PropertyNotFoundException e) {
072                return original;
073            }
074
075            return annotation.cast(new XmlElement() {
076                @Override
077                public String name() {
078                    return xmlElement.name();
079                }
080
081                @Override
082                public boolean nillable() {
083                    return xmlElement.nillable();
084                }
085
086                @Override
087                public boolean required() {
088                    return xmlElement.required();
089                }
090
091                @Override
092                public String namespace() {
093                    return xmlElement.namespace();
094                }
095
096                @Override
097                public String defaultValue() {
098                    return defaultValue;
099                }
100
101                @SuppressWarnings("rawtypes")
102                @Override
103                public Class type() {
104                    return xmlElement.type();
105                }
106
107                @Override
108                public Class<? extends Annotation> annotationType() {
109                    return xmlElement.annotationType();
110                }
111            });
112        }
113        return original;
114    }
115
116    @Override
117    public boolean hasFieldAnnotation(Class<? extends Annotation> annotationType, Field field) {
118        return delegate.hasFieldAnnotation(annotationType, field);
119    }
120
121    @SuppressWarnings("rawtypes")
122    @Override
123    public boolean hasClassAnnotation(Class clazz, Class<? extends Annotation> annotationType) {
124        return delegate.hasClassAnnotation(clazz, annotationType);
125    }
126
127    @Override
128    public Annotation[] getAllFieldAnnotations(Field field, Locatable srcPos) {
129        return delegate.getAllFieldAnnotations(field, srcPos);
130    }
131
132    @Override
133    public <A extends Annotation> A getMethodAnnotation(Class<A> annotation, Method getter,
134            Method setter, Locatable srcpos) {
135        return delegate.getMethodAnnotation(annotation, getter, setter, srcpos);
136    }
137
138    @Override
139    public boolean hasMethodAnnotation(Class<? extends Annotation> annotation, String propertyName,
140            Method getter, Method setter, Locatable srcPos) {
141        return delegate.hasMethodAnnotation(annotation, propertyName, getter, setter, srcPos);
142    }
143
144    @Override
145    public Annotation[] getAllMethodAnnotations(Method method, Locatable srcPos) {
146        return delegate.getAllMethodAnnotations(method, srcPos);
147    }
148
149    @Override
150    public <A extends Annotation> A getMethodAnnotation(Class<A> annotation, Method method,
151            Locatable srcpos) {
152        return delegate.getMethodAnnotation(annotation, method, srcpos);
153    }
154
155    @Override
156    public boolean hasMethodAnnotation(Class<? extends Annotation> annotation, Method method) {
157        return delegate.hasMethodAnnotation(annotation, method);
158    }
159
160    @Override
161    public <A extends Annotation> A getMethodParameterAnnotation(Class<A> annotation,
162            Method method, int paramIndex, Locatable srcPos) {
163        return delegate.getMethodParameterAnnotation(annotation, method, paramIndex, srcPos);
164    }
165
166    @SuppressWarnings("rawtypes")
167    @Override
168    public <A extends Annotation> A getClassAnnotation(Class<A> annotation, Class clazz,
169            Locatable srcpos) {
170        return delegate.getClassAnnotation(annotation, clazz, srcpos);
171    }
172
173    @SuppressWarnings("rawtypes")
174    @Override
175    public <A extends Annotation> A getPackageAnnotation(Class<A> annotation, Class clazz,
176            Locatable srcpos) {
177        return delegate.getPackageAnnotation(annotation, clazz, srcpos);
178    }
179
180    @Override
181    public Type getClassValue(Annotation a, String name) {
182        return delegate.getClassValue(a, name);
183    }
184
185    @Override
186    public Type[] getClassArrayValue(Annotation a, String name) {
187        return delegate.getClassArrayValue(a, name);
188    }
189}