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.collections.*; 023import org.apache.juneau.internal.*; 024import org.apache.juneau.serializer.*; 025 026/** 027 * Exception that indicates invalid syntax encountered during parsing. 028 */ 029public class ParseException extends BasicException { 030 031 private static final long serialVersionUID = 1L; 032 033 /** 034 * Creator method. 035 * 036 * <p> 037 * If the throwable is already a {@link ParseException}, we simply return that exception as-is. 038 * If the throwable is an {@link InvocationTargetException}, we unwrap the thrown exception. 039 * Otherwise we create a new {@link ParseException}. 040 * 041 * @param e The exception being wrapped or unwrapped. 042 * @return A new {@link SerializeException}. 043 */ 044 public static ParseException create(Throwable e) { 045 if (e instanceof InvocationTargetException) 046 e = ((InvocationTargetException)e).getCause(); 047 if (e instanceof ParseException) 048 return (ParseException)e; 049 return new ParseException(e); 050 } 051 052 /** 053 * Constructor. 054 * 055 * @param message The {@link MessageFormat}-style message. 056 * @param args Optional {@link MessageFormat}-style arguments. 057 */ 058 public ParseException(String message, Object...args) { 059 super(message, args); 060 } 061 062 /** 063 * Constructor. 064 * 065 * @param causedBy The cause of this exception. 066 * @param message The {@link MessageFormat}-style message. 067 * @param args Optional {@link MessageFormat}-style arguments. 068 */ 069 public ParseException(Throwable causedBy, String message, Object...args) { 070 super(causedBy, message, args); 071 } 072 073 /** 074 * Constructor. 075 * 076 * @param causedBy The cause of this exception. 077 */ 078 public ParseException(Throwable causedBy) { 079 super(causedBy); 080 } 081 082 /** 083 * Constructor. 084 * 085 * @param session The parser session. 086 * @param message The exception message containing {@link MessageFormat}-style arguments. 087 * @param args Optional {@link MessageFormat}-style arguments. 088 */ 089 public ParseException(ParserSession session, String message, Object...args) { 090 super(getMessage(session, message, args)); 091 } 092 093 /** 094 * Constructor. 095 * 096 * @param session The parser session. 097 * @param causedBy The cause of this exception. 098 * @param message The exception message containing {@link MessageFormat}-style arguments. 099 * @param args Optional {@link MessageFormat}-style arguments. 100 */ 101 public ParseException(ParserSession session, Throwable causedBy, String message, Object...args) { 102 super(causedBy, getMessage(session, message, args)); 103 } 104 105 /** 106 * Constructor. 107 * 108 * @param session The parser session. 109 * @param causedBy The inner exception. 110 */ 111 public ParseException(ParserSession session, Exception causedBy) { 112 super(causedBy, getMessage(session, causedBy.getMessage())); 113 } 114 115 116 private static String getMessage(ParserSession session, String msg, Object... args) { 117 if (args.length != 0) 118 msg = format(msg, args); 119 120 if (session != null) { 121 Position p = session.getPosition(); 122 123 msg += "\n\tAt: " + p; 124 125 OMap lastLocation = session.getLastLocation(); 126 if (lastLocation != null) { 127 msg += "\n\tWhile parsing into: "; 128 for (Map.Entry<String,Object> e : lastLocation.entrySet()) 129 msg += "\n\t\t" + e.getKey() + ": " + e.getValue(); 130 } 131 132 String lines = session.getInputAsString(); 133 if (lines == null) 134 msg += "\n\tUse BEAN_debug setting to display content."; 135 else { 136 int numLines = session.getDebugOutputLines(); 137 int start = p.line - numLines, end = p.line + numLines; 138 msg += "\n---start--\n" + StringUtils.getNumberedLines(lines, start, end) + "---end---"; 139 } 140 } 141 return msg; 142 } 143 144 /** 145 * Returns the highest-level <c>ParseException</c> in the stack trace. 146 * 147 * <p> 148 * Useful for JUnit testing of error conditions. 149 * 150 * @return The root parse exception, or this exception if there isn't one. 151 */ 152 public ParseException getRootCause() { 153 ParseException t = this; 154 while (! (t.getCause() == null || ! (t.getCause() instanceof ParseException))) 155 t = (ParseException)t.getCause(); 156 return t; 157 } 158}