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$)
32 * @version $Revision$ $Date$
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 private static final int CP_INFO_METHOD_HANDLE = 15;
53 private static final int CP_INFO_METHOD_TYPE = 16;
54 private static final int CP_INFO_INVOKE_DYNAMIC = 18;
55
56
57 /**
58 * Checks if the .class file referenced by the DataInput could
59 * contain the annotation names available in the set.
60 *
61 * @param in
62 * @param byteCodeAnnotationsNames
63 * @return
64 * @throws IOException
65 */
66 public boolean couldContainAnnotationsOnClassDef(DataInput in,
67 Set<String> byteCodeAnnotationsNames)
68 throws IOException
69 {
70 /* According to Java VM Spec, each .class file contains
71 * a single class or interface definition. The structure
72 * definition is shown below:
73
74 ClassFile {
75 u4 magic;
76 u2 minor_version;
77 u2 major_version;
78 u2 constant_pool_count;
79 cp_info constant_pool[constant_pool_count-1];
80 u2 access_flags;
81 u2 this_class;
82 u2 super_class;
83 u2 interfaces_count;
84 u2 interfaces[interfaces_count];
85 u2 fields_count;
86 field_info fields[fields_count];
87 u2 methods_count;
88 method_info methods[methods_count];
89 u2 attributes_count;
90 attribute_info attributes[attributes_count];
91 }
92
93 * u1 = readUnsignedByte
94 * u2 = readUnsignedShort
95 * u4 = readInt
96 *
97 */
98 int magic = in.readInt(); //u4
99
100 if (magic != 0xCAFEBABE)
101 {
102 //the file is not recognized as a class file
103 return false;
104 }
105 //u2 but since in java does not exists unsigned,
106 //store on a bigger value
107 int minorVersion = in.readUnsignedShort();//u2
108 int majorVersion = in.readUnsignedShort();//u2
109
110 if (majorVersion < 49)
111 {
112 //Compiled with jdk 1.4, so does not have annotations
113 return false;
114 }
115
116 //constantsPoolCount is the number of entries + 1
117 //The index goes from 1 to constantsPoolCount-1
118 int constantsPoolCount = in.readUnsignedShort();
119
120 for (int i = 1; i < constantsPoolCount; i++)
121 {
122 // Format:
123 // cp_info {
124 // u1 tag;
125 // u1 info[];
126 // }
127 int tag = in.readUnsignedByte();
128
129 switch (tag)
130 {
131 case CP_INFO_UTF8:
132 //u2 length
133 //u1 bytes[length]
134 //Check if the string is a annotation reference
135 //name
136 String name = in.readUTF();
137 if (byteCodeAnnotationsNames.contains(name))
138 {
139 return true;
140 }
141 break;
142 case CP_INFO_CLASS: //ignore
143 //u2 name_index
144 in.readUnsignedShort();
145 break;
146 case CP_INFO_FIELD_REF: //ignore
147 case CP_INFO_METHOD_REF: //ignore
148 case CP_INFO_INTERFACE_REF: //ignore
149 //u2 class_index
150 //u2 name_and_type_index
151 in.readUnsignedShort();
152 in.readUnsignedShort();
153 break;
154 case CP_INFO_STRING: //ignore
155 //u2 string_index
156 in.readUnsignedShort();
157 break;
158 case CP_INFO_INTEGER: //ignore
159 case CP_INFO_FLOAT: //ignore
160 //u4 bytes
161 in.readInt();
162 break;
163 case CP_INFO_LONG: //ignore
164 case CP_INFO_DOUBLE: //ignore
165 //u4 high_bytes
166 //u4 low_bytes
167 in.readInt();
168 in.readInt();
169 // this tag takes two entries in the constants pool
170 i++;
171 break;
172 case CP_INFO_NAME_AND_TYPE: //ignore
173 //u2 name_index
174 //u2 descriptor_index
175 in.readUnsignedShort();
176 in.readUnsignedShort();
177 break;
178
179 case CP_INFO_METHOD_HANDLE: // Ignore
180 // u1 reference_kind
181 // u2 reference_index
182 in.readUnsignedByte();
183 in.readUnsignedShort();
184 break;
185
186 case CP_INFO_METHOD_TYPE: // Ignore
187 // u2 descriptor_index
188 in.readUnsignedShort();
189 break;
190
191 case CP_INFO_INVOKE_DYNAMIC: // Ignore
192 // u2 bootstrap_method_attr_index;
193 // u2 name_and_type_index;
194 in.readUnsignedShort();
195 in.readUnsignedShort();
196 break;
197
198 default:
199 // THIS SHOULD NOT HAPPEN! Log error info
200 // and break for loop, because from this point
201 // we are reading corrupt data.
202 if (log.isLoggable(Level.WARNING))
203 {
204 log.warning("Unknown tag in constants pool: " + tag);
205 }
206 i = constantsPoolCount;
207 break;
208 }
209 }
210 return false;
211 }
212 }