001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.jackson; 018 019import java.io.IOException; 020 021import com.fasterxml.jackson.core.JsonParser; 022import com.fasterxml.jackson.core.JsonProcessingException; 023import com.fasterxml.jackson.core.JsonToken; 024import com.fasterxml.jackson.databind.DeserializationContext; 025import com.fasterxml.jackson.databind.JsonMappingException; 026import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer; 027 028/** 029 * Copy and edit the Jackson (Apache License 2.0) class to use Log4j attribute names. Does not work as of Jackson 2.3.2. 030 * <p> 031 * <em>Consider this class private.</em> 032 * </p> 033 */ 034public final class Log4jStackTraceElementDeserializer extends StdScalarDeserializer<StackTraceElement> { 035 private static final long serialVersionUID = 1L; 036 037 /** 038 * Constructs a new initialized instance. 039 */ 040 public Log4jStackTraceElementDeserializer() { 041 super(StackTraceElement.class); 042 } 043 044 @Override 045 public StackTraceElement deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, 046 JsonProcessingException { 047 JsonToken t = jp.getCurrentToken(); 048 // Must get an Object 049 if (t == JsonToken.START_OBJECT) { 050 String className = null, methodName = null, fileName = null; 051 int lineNumber = -1; 052 053 while ((t = jp.nextValue()) != JsonToken.END_OBJECT) { 054 final String propName = jp.getCurrentName(); 055 if ("class".equals(propName)) { 056 className = jp.getText(); 057 } else if ("file".equals(propName)) { 058 fileName = jp.getText(); 059 } else if ("line".equals(propName)) { 060 if (t.isNumeric()) { 061 lineNumber = jp.getIntValue(); 062 } else { 063 // An XML number always comes in a string since there is no syntax help as with JSON. 064 try { 065 lineNumber = Integer.parseInt(jp.getText().trim()); 066 } catch (final NumberFormatException e) { 067 throw JsonMappingException.from(jp, "Non-numeric token (" + t + ") for property 'line'", e); 068 } 069 } 070 } else if ("method".equals(propName)) { 071 methodName = jp.getText(); 072 } else if ("nativeMethod".equals(propName)) { 073 // no setter, not passed via constructor: ignore 074 } else { 075 this.handleUnknownProperty(jp, ctxt, this._valueClass, propName); 076 } 077 } 078 return new StackTraceElement(className, methodName, fileName, lineNumber); 079 } 080 throw ctxt.mappingException(this._valueClass, t); 081 } 082}