blob: 856ae87b6be646277270aa27f63d78ca6912469d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.config.annotation;
import java.io.DataInput;
import java.io.IOException;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Scan .class files for annotation signature directly, without load them.
*
* @since 2.0
* @author Leonardo Uribe (latest modification by $Author$)
* @version $Revision$ $Date$
*/
class _ClassByteCodeAnnotationFilter
{
private static final Logger log = Logger.getLogger(_ClassByteCodeAnnotationFilter.class.getName());
//Constants used to define type in cp_info structure
private static final int CP_INFO_CLASS = 7;
private static final int CP_INFO_FIELD_REF = 9;
private static final int CP_INFO_METHOD_REF = 10;
private static final int CP_INFO_INTERFACE_REF = 11;
private static final int CP_INFO_STRING = 8;
private static final int CP_INFO_INTEGER = 3;
private static final int CP_INFO_FLOAT = 4;
private static final int CP_INFO_LONG = 5;
private static final int CP_INFO_DOUBLE = 6;
private static final int CP_INFO_NAME_AND_TYPE = 12;
private static final int CP_INFO_UTF8 = 1;
private static final int CP_INFO_METHOD_HANDLE = 15;
private static final int CP_INFO_METHOD_TYPE = 16;
private static final int CP_INFO_INVOKE_DYNAMIC = 18;
/**
* Checks if the .class file referenced by the DataInput could
* contain the annotation names available in the set.
*
* @param in
* @param byteCodeAnnotationsNames
* @return
* @throws IOException
*/
public static boolean couldContainAnnotationsOnClassDef(DataInput in, Set<String> byteCodeAnnotationsNames)
throws IOException
{
/* According to Java VM Spec, each .class file contains
* a single class or interface definition. The structure
* definition is shown below:
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
* u1 = readUnsignedByte
* u2 = readUnsignedShort
* u4 = readInt
*
*/
int magic = in.readInt(); //u4
if (magic != 0xCAFEBABE)
{
//the file is not recognized as a class file
return false;
}
//u2 but since in java does not exists unsigned,
//store on a bigger value
int minorVersion = in.readUnsignedShort();//u2
int majorVersion = in.readUnsignedShort();//u2
if (majorVersion < 49)
{
//Compiled with jdk 1.4, so does not have annotations
return false;
}
//constantsPoolCount is the number of entries + 1
//The index goes from 1 to constantsPoolCount-1
int constantsPoolCount = in.readUnsignedShort();
for (int i = 1; i < constantsPoolCount; i++)
{
// Format:
// cp_info {
// u1 tag;
// u1 info[];
// }
int tag = in.readUnsignedByte();
switch (tag)
{
case CP_INFO_UTF8:
//u2 length
//u1 bytes[length]
//Check if the string is a annotation reference
//name
String name = in.readUTF();
if (byteCodeAnnotationsNames.contains(name))
{
return true;
}
break;
case CP_INFO_CLASS: //ignore
//u2 name_index
in.readUnsignedShort();
break;
case CP_INFO_FIELD_REF: //ignore
case CP_INFO_METHOD_REF: //ignore
case CP_INFO_INTERFACE_REF: //ignore
//u2 class_index
//u2 name_and_type_index
in.readUnsignedShort();
in.readUnsignedShort();
break;
case CP_INFO_STRING: //ignore
//u2 string_index
in.readUnsignedShort();
break;
case CP_INFO_INTEGER: //ignore
case CP_INFO_FLOAT: //ignore
//u4 bytes
in.readInt();
break;
case CP_INFO_LONG: //ignore
case CP_INFO_DOUBLE: //ignore
//u4 high_bytes
//u4 low_bytes
in.readInt();
in.readInt();
// this tag takes two entries in the constants pool
i++;
break;
case CP_INFO_NAME_AND_TYPE: //ignore
//u2 name_index
//u2 descriptor_index
in.readUnsignedShort();
in.readUnsignedShort();
break;
case CP_INFO_METHOD_HANDLE: // Ignore
// u1 reference_kind
// u2 reference_index
in.readUnsignedByte();
in.readUnsignedShort();
break;
case CP_INFO_METHOD_TYPE: // Ignore
// u2 descriptor_index
in.readUnsignedShort();
break;
case CP_INFO_INVOKE_DYNAMIC: // Ignore
// u2 bootstrap_method_attr_index;
// u2 name_and_type_index;
in.readUnsignedShort();
in.readUnsignedShort();
break;
default:
// THIS SHOULD NOT HAPPEN! Log error info
// and break for loop, because from this point
// we are reading corrupt data.
if (log.isLoggable(Level.WARNING))
{
log.warning("Unknown tag in constants pool: " + tag);
}
i = constantsPoolCount;
break;
}
}
return false;
}
}