1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.myfaces.config.annotation;
20
21 import java.io.DataInput;
22 import java.io.IOException;
23 import java.util.Set;
24 import java.util.logging.Level;
25 import java.util.logging.Logger;
26
27 /**
28 * Scan .class files for annotation signature directly, without load them.
29 *
30 * @since 2.0
31 * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
32 * @version $Revision: 1041035 $ $Date: 2010-12-01 09:59:17 -0500 (Wed, 01 Dec 2010) $
33 */
34 class _ClassByteCodeAnnotationFilter
35 {
36
37 private static final Logger log = Logger.getLogger(_ClassByteCodeAnnotationFilter.class.getName());
38
39 //Constants used to define type in cp_info structure
40 private static final int CP_INFO_CLASS = 7;
41 private static final int CP_INFO_FIELD_REF = 9;
42 private static final int CP_INFO_METHOD_REF = 10;
43 private static final int CP_INFO_INTERFACE_REF = 11;
44 private static final int CP_INFO_STRING = 8;
45 private static final int CP_INFO_INTEGER = 3;
46 private static final int CP_INFO_FLOAT = 4;
47 private static final int CP_INFO_LONG = 5;
48 private static final int CP_INFO_DOUBLE = 6;
49 private static final int CP_INFO_NAME_AND_TYPE = 12;
50 private static final int CP_INFO_UTF8 = 1;
51
52 /**
53 * Checks if the .class file referenced by the DataInput could
54 * contain the annotation names available in the set.
55 *
56 * @param in
57 * @param byteCodeAnnotationsNames
58 * @return
59 * @throws IOException
60 */
61 public boolean couldContainAnnotationsOnClassDef(DataInput in,
62 Set<String> byteCodeAnnotationsNames)
63 throws IOException
64 {
65 /* According to Java VM Spec, each .class file contains
66 * a single class or interface definition. The structure
67 * definition is shown below:
68
69 ClassFile {
70 u4 magic;
71 u2 minor_version;
72 u2 major_version;
73 u2 constant_pool_count;
74 cp_info constant_pool[constant_pool_count-1];
75 u2 access_flags;
76 u2 this_class;
77 u2 super_class;
78 u2 interfaces_count;
79 u2 interfaces[interfaces_count];
80 u2 fields_count;
81 field_info fields[fields_count];
82 u2 methods_count;
83 method_info methods[methods_count];
84 u2 attributes_count;
85 attribute_info attributes[attributes_count];
86 }
87
88 * u1 = readUnsignedByte
89 * u2 = readUnsignedShort
90 * u4 = readInt
91 *
92 */
93 int magic = in.readInt(); //u4
94
95 if (magic != 0xCAFEBABE)
96 {
97 //the file is not recognized as a class file
98 return false;
99 }
100 //u2 but since in java does not exists unsigned,
101 //store on a bigger value
102 int minorVersion = in.readUnsignedShort();//u2
103 int majorVersion = in.readUnsignedShort();//u2
104
105 if (majorVersion < 49)
106 {
107 //Compiled with jdk 1.4, so does not have annotations
108 return false;
109 }
110
111 //constantsPoolCount is the number of entries + 1
112 //The index goes from 1 to constantsPoolCount-1
113 int constantsPoolCount = in.readUnsignedShort();
114
115 for (int i = 1; i < constantsPoolCount; i++)
116 {
117 // Format:
118 // cp_info {
119 // u1 tag;
120 // u1 info[];
121 // }
122 int tag = in.readUnsignedByte();
123
124 switch (tag)
125 {
126 case CP_INFO_UTF8:
127 //u2 length
128 //u1 bytes[length]
129 //Check if the string is a annotation reference
130 //name
131 String name = in.readUTF();
132 if (byteCodeAnnotationsNames.contains(name))
133 {
134 return true;
135 }
136 break;
137 case CP_INFO_CLASS: //ignore
138 //u2 name_index
139 in.readUnsignedShort();
140 break;
141 case CP_INFO_FIELD_REF: //ignore
142 case CP_INFO_METHOD_REF: //ignore
143 case CP_INFO_INTERFACE_REF: //ignore
144 //u2 class_index
145 //u2 name_and_type_index
146 in.readUnsignedShort();
147 in.readUnsignedShort();
148 break;
149 case CP_INFO_STRING: //ignore
150 //u2 string_index
151 in.readUnsignedShort();
152 break;
153 case CP_INFO_INTEGER: //ignore
154 case CP_INFO_FLOAT: //ignore
155 //u4 bytes
156 in.readInt();
157 break;
158 case CP_INFO_LONG: //ignore
159 case CP_INFO_DOUBLE: //ignore
160 //u4 high_bytes
161 //u4 low_bytes
162 in.readInt();
163 in.readInt();
164 // this tag takes two entries in the constants pool
165 i++;
166 break;
167 case CP_INFO_NAME_AND_TYPE: //ignore
168 //u2 name_index
169 //u2 descriptor_index
170 in.readUnsignedShort();
171 in.readUnsignedShort();
172 break;
173 default:
174 // THIS SHOULD NOT HAPPEN! Log error info
175 // and break for loop, because from this point
176 // we are reading corrupt data.
177 if (log.isLoggable(Level.WARNING))
178 {
179 log.warning("Unknown tag in constants pool: " + tag);
180 }
181 i = constantsPoolCount;
182 break;
183 }
184 }
185 return false;
186 }
187 }