001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * 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 is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.parser; 014 015import static org.apache.juneau.internal.StringUtils.*; 016 017import java.lang.reflect.*; 018import java.text.*; 019import java.util.*; 020 021import org.apache.juneau.*; 022import org.apache.juneau.internal.*; 023import org.apache.juneau.serializer.*; 024 025/** 026 * Exception that indicates invalid syntax encountered during parsing. 027 */ 028public class ParseException extends FormattedException { 029 030 private static final long serialVersionUID = 1L; 031 032 /** 033 * Creator method. 034 * 035 * <p> 036 * If the throwable is already a {@link ParseException}, we simply return that exception as-is. 037 * If the throwable is an {@link InvocationTargetException}, we unwrap the thrown exception. 038 * Otherwise we create a new {@link ParseException}. 039 * 040 * @param e The exception being wrapped or unwrapped. 041 * @return A new {@link SerializeException}. 042 */ 043 public static ParseException create(Throwable e) { 044 if (e instanceof InvocationTargetException) 045 e = ((InvocationTargetException)e).getCause(); 046 if (e instanceof ParseException) 047 return (ParseException)e; 048 return new ParseException(e); 049 } 050 051 /** 052 * Constructor. 053 * 054 * @param message The {@link MessageFormat}-style message. 055 * @param args Optional {@link MessageFormat}-style arguments. 056 */ 057 public ParseException(String message, Object...args) { 058 super(message, args); 059 } 060 061 /** 062 * Constructor. 063 * 064 * @param causedBy The cause of this exception. 065 * @param message The {@link MessageFormat}-style message. 066 * @param args Optional {@link MessageFormat}-style arguments. 067 */ 068 public ParseException(Throwable causedBy, String message, Object...args) { 069 super(causedBy, message, args); 070 } 071 072 /** 073 * Constructor. 074 * 075 * @param causedBy The cause of this exception. 076 */ 077 public ParseException(Throwable causedBy) { 078 super(causedBy); 079 } 080 081 /** 082 * Constructor. 083 * 084 * @param session The parser session. 085 * @param message The exception message containing {@link MessageFormat}-style arguments. 086 * @param args Optional {@link MessageFormat}-style arguments. 087 */ 088 public ParseException(ParserSession session, String message, Object...args) { 089 super(getMessage(session, message, args)); 090 } 091 092 /** 093 * Constructor. 094 * 095 * @param session The parser session. 096 * @param causedBy The cause of this exception. 097 * @param message The exception message containing {@link MessageFormat}-style arguments. 098 * @param args Optional {@link MessageFormat}-style arguments. 099 */ 100 public ParseException(ParserSession session, Throwable causedBy, String message, Object...args) { 101 super(causedBy, getMessage(session, message, args)); 102 } 103 104 /** 105 * Constructor. 106 * 107 * @param session The parser session. 108 * @param causedBy The inner exception. 109 */ 110 public ParseException(ParserSession session, Exception causedBy) { 111 super(causedBy, getMessage(session, causedBy.getMessage())); 112 } 113 114 115 private static String getMessage(ParserSession session, String msg, Object... args) { 116 if (args.length != 0) 117 msg = format(msg, args); 118 119 if (session != null) { 120 Position p = session.getPosition(); 121 122 msg += "\n\tAt: " + p; 123 124 ObjectMap lastLocation = session.getLastLocation(); 125 if (lastLocation != null) { 126 msg += "\n\tWhile parsing into: "; 127 for (Map.Entry<String,Object> e : lastLocation.entrySet()) 128 msg += "\n\t\t" + e.getKey() + ": " + e.getValue(); 129 } 130 131 String lines = session.getInputAsString(); 132 if (lines == null) 133 msg += "\n\tUse BEAN_debug setting to display content."; 134 else { 135 int numLines = session.getDebugOutputLines(); 136 int start = p.line - numLines, end = p.line + numLines; 137 msg += "\n---start--\n" + StringUtils.getNumberedLines(lines, start, end) + "---end---"; 138 } 139 } 140 return msg; 141 } 142 143 /** 144 * Returns the highest-level <c>ParseException</c> in the stack trace. 145 * 146 * <p> 147 * Useful for JUnit testing of error conditions. 148 * 149 * @return The root parse exception, or this exception if there isn't one. 150 */ 151 public ParseException getRootCause() { 152 ParseException t = this; 153 while (! (t.getCause() == null || ! (t.getCause() instanceof ParseException))) 154 t = (ParseException)t.getCause(); 155 return t; 156 } 157}