View Javadoc

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 }