1/*
2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.xml.internal.bind.v2.runtime;
27
28import java.lang.annotation.Annotation;
29import java.util.ArrayList;
30import java.util.Collections;
31import java.util.List;
32
33import javax.xml.bind.JAXBContext;
34import javax.xml.bind.JAXBException;
35
36import com.sun.xml.internal.bind.v2.model.annotation.Locatable;
37
38/**
39 * Signals an incorrect use of JAXB annotations.
40 *
41 * @author Kohsuke Kawaguchi (kk@kohsuke.org)
42 * @since JAXB 2.0 EA1
43 */
44public class IllegalAnnotationException extends JAXBException {
45
46    /**
47     * Read-only list of {@link Location}s.
48     */
49    private final List<List<Location>> pos;
50
51    private static final long serialVersionUID = 1L;
52
53    public IllegalAnnotationException(String message, Locatable src) {
54        super(message);
55        pos = build(src);
56    }
57
58    public IllegalAnnotationException(String message, Annotation src) {
59        this(message,cast(src));
60    }
61
62    public IllegalAnnotationException(String message, Locatable src1, Locatable src2) {
63        super(message);
64        pos = build(src1,src2);
65    }
66
67    public IllegalAnnotationException(String message, Annotation src1, Annotation src2) {
68        this(message,cast(src1),cast(src2));
69    }
70
71    public IllegalAnnotationException(String message, Annotation src1, Locatable src2) {
72        this(message,cast(src1),src2);
73    }
74
75    public IllegalAnnotationException(String message, Throwable cause, Locatable src) {
76        super(message, cause);
77        pos = build(src);
78    }
79
80    private static Locatable cast(Annotation a) {
81        if(a instanceof Locatable)
82            return (Locatable)a;
83        else
84            return null;
85    }
86
87    private List<List<Location>> build(Locatable... srcs) {
88        List<List<Location>> r = new ArrayList<List<Location>>();
89        for( Locatable l : srcs ) {
90            if(l!=null) {
91                List<Location> ll = convert(l);
92                if(ll!=null && !ll.isEmpty())
93                    r.add(ll);
94            }
95        }
96        return Collections.unmodifiableList(r);
97    }
98
99    /**
100     * Builds a list of {@link Location}s out of a {@link Locatable}.
101     */
102    private List<Location> convert(Locatable src) {
103        if(src==null)   return null;
104
105        List<Location> r = new ArrayList<Location>();
106        for( ; src!=null; src=src.getUpstream())
107            r.add(src.getLocation());
108        return Collections.unmodifiableList(r);
109    }
110
111
112
113    /**
114     * Returns a read-only list of {@link Location} that indicates
115     * where in the source code the problem has happened.
116     *
117     * <p>
118     * Normally, an annotation error happens on one particular
119     * annotation, in which case this method returns a list that
120     * contains another list, which in turn contains the location
121     * information that leads to the error location
122     * (IOW, {@code [ [pos1,pos2,...,posN] ]})
123     *
124     * <p>
125     * Sometimes, an error could occur because of two or more conflicting
126     * annotations, in which case this method returns a list
127     * that contains many lists, where each list contains
128     * the location information that leads to each of the conflicting
129     * annotations
130     * (IOW, {@code [ [pos11,pos12,...,pos1N],[pos21,pos22,...,pos2M], ... ]})
131     *
132     * <p>
133     * Yet some other time, the runtime can fail to provide any
134     * error location, in which case this method returns an empty list.
135     * (IOW, {@code []}). We do try hard to make sure this won't happen,
136     * so please <a href="http://jaxb.dev.java.net/">let us know</a>
137     * if you see this behavior.
138     *
139     *
140     * <h3>List of {@link Location}</h3>
141     * <p>
142     * Each error location is identified not just by one {@link Location}
143     * object, but by a sequence of {@link Location}s that shows why
144     * the runtime is led to the place of the error.
145     * This list is sorted such that the most specific {@link Location} comes
146     * to the first in the list, sort of like a stack trace.
147     *
148     * <p>
149     * For example, suppose you specify class {@code Foo} to {@link JAXBContext},
150     * {@code Foo} derives from {@code Bar}, {@code Bar} has a field {@code pea}
151     * that points to {@code Zot}, {@code Zot} contains a {@code gum}
152     * property, and this property has an errornous annotation.
153     * Then when this exception is thrown, the list of {@link Location}s
154     * will look something like
155     * {@code [ "gum property", "Zot class", "pea property", "Bar class", "Foo class" ]}
156     *
157     *
158     * @return
159     *      can be empty when no source position is available,
160     *      but never null. The returned list will never contain
161     *      null nor length-0 {@link List}.
162     */
163    public List<List<Location>> getSourcePos() {
164        return pos;
165    }
166
167    /**
168     * Returns the exception name, message, and related information
169     * together in one string.
170     *
171     * <p>
172     * Overriding this method (instead of {@link #printStackTrace} allows
173     * this crucial detail to show up even when this exception is nested
174     * inside other exceptions.
175     */
176    public String toString() {
177        StringBuilder sb = new StringBuilder(getMessage());
178
179        for( List<Location> locs : pos ) {
180            sb.append("\n\tthis problem is related to the following location:");
181            for( Location loc : locs )
182                sb.append("\n\t\tat ").append(loc.toString());
183        }
184
185        return sb.toString();
186    }
187}
188