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: 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 }