Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
_ClassByteCodeAnnotationFilter |
|
| 23.0;23 |
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 | 0 | class _ClassByteCodeAnnotationFilter |
35 | { | |
36 | ||
37 | 0 | 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 | 0 | int magic = in.readInt(); //u4 |
99 | ||
100 | 0 | if (magic != 0xCAFEBABE) |
101 | { | |
102 | //the file is not recognized as a class file | |
103 | 0 | return false; |
104 | } | |
105 | //u2 but since in java does not exists unsigned, | |
106 | //store on a bigger value | |
107 | 0 | int minorVersion = in.readUnsignedShort();//u2 |
108 | 0 | int majorVersion = in.readUnsignedShort();//u2 |
109 | ||
110 | 0 | if (majorVersion < 49) |
111 | { | |
112 | //Compiled with jdk 1.4, so does not have annotations | |
113 | 0 | return false; |
114 | } | |
115 | ||
116 | //constantsPoolCount is the number of entries + 1 | |
117 | //The index goes from 1 to constantsPoolCount-1 | |
118 | 0 | int constantsPoolCount = in.readUnsignedShort(); |
119 | ||
120 | 0 | for (int i = 1; i < constantsPoolCount; i++) |
121 | { | |
122 | // Format: | |
123 | // cp_info { | |
124 | // u1 tag; | |
125 | // u1 info[]; | |
126 | // } | |
127 | 0 | int tag = in.readUnsignedByte(); |
128 | ||
129 | 0 | 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 | 0 | String name = in.readUTF(); |
137 | 0 | if (byteCodeAnnotationsNames.contains(name)) |
138 | { | |
139 | 0 | return true; |
140 | } | |
141 | break; | |
142 | case CP_INFO_CLASS: //ignore | |
143 | //u2 name_index | |
144 | 0 | in.readUnsignedShort(); |
145 | 0 | 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 | 0 | in.readUnsignedShort(); |
152 | 0 | in.readUnsignedShort(); |
153 | 0 | break; |
154 | case CP_INFO_STRING: //ignore | |
155 | //u2 string_index | |
156 | 0 | in.readUnsignedShort(); |
157 | 0 | break; |
158 | case CP_INFO_INTEGER: //ignore | |
159 | case CP_INFO_FLOAT: //ignore | |
160 | //u4 bytes | |
161 | 0 | in.readInt(); |
162 | 0 | break; |
163 | case CP_INFO_LONG: //ignore | |
164 | case CP_INFO_DOUBLE: //ignore | |
165 | //u4 high_bytes | |
166 | //u4 low_bytes | |
167 | 0 | in.readInt(); |
168 | 0 | in.readInt(); |
169 | // this tag takes two entries in the constants pool | |
170 | 0 | i++; |
171 | 0 | break; |
172 | case CP_INFO_NAME_AND_TYPE: //ignore | |
173 | //u2 name_index | |
174 | //u2 descriptor_index | |
175 | 0 | in.readUnsignedShort(); |
176 | 0 | in.readUnsignedShort(); |
177 | 0 | break; |
178 | ||
179 | case CP_INFO_METHOD_HANDLE: // Ignore | |
180 | // u1 reference_kind | |
181 | // u2 reference_index | |
182 | 0 | in.readUnsignedByte(); |
183 | 0 | in.readUnsignedShort(); |
184 | 0 | break; |
185 | ||
186 | case CP_INFO_METHOD_TYPE: // Ignore | |
187 | // u2 descriptor_index | |
188 | 0 | in.readUnsignedShort(); |
189 | 0 | break; |
190 | ||
191 | case CP_INFO_INVOKE_DYNAMIC: // Ignore | |
192 | // u2 bootstrap_method_attr_index; | |
193 | // u2 name_and_type_index; | |
194 | 0 | in.readUnsignedShort(); |
195 | 0 | in.readUnsignedShort(); |
196 | 0 | 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 | 0 | if (log.isLoggable(Level.WARNING)) |
203 | { | |
204 | 0 | log.warning("Unknown tag in constants pool: " + tag); |
205 | } | |
206 | 0 | i = constantsPoolCount; |
207 | break; | |
208 | } | |
209 | } | |
210 | 0 | return false; |
211 | } | |
212 | } |