javaclass

Changeset

188:fa7d2529c54a
2011-09-18 David Drysdale raw files shortlog changelog graph Add support for Java 1.5 + 1.6 class files. Also add more tests cases, fix some bugs, and check that serialization of loaded class files returns the same as the input.
javaclass/classfile.py (file) tests/Annotation.java (file) tests/AnnotationMarker.java (file) tests/AnnotationTest.java (file) tests/EnclosingMethodTest.java (file) tests/GenericTest.java (file)
     1.1 --- a/javaclass/classfile.py	Thu Mar 24 01:00:49 2011 +0100
     1.2 +++ b/javaclass/classfile.py	Sun Sep 18 20:25:18 2011 +0100
     1.3 @@ -6,6 +6,7 @@
     1.4  
     1.5  Copyright (C) 2004, 2005, 2006, 2011 Paul Boddie <paul@boddie.org.uk>
     1.6  Copyright (C) 2010 Braden Thomas <bradenthomas@me.com>
     1.7 +Copyright (C) 2011 David Drysdale <dmd@lurklurk.org>
     1.8  
     1.9  This program is free software; you can redistribute it and/or modify it under
    1.10  the terms of the GNU Lesser General Public License as published by the Free
    1.11 @@ -537,9 +538,415 @@
    1.12              od += lv.serialize()
    1.13          return od
    1.14  
    1.15 +class LocalVariableTypeAttributeInfo(AttributeInfo):
    1.16 +    def init(self, data, class_file):
    1.17 +        self.class_file = class_file
    1.18 +        self.attribute_length = u4(data[0:4])
    1.19 +        local_variable_type_table_length = u2(data[4:6])
    1.20 +        data = data[6:]
    1.21 +        self.local_variable_type_table = []
    1.22 +        for i in range(0, local_variable_type_table_length):
    1.23 +            local_variable = LocalVariableInfo()
    1.24 +            data = local_variable.init(data, self.class_file)
    1.25 +            self.local_variable_type_table.append(local_variable)
    1.26 +        return data
    1.27 +
    1.28 +    def serialize(self):
    1.29 +        od = su4(self.attribute_length)+su2(len(self.local_variable_type_table))
    1.30 +        od += "".join([lv.serialize() for lv in self.local_variable_type_table])
    1.31 +        return od
    1.32 +
    1.33  class DeprecatedAttributeInfo(AttributeInfo):
    1.34      pass
    1.35  
    1.36 +class VerificationTypeInfo(object):
    1.37 +    def __init__(self, tag):
    1.38 +        self.tag = tag
    1.39 +    def init(self, data, class_file):
    1.40 +        self.class_file = class_file
    1.41 +        tag = u1(data[0:1])
    1.42 +        assert(tag == self.tag)
    1.43 +        return data[1:]
    1.44 +    def serialize(self):
    1.45 +        return su1(self.tag)
    1.46 +class TopVariableInfo(VerificationTypeInfo):
    1.47 +    TAG = 0
    1.48 +class IntegerVariableInfo(VerificationTypeInfo):
    1.49 +    TAG = 1
    1.50 +class FloatVariableInfo(VerificationTypeInfo):
    1.51 +    TAG = 2
    1.52 +class DoubleVariableInfo(VerificationTypeInfo):
    1.53 +    TAG = 3
    1.54 +class LongVariableInfo(VerificationTypeInfo):
    1.55 +    TAG = 4
    1.56 +class NullVariableInfo(VerificationTypeInfo):
    1.57 +    TAG = 5
    1.58 +class UninitializedThisVariableInfo(VerificationTypeInfo):
    1.59 +    TAG = 6
    1.60 +class ObjectVariableInfo(VerificationTypeInfo):
    1.61 +    TAG = 7
    1.62 +    def init(self, data, class_file):
    1.63 +        data = super(ObjectVariableInfo, self).init(data, class_file)
    1.64 +        self.cpool_index = u2(data)
    1.65 +        return data[2:]
    1.66 +    def serialize(self):
    1.67 +        return super(ObjectVariableInfo, self).serialize() + su2(self.cpool_index)
    1.68 +class UninitializedVariableInfo(VerificationTypeInfo):
    1.69 +    TAG = 8
    1.70 +    def init(self, data, class_file):
    1.71 +        data = super(UninitializedVariableInfo, self).init(data, class_file)
    1.72 +        self.offset = u2(data)
    1.73 +        return data[2:]
    1.74 +    def serialize(self):
    1.75 +        return super(UninitializedVariableInfo, self).serialize() + su2(self.offset)
    1.76 +
    1.77 +VARIABLE_INFO_CLASSES = (TopVariableInfo, IntegerVariableInfo, FloatVariableInfo, DoubleVariableInfo,
    1.78 +                         LongVariableInfo, NullVariableInfo, UninitializedThisVariableInfo,
    1.79 +                         ObjectVariableInfo, UninitializedVariableInfo)
    1.80 +VARIABLE_INFO_TAG_MAP = dict([(cls.TAG, cls) for cls in VARIABLE_INFO_CLASSES])
    1.81 +
    1.82 +# Exception
    1.83 +class UnknownVariableInfo:
    1.84 +    def __init__(self, tag):
    1.85 +        self.tag = tag
    1.86 +    def __str__(self):
    1.87 +        return repr(self.tag)
    1.88 +
    1.89 +def create_verification_type_info(data):
    1.90 +    # Does not consume data, just does lookahead
    1.91 +    tag = u1(data[0:1])
    1.92 +    if tag in VARIABLE_INFO_TAG_MAP:
    1.93 +        return VARIABLE_INFO_TAG_MAP[tag](tag)
    1.94 +    else:
    1.95 +        raise UnknownVariableInfo, tag
    1.96 +
    1.97 +
    1.98 +class StackMapFrame(object):
    1.99 +    def __init__(self, frame_type):
   1.100 +        self.frame_type = frame_type
   1.101 +    def init(self, data, class_file):
   1.102 +        self.class_file = class_file
   1.103 +        frame_type = u1(data[0:1])
   1.104 +        assert(frame_type == self.frame_type)
   1.105 +        return data[1:]
   1.106 +    def serialize(self):
   1.107 +        return su1(self.frame_type)
   1.108 +class SameFrame(StackMapFrame):
   1.109 +    TYPE_LOWER = 0
   1.110 +    TYPE_UPPER = 63
   1.111 +class SameLocals1StackItemFrame(StackMapFrame):
   1.112 +    TYPE_LOWER = 64
   1.113 +    TYPE_UPPER = 127
   1.114 +    def init(self, data, class_file):
   1.115 +        data = super(SameLocals1StackItemFrame, self).init(data, class_file)
   1.116 +        self.offset_delta = self.frame_type - 64
   1.117 +        self.stack = [create_verification_type_info(data)]
   1.118 +        return self.stack[0].init(data, class_file)
   1.119 +    def serialize(self):
   1.120 +        return super(SameLocals1StackItemFrame, self).serialize()+self.stack[0].serialize()
   1.121 +class SameLocals1StackItemFrameExtended(StackMapFrame):
   1.122 +    TYPE_LOWER = 247
   1.123 +    TYPE_UPPER = 247
   1.124 +    def init(self, data, class_file):
   1.125 +        data = super(SameLocals1StackItemFrameExtended, self).init(data, class_file)
   1.126 +        self.offset_delta = u2(data[0:2])
   1.127 +        data = data[2:]
   1.128 +        self.stack = [create_verification_type_info(data)]
   1.129 +        return self.stack[0].init(data, class_file)
   1.130 +    def serialize(self):
   1.131 +        return super(SameLocals1StackItemFrameExtended, self).serialize()+su2(self.offset_delta)+self.stack[0].serialize()
   1.132 +class ChopFrame(StackMapFrame):
   1.133 +    TYPE_LOWER = 248
   1.134 +    TYPE_UPPER = 250
   1.135 +    def init(self, data, class_file):
   1.136 +        data = super(ChopFrame, self).init(data, class_file)
   1.137 +        self.offset_delta = u2(data[0:2])
   1.138 +        return data[2:]
   1.139 +    def serialize(self):
   1.140 +        return super(ChopFrame, self).serialize()+su2(self.offset_delta)
   1.141 +class SameFrameExtended(StackMapFrame):
   1.142 +    TYPE_LOWER = 251
   1.143 +    TYPE_UPPER = 251
   1.144 +    def init(self, data, class_file):
   1.145 +        data = super(SameFrameExtended, self).init(data, class_file)
   1.146 +        self.offset_delta = u2(data[0:2])
   1.147 +        return data[2:]
   1.148 +    def serialize(self):
   1.149 +        return super(SameFrameExtended, self).serialize()+su2(self.offset_delta)
   1.150 +class AppendFrame(StackMapFrame):
   1.151 +    TYPE_LOWER = 252
   1.152 +    TYPE_UPPER = 254
   1.153 +    def init(self, data, class_file):
   1.154 +        data = super(AppendFrame, self).init(data, class_file)
   1.155 +        self.offset_delta = u2(data[0:2])
   1.156 +        data = data[2:]
   1.157 +        num_locals = self.frame_type - 251
   1.158 +        self.locals = []
   1.159 +        for ii in xrange(num_locals):
   1.160 +            info = create_verification_type_info(data)
   1.161 +            data = info.init(data, class_file)
   1.162 +            self.locals.append(info)
   1.163 +        return data
   1.164 +    def serialize(self):
   1.165 +        od = super(AppendFrame, self).serialize()+su2(self.offset_delta)
   1.166 +        od += "".join([l.serialize() for l in self.locals])
   1.167 +        return od
   1.168 +class FullFrame(StackMapFrame):
   1.169 +    TYPE_LOWER = 255
   1.170 +    TYPE_UPPER = 255
   1.171 +    def init(self, data, class_file):
   1.172 +        data = super(FullFrame, self).init(data, class_file)
   1.173 +        self.offset_delta = u2(data[0:2])
   1.174 +        num_locals = u2(data[2:4])
   1.175 +        data = data[4:]
   1.176 +        self.locals = []
   1.177 +        for ii in xrange(num_locals):
   1.178 +            info = create_verification_type_info(data)
   1.179 +            data = info.init(data, class_file)
   1.180 +            self.locals.append(info)
   1.181 +        num_stack_items = u2(data[0:2])
   1.182 +        data = data[2:]
   1.183 +        self.stack = []
   1.184 +        for ii in xrange(num_stack_items):
   1.185 +            stack_item = create_verification_type_info(data)
   1.186 +            data = stack_item.init(data, class_file)
   1.187 +            self.stack.append(stack_item)
   1.188 +        return data
   1.189 +    def serialize(self):
   1.190 +        od = super(FullFrame, self).serialize()+su2(self.offset_delta)+su2(len(self.locals))
   1.191 +        od += "".join([l.serialize() for l in self.locals])
   1.192 +        od += su2(len(self.stack))
   1.193 +        od += "".join([s.serialize() for s in self.stack])
   1.194 +        return od
   1.195 +
   1.196 +FRAME_CLASSES = (SameFrame, SameLocals1StackItemFrame, SameLocals1StackItemFrameExtended,
   1.197 +                 ChopFrame, SameFrameExtended, AppendFrame, FullFrame)
   1.198 +
   1.199 +# Exception
   1.200 +class UnknownStackFrame:
   1.201 +    def __init__(self, frame_type):
   1.202 +        self.frame_type = frame_type
   1.203 +    def __str__(self):
   1.204 +        return repr(self.frame_type)
   1.205 +
   1.206 +def create_stack_frame(data):
   1.207 +    # Does not consume data, just does lookahead
   1.208 +    frame_type = u1(data[0:1])
   1.209 +    for cls in FRAME_CLASSES:
   1.210 +        if frame_type >= cls.TYPE_LOWER and frame_type <= cls.TYPE_UPPER:
   1.211 +            return cls(frame_type)
   1.212 +    raise UnknownStackFrame, frame_type
   1.213 +
   1.214 +class StackMapTableAttributeInfo(AttributeInfo):
   1.215 +    def init(self, data, class_file):
   1.216 +        self.class_file = class_file
   1.217 +        self.attribute_length = u4(data[0:4])
   1.218 +        num_entries = u2(data[4:6])
   1.219 +        self.entries = []
   1.220 +        data = data[6:]
   1.221 +        for i in range(0, num_entries):
   1.222 +            frame = create_stack_frame(data)
   1.223 +            data = frame.init(data, class_file)
   1.224 +            self.entries.append(frame)
   1.225 +        return data
   1.226 +    def serialize(self):
   1.227 +        od = su4(self.attribute_length)+su2(len(self.entries))
   1.228 +        od += "".join([e.serialize() for e in self.entries])
   1.229 +        return od
   1.230 +
   1.231 +
   1.232 +class EnclosingMethodAttributeInfo(AttributeInfo):
   1.233 +    def init(self, data, class_file):
   1.234 +        self.class_file = class_file
   1.235 +        self.attribute_length = u4(data[0:4])
   1.236 +        self.class_index = u2(data[4:6])
   1.237 +        self.method_index = u2(data[6:8])
   1.238 +        return data[8:]
   1.239 +    def serialize(self):
   1.240 +        return su4(self.attribute_length)+su2(self.class_index)+su2(self.method_index)
   1.241 +
   1.242 +
   1.243 +class SignatureAttributeInfo(AttributeInfo):
   1.244 +    def init(self, data, class_file):
   1.245 +        self.class_file = class_file
   1.246 +        self.attribute_length = u4(data[0:4])
   1.247 +        self.signature_index = u2(data[4:6])
   1.248 +        return data[6:]
   1.249 +    def serialize(self):
   1.250 +        return su4(self.attribute_length)+su2(self.signature_index)
   1.251 +
   1.252 +
   1.253 +class SourceDebugExtensionAttributeInfo(AttributeInfo):
   1.254 +    def init(self, data, class_file):
   1.255 +        self.class_file = class_file
   1.256 +        self.attribute_length = u4(data[0:4])
   1.257 +        self.debug_extension = data[4:(4 + self.attribute_length)]
   1.258 +        return data[(4+ self.attribute_length):]
   1.259 +    def serialize(self):
   1.260 +        return su4(self.attribute_length)+self.debug_extension
   1.261 +
   1.262 +
   1.263 +class ElementValue(object):
   1.264 +    def __init__(self, tag):
   1.265 +        self.tag = tag
   1.266 +    def init(self, data, class_file):
   1.267 +        self.class_file = class_file
   1.268 +        tag = chr(u1(data[0:1]))
   1.269 +        assert(tag == self.tag)
   1.270 +        return data[1:]
   1.271 +    def serialize(self):
   1.272 +        return su1(ord(self.tag))
   1.273 +class ConstValue(ElementValue):
   1.274 +    def init(self, data, class_file):
   1.275 +        data = super(ConstValue, self).init(data, class_file)
   1.276 +        self.const_value_index = u2(data[0:2])
   1.277 +        return data[2:]
   1.278 +    def serialize(self):
   1.279 +        return super(ConstValue, self).serialize()+su2(self.const_value_index)
   1.280 +class EnumConstValue(ElementValue):
   1.281 +    def init(self, data, class_file):
   1.282 +        data = super(EnumConstValue, self).init(data, class_file)
   1.283 +        self.type_name_index = u2(data[0:2])
   1.284 +        self.const_name_index = u2(data[2:4])
   1.285 +        return data[4:]
   1.286 +    def serialize(self):
   1.287 +        return super(EnumConstValue, self).serialize()+su2(self.type_name_index)+su2(self.const_name_index)
   1.288 +class ClassInfoValue(ElementValue):
   1.289 +    def init(self, data, class_file):
   1.290 +        data = super(ClassInfoValue, self).init(data, class_file)
   1.291 +        self.class_info_index = u2(data[0:2])
   1.292 +        return data[2:]
   1.293 +    def serialize(self):
   1.294 +        return super(ClassInfoValue, self).serialize()+su2(self.class_info_index)
   1.295 +class AnnotationValue(ElementValue):
   1.296 +    def init(self, data, class_file):
   1.297 +        data = super(AnnotationValue, self).init(data, class_file)
   1.298 +        self.annotation_value = Annotation()
   1.299 +        return self.annotation_value.init(data, class_file)
   1.300 +    def serialize(self):
   1.301 +        return super(AnnotationValue, self).serialize()+self.annotation_value.serialize()
   1.302 +class ArrayValue(ElementValue):
   1.303 +    def init(self, data, class_file):
   1.304 +        data = super(ArrayValue, self).init(data, class_file)
   1.305 +        num_values = u2(data[0:2])
   1.306 +        data = data[2:]
   1.307 +        self.values = []
   1.308 +        for ii in xrange(num_values):
   1.309 +            element_value = create_element_value(data)
   1.310 +            data = element_value.init(data, class_file)
   1.311 +            self.values.append(element_value)
   1.312 +        return data
   1.313 +    def serialize(self):
   1.314 +        od = super(ArrayValue, self).serialize()+su2(len(self.values))
   1.315 +        od += "".join([v.serialize() for v in self.values])
   1.316 +        return od
   1.317 +# Exception
   1.318 +class UnknownElementValue:
   1.319 +    def __init__(self, tag):
   1.320 +        self.tag = tag
   1.321 +    def __str__(self):
   1.322 +        return repr(self.tag)
   1.323 +
   1.324 +def create_element_value(data):
   1.325 +    tag = chr(u1(data[0:1]))
   1.326 +    if tag in ('B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 's'):
   1.327 +        return ConstValue(tag)
   1.328 +    elif tag == 'e':
   1.329 +        return EnumConstValue(tag)
   1.330 +    elif tag == 'c':
   1.331 +        return ClassInfoValue(tag)
   1.332 +    elif tag == '@':
   1.333 +        return AnnotationValue(tag)
   1.334 +    elif tag == '[':
   1.335 +        return ArrayValue(tag)
   1.336 +    else:
   1.337 +        raise UnknownElementValue, tag
   1.338 +    
   1.339 +
   1.340 +class Annotation(object):
   1.341 +    def init(self, data, class_file):
   1.342 +        self.class_file = class_file
   1.343 +        self.type_index = u2(data[0:2])
   1.344 +        num_element_value_pairs = u2(data[2:4])
   1.345 +        data = data[4:]
   1.346 +        self.element_value_pairs = []
   1.347 +        for ii in xrange(num_element_value_pairs):
   1.348 +            element_name_index = u2(data[0:2])
   1.349 +            data = data[2:]
   1.350 +            element_value = create_element_value(data)
   1.351 +            data = element_value.init(data, class_file)
   1.352 +            self.element_value_pairs.append((element_name_index, element_value))
   1.353 +        return data
   1.354 +    def serialize(self):
   1.355 +        od = su2(self.type_index)+su2(len(self.element_value_pairs))
   1.356 +        od += "".join([su2(evp[0])+evp[1].serialize() for evp in self.element_value_pairs])
   1.357 +        return od
   1.358 +
   1.359 +
   1.360 +class RuntimeAnnotationsAttributeInfo(AttributeInfo):
   1.361 +    def init(self, data, class_file):
   1.362 +        self.class_file = class_file
   1.363 +        self.attribute_length = u4(data[0:4])
   1.364 +        num_annotations = u2(data[4:6])
   1.365 +        data = data[6:]
   1.366 +        self.annotations = []
   1.367 +        for ii in xrange(num_annotations):
   1.368 +            annotation = Annotation() 
   1.369 +            data = annotation.init(data, class_file)
   1.370 +            self.annotations.append(annotation)
   1.371 +        return data
   1.372 +    def serialize(self):
   1.373 +        od = su4(self.attribute_length)+su2(len(self.annotations))
   1.374 +        od += "".join([a.serialize() for a in self.annotations])
   1.375 +        return od
   1.376 +
   1.377 +class RuntimeVisibleAnnotationsAttributeInfo(RuntimeAnnotationsAttributeInfo):
   1.378 +    pass
   1.379 +
   1.380 +class RuntimeInvisibleAnnotationsAttributeInfo(RuntimeAnnotationsAttributeInfo):
   1.381 +    pass
   1.382 +
   1.383 +class RuntimeParameterAnnotationsAttributeInfo(AttributeInfo):
   1.384 +    def init(self, data, class_file):
   1.385 +        self.class_file = class_file
   1.386 +        self.attribute_length = u4(data[0:4])
   1.387 +        num_parameters = u1(data[4:5])
   1.388 +        data = data[5:]
   1.389 +        self.parameter_annotations = []
   1.390 +        for ii in xrange(num_parameters):
   1.391 +            num_annotations = u2(data[0:2])
   1.392 +            data = data[2:]
   1.393 +            annotations = []
   1.394 +            for jj in xrange(num_annotations):
   1.395 +                annotation = Annotation() 
   1.396 +                data = annotation.init(data, class_file)
   1.397 +                annotations.append(annotation)
   1.398 +            self.parameter_annotations.append(annotations)
   1.399 +        return data
   1.400 +    def serialize(self):
   1.401 +        od = su4(self.attribute_length)+su1(len(self.parameter_annotations))
   1.402 +        for pa in self.parameter_annotations:
   1.403 +            od += su2(len(pa))
   1.404 +            od += "".join([a.serialize() for a in pa])
   1.405 +        return od
   1.406 +        
   1.407 +class RuntimeVisibleParameterAnnotationsAttributeInfo(RuntimeParameterAnnotationsAttributeInfo):
   1.408 +    pass
   1.409 +
   1.410 +class RuntimeInvisibleParameterAnnotationsAttributeInfo(RuntimeParameterAnnotationsAttributeInfo):
   1.411 +    pass
   1.412 +
   1.413 +class AnnotationDefaultAttributeInfo(AttributeInfo):
   1.414 +    def init(self, data, class_file):
   1.415 +        self.class_file = class_file
   1.416 +        self.attribute_length = u4(data[0:4])
   1.417 +        data = data[4:]
   1.418 +        self.default_value = create_element_value(data)
   1.419 +        return self.default_value.init(data, class_file)
   1.420 +    def serialize(self):
   1.421 +        return su4(self.attribute_length)+self.default_value.serialize()
   1.422 +
   1.423 +
   1.424  # Child classes of the attribute information classes.
   1.425  
   1.426  class ExceptionInfo:
   1.427 @@ -592,11 +999,45 @@
   1.428  # Exceptions.
   1.429  
   1.430  class UnknownTag(Exception):
   1.431 -    pass
   1.432 +    def __init__(self, tag):
   1.433 +        self.tag = tag
   1.434 +    def __str__(self):
   1.435 +        return repr(self.tag)
   1.436  
   1.437  class UnknownAttribute(Exception):
   1.438 -    pass
   1.439 +    def __init__(self, name):
   1.440 +        self.name = name
   1.441  
   1.442 +ATTR_NAMES_TO_CLASS = {"SourceFile": SourceFileAttributeInfo, 
   1.443 +                       "ConstantValue": ConstantValueAttributeInfo, 
   1.444 +                       "Code": CodeAttributeInfo, 
   1.445 +                       "Exceptions": ExceptionsAttributeInfo,
   1.446 +                       "InnerClasses": InnerClassesAttributeInfo, 
   1.447 +                       "Synthetic": SyntheticAttributeInfo,
   1.448 +                       "LineNumberTable": LineNumberAttributeInfo, 
   1.449 +                       "LocalVariableTable": LocalVariableAttributeInfo, 
   1.450 +                       "Deprecated": DeprecatedAttributeInfo,
   1.451 +                       # Java SE 1.6, class file >= 50.0, VMSpec v3 s4.7.4
   1.452 +                       "StackMapTable": StackMapTableAttributeInfo,
   1.453 +                       # Java SE 1.5, class file >= 49.0, VMSpec v3  s4.7.7
   1.454 +                       "EnclosingMethod": EnclosingMethodAttributeInfo,
   1.455 +                       # Java SE 1.5, class file >= 49.0, VMSpec v3  s4.7.9
   1.456 +                       "Signature": SignatureAttributeInfo,
   1.457 +                       # Java SE 1.5, class file >= 49.0, VMSpec v3  s4.7.11
   1.458 +                       "SourceDebugExtension": SourceDebugExtensionAttributeInfo,
   1.459 +                       # Java SE 1.5, class file >= 49.0, VMSpec v3  s4.7.14
   1.460 +                       "LocalVariableTypeTable": LocalVariableTypeAttributeInfo,
   1.461 +                       # Java SE 1.5, class file >= 49.0, VMSpec v3  s4.7.16
   1.462 +                       "RuntimeVisibleAnnotations": RuntimeVisibleAnnotationsAttributeInfo,
   1.463 +                       # Java SE 1.5, class file >= 49.0, VMSpec v3  s4.7.17
   1.464 +                       "RuntimeInvisibleAnnotations": RuntimeInvisibleAnnotationsAttributeInfo,
   1.465 +                       # Java SE 1.5, class file >= 49.0, VMSpec v3  s4.7.18
   1.466 +                       "RuntimeVisibleParameterAnnotations": RuntimeVisibleParameterAnnotationsAttributeInfo,
   1.467 +                       # Java SE 1.5, class file >= 49.0, VMSpec v3  s4.7.19
   1.468 +                       "RuntimeInvisibleParameterAnnotations": RuntimeInvisibleParameterAnnotationsAttributeInfo,
   1.469 +                       # Java SE 1.5, class file >= 49.0, VMSpec v3  s4.7.20
   1.470 +                       "AnnotationDefault": AnnotationDefaultAttributeInfo,}
   1.471 +                       
   1.472  # Abstractions for the main structures.
   1.473  
   1.474  class ClassFile:
   1.475 @@ -611,6 +1052,9 @@
   1.476          """
   1.477  
   1.478          self.attribute_class_to_index = None
   1.479 +        magic = u4(s[0:])
   1.480 +        if magic != 0xCAFEBABE:
   1.481 +            raise UnknownAttribute, magic
   1.482          self.minorv,self.majorv = u2(s[4:]),u2(s[6:])
   1.483          self.constants, s = self._get_constants(s[8:])
   1.484          self.access_flags, s = self._get_access_flags(s)
   1.485 @@ -651,10 +1095,10 @@
   1.486              od += su1(8)
   1.487          elif isinstance(c, FieldRefInfo):
   1.488              od += su1(9)
   1.489 +        elif isinstance(c, InterfaceMethodRefInfo):  # check subclass first
   1.490 +            od += su1(11)
   1.491          elif isinstance(c, MethodRefInfo):
   1.492              od += su1(10)
   1.493 -        elif isinstance(c, InterfaceMethodRefInfo):
   1.494 -            od += su1(11)
   1.495          elif isinstance(c, NameAndTypeInfo):
   1.496              od += su1(12)
   1.497          else:
   1.498 @@ -725,24 +1169,8 @@
   1.499      def _get_attribute_from_table(self, s):
   1.500          attribute_name_index = u2(s[0:2])
   1.501          constant_name = self.constants[attribute_name_index - 1].bytes
   1.502 -        if constant_name == "SourceFile":
   1.503 -            attribute = SourceFileAttributeInfo()
   1.504 -        elif constant_name == "ConstantValue":
   1.505 -            attribute = ConstantValueAttributeInfo()
   1.506 -        elif constant_name == "Code":
   1.507 -            attribute = CodeAttributeInfo()
   1.508 -        elif constant_name == "Exceptions":
   1.509 -            attribute = ExceptionsAttributeInfo()
   1.510 -        elif constant_name == "InnerClasses":
   1.511 -            attribute = InnerClassesAttributeInfo()
   1.512 -        elif constant_name == "Synthetic":
   1.513 -            attribute = SyntheticAttributeInfo()
   1.514 -        elif constant_name == "LineNumberTable":
   1.515 -            attribute = LineNumberAttributeInfo()
   1.516 -        elif constant_name == "LocalVariableTable":
   1.517 -            attribute = LocalVariableAttributeInfo()
   1.518 -        elif constant_name == "Deprecated":
   1.519 -            attribute = DeprecatedAttributeInfo()
   1.520 +        if constant_name in ATTR_NAMES_TO_CLASS:
   1.521 +            attribute = ATTR_NAMES_TO_CLASS[constant_name]()
   1.522          else:
   1.523              raise UnknownAttribute, constant_name
   1.524          s = attribute.init(s[2:], self)
   1.525 @@ -796,7 +1224,7 @@
   1.526          return interfaces, s
   1.527  
   1.528      def _serialize_interfaces(self):
   1.529 -        return su2(len(self.interfaces))+"".join([su2(self.interfaces.index(interf)+1) for interf in self.interfaces])
   1.530 +        return su2(len(self.interfaces))+"".join([su2(self.constants.index(interf)+1) for interf in self.interfaces])
   1.531  
   1.532      def _get_fields(self, s):
   1.533          number = u2(s[0:2])
   1.534 @@ -816,16 +1244,11 @@
   1.535          if len(attrs) == 0: return od
   1.536          if self.attribute_class_to_index == None:
   1.537              self.attribute_class_to_index = {}
   1.538 -            attr_names_to_class = {"SourceFile":SourceFileAttributeInfo, "ConstantValue":ConstantValueAttributeInfo, 
   1.539 -                            "Code":CodeAttributeInfo, "Exceptions":ExceptionsAttributeInfo,
   1.540 -                            "InnerClasses":InnerClassesAttributeInfo, "Synthetic":SyntheticAttributeInfo,
   1.541 -                            "LineNumberTable":LineNumberAttributeInfo, "LocalVariableTable":LocalVariableAttributeInfo, 
   1.542 -                            "Deprecated":DeprecatedAttributeInfo}
   1.543              index = 0
   1.544              for c in self.constants:
   1.545                  index += 1
   1.546 -                if isinstance(c, Utf8Info) and str(c) in attr_names_to_class.keys():
   1.547 -                    self.attribute_class_to_index[attr_names_to_class[str(c)]]=index
   1.548 +                if isinstance(c, Utf8Info) and str(c) in ATTR_NAMES_TO_CLASS.keys():
   1.549 +                    self.attribute_class_to_index[ATTR_NAMES_TO_CLASS[str(c)]]=index
   1.550          for attribute in attrs:
   1.551              for (classtype,name_index) in self.attribute_class_to_index.iteritems():
   1.552                  if isinstance(attribute, classtype):
   1.553 @@ -847,7 +1270,10 @@
   1.554  if __name__ == "__main__":
   1.555      import sys
   1.556      f = open(sys.argv[1], "rb")
   1.557 -    c = ClassFile(f.read())
   1.558 +    in_data = f.read()
   1.559 +    c = ClassFile(in_data)
   1.560      f.close()
   1.561 +    out_data = c.serialize()
   1.562 +    assert(in_data == out_data)
   1.563  
   1.564  # vim: tabstop=4 expandtab shiftwidth=4
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tests/Annotation.java	Sun Sep 18 20:25:18 2011 +0100
     2.3 @@ -0,0 +1,5 @@
     2.4 +
     2.5 +public @interface Annotation {
     2.6 +  int a() default 99;
     2.7 +  String b();
     2.8 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tests/AnnotationMarker.java	Sun Sep 18 20:25:18 2011 +0100
     3.3 @@ -0,0 +1,5 @@
     3.4 +import java.lang.annotation.*;
     3.5 +
     3.6 +@Retention(RetentionPolicy.RUNTIME)
     3.7 +@Target(ElementType.METHOD)
     3.8 +public @interface AnnotationMarker {}
\ No newline at end of file
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tests/AnnotationTest.java	Sun Sep 18 20:25:18 2011 +0100
     4.3 @@ -0,0 +1,14 @@
     4.4 +
     4.5 +class AnnotationTest {
     4.6 +  @Annotation(a=1, b="foo")
     4.7 +  public static void hello() {
     4.8 +  }
     4.9 +  @AnnotationMarker
    4.10 +  private static int getx() {
    4.11 +    return 1;
    4.12 +  }
    4.13 +  private static int addup(@Annotation(b="param") int x, 
    4.14 +                           int y) {
    4.15 +    return x+y;
    4.16 +  }
    4.17 +}
\ No newline at end of file
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tests/EnclosingMethodTest.java	Sun Sep 18 20:25:18 2011 +0100
     5.3 @@ -0,0 +1,12 @@
     5.4 +public class EnclosingMethodTest {
     5.5 +  public int outer(int a) {
     5.6 +    class InnerClass {
     5.7 +      public int inner(int b) {
     5.8 +        return b+1;
     5.9 +      }
    5.10 +    }
    5.11 +    InnerClass inc = new InnerClass();
    5.12 +    return inc.inner(a);
    5.13 +  }
    5.14 +}
    5.15 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tests/GenericTest.java	Sun Sep 18 20:25:18 2011 +0100
     6.3 @@ -0,0 +1,9 @@
     6.4 +import java.util.List;
     6.5 +import java.util.ArrayList;
     6.6 +class GenericTest<T> {
     6.7 +  public T mT;
     6.8 +  public GenericTest(T t) {
     6.9 +    mT = t;
    6.10 +    List<T> l = new ArrayList<T>();
    6.11 +  }
    6.12 +}
\ No newline at end of file