All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opalj.bc.Assembler.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package bc

import scala.annotation.switch
import java.io.ByteArrayOutputStream
import java.io.DataOutputStream

import org.opalj.bc.MethodFilter.logContext
import org.opalj.bi.ACC_STRICT
import org.opalj.bi.{ConstantPoolTags => CPTags}
import org.opalj.da._
import org.opalj.da.ClassFileReader.LineNumberTable_attribute
import org.opalj.log.OPALLogger

/**
 * Factory to create the binary representation (that is, an array of bytes) of a given class file.
 *
 * @author Michael Eichberg
 */
object Assembler {

    private[bc] def as[T](x: AnyRef): T = x.asInstanceOf[T]

    implicit object RichCONSTANT_Class_info extends ClassFileElement[CONSTANT_Class_info] {
        def write(
            ci: CONSTANT_Class_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeShort(name_index)
        }
    }

    implicit object RichCONSTANT_Ref extends ClassFileElement[CONSTANT_Ref] {
        def write(
            cr: CONSTANT_Ref
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import cr._
            import out._
            writeByte(tag)
            writeShort(class_index)
            writeShort(name_and_type_index)
        }
    }

    implicit object RichCONSTANT_String_info extends ClassFileElement[CONSTANT_String_info] {
        def write(
            ci: CONSTANT_String_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeShort(string_index)
        }
    }

    implicit object RichCONSTANT_Integer_info extends ClassFileElement[CONSTANT_Integer_info] {
        def write(
            ci: CONSTANT_Integer_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeInt(value)
        }
    }

    implicit object RichCONSTANT_Float_info extends ClassFileElement[CONSTANT_Float_info] {
        def write(
            ci: CONSTANT_Float_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeFloat(value)
        }
    }

    implicit object RichCONSTANT_Long_info extends ClassFileElement[CONSTANT_Long_info] {
        def write(
            ci: CONSTANT_Long_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeLong(value)
        }
    }

    implicit object RichCONSTANT_Double_info extends ClassFileElement[CONSTANT_Double_info] {
        def write(
            ci: CONSTANT_Double_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeDouble(value)
        }
    }

    implicit object RichCONSTANT_NameAndType_info
        extends ClassFileElement[CONSTANT_NameAndType_info] {
        def write(
            ci: CONSTANT_NameAndType_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeShort(name_index)
            writeShort(descriptor_index)

        }
    }

    implicit object RichCONSTANT_Utf8_info
        extends ClassFileElement[CONSTANT_Utf8_info] {
        def write(
            ci: CONSTANT_Utf8_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeUTF(value)
        }
    }

    implicit object RichCONSTANT_MethodHandle_info
        extends ClassFileElement[CONSTANT_MethodHandle_info] {
        def write(
            ci: CONSTANT_MethodHandle_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeByte(reference_kind)
            writeShort(reference_index)
        }
    }

    implicit object RichCONSTANT_MethodType_info
        extends ClassFileElement[CONSTANT_MethodType_info] {
        def write(
            ci: CONSTANT_MethodType_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeShort(descriptor_index)
        }
    }

    implicit object RichCONSTANT_InvokeDynamic_info
        extends ClassFileElement[CONSTANT_InvokeDynamic_info] {
        def write(
            ci: CONSTANT_InvokeDynamic_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeShort(bootstrap_method_attr_index)
            writeShort(name_and_type_index)
        }
    }

    implicit object RichCONSTANT_Module_info extends ClassFileElement[CONSTANT_Module_info] {
        def write(
            ci: CONSTANT_Module_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeShort(name_index)
        }
    }

    implicit object RichCONSTANT_Package_info extends ClassFileElement[CONSTANT_Package_info] {
        def write(
            ci: CONSTANT_Package_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeShort(name_index)
        }
    }

    implicit object RichCONSTANT_Dynamic_info extends ClassFileElement[CONSTANT_Dynamic_info] {
        def write(
            ci: CONSTANT_Dynamic_info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import ci._
            import out._
            writeByte(tag)
            writeShort(bootstrap_method_attr_index)
            writeShort(name_and_type_index)
        }
    }

    implicit object RichConstant_Pool_Entry extends ClassFileElement[Constant_Pool_Entry] {
        def write(
            cpe: Constant_Pool_Entry
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            cpe.Constant_Type_Value.id match {
                case CPTags.CONSTANT_Utf8_ID        => serializeAs[CONSTANT_Utf8_info](cpe)
                case CPTags.CONSTANT_Class_ID       => serializeAs[CONSTANT_Class_info](cpe)
                case CPTags.CONSTANT_String_ID      => serializeAs[CONSTANT_String_info](cpe)
                case CPTags.CONSTANT_Integer_ID     => serializeAs[CONSTANT_Integer_info](cpe)
                case CPTags.CONSTANT_Float_ID       => serializeAs[CONSTANT_Float_info](cpe)
                case CPTags.CONSTANT_Long_ID        => serializeAs[CONSTANT_Long_info](cpe)
                case CPTags.CONSTANT_Double_ID      => serializeAs[CONSTANT_Double_info](cpe)
                case CPTags.CONSTANT_NameAndType_ID => serializeAs[CONSTANT_NameAndType_info](cpe)
                case CPTags.CONSTANT_Fieldref_ID |
                    CPTags.CONSTANT_Methodref_ID |
                    CPTags.CONSTANT_InterfaceMethodref_ID => serializeAs[CONSTANT_Ref](cpe)

                // JAVA 7
                case CPTags.CONSTANT_MethodHandle_ID =>
                    serializeAs[CONSTANT_MethodHandle_info](cpe)
                case CPTags.CONSTANT_MethodType_ID =>
                    serializeAs[CONSTANT_MethodType_info](cpe)
                case CPTags.CONSTANT_InvokeDynamic_ID =>
                    serializeAs[CONSTANT_InvokeDynamic_info](cpe)

                // JAVA 9
                case CPTags.CONSTANT_Module_ID  => serializeAs[CONSTANT_Module_info](cpe)
                case CPTags.CONSTANT_Package_ID => serializeAs[CONSTANT_Package_info](cpe)

                // JAVA 11
                case CPTags.CONSTANT_Dynamic_ID => serializeAs[CONSTANT_Dynamic_info](cpe)
            }
        }
    }

    implicit object RichElementValue extends ClassFileElement[ElementValue] {
        def write(
            ev: ElementValue
        )(
            implicit
            out:                DataOutputStream,
            segmentInformation: (String, Int) => Unit
        ): Unit = {
            import out._
            val tag = ev.tag
            writeByte(tag)
            tag match {
                case 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' =>
                    writeShort(as[BaseElementValue](ev).const_value_index)
                case 's' =>
                    writeShort(as[StringValue](ev).const_value_index)
                case 'e' =>
                    val e = as[EnumValue](ev)
                    writeShort(e.type_name_index)
                    writeShort(e.const_name_index)
                case 'c' =>
                    writeShort(as[ClassValue](ev).class_info_index)
                case '@' =>
                    val av = as[AnnotationValue](ev)
                    serialize(av.annotation)(RichAnnotation, out, segmentInformation)
                case '[' =>
                    val av = as[ArrayValue](ev)
                    writeShort(av.values.length)
                    av.values.foreach { serialize(_) }
            }
        }
    }

    implicit object RichAnnotation extends ClassFileElement[Annotation] {
        def write(
            a: Annotation
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import a._
            import out._
            writeShort(type_index)
            writeShort(element_value_pairs.length)
            element_value_pairs.foreach { evp =>
                writeShort(evp.element_name_index)
                serialize(evp.element_value)
            }
        }
    }

    implicit object RichTypeAnnotation extends ClassFileElement[TypeAnnotation] {
        def write(
            ta: TypeAnnotation
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import out._
            val target_type = ta.target_type
            val target_typeTag = target_type.tag
            writeByte(target_typeTag)
            (target_typeTag: @switch) match {
                case 0x00 | 0x01 =>
                    val tt = as[TATTypeParameter](target_type)
                    writeByte(tt.type_parameter_index)

                case 0x10 =>
                    val tt = as[TATSupertype](target_type)
                    writeShort(tt.supertype_index)

                case 0x11 | 0x12 =>
                    val tt = as[TATTypeParameterBound](target_type)
                    writeByte(tt.type_parameter_index)
                    writeByte(tt.bound_index)

                case 0x16 =>
                    val tt = as[TATFormalParameter](target_type)
                    writeByte(tt.formal_parameter_index)

                case 0x17 =>
                    val TATThrows(throws_type_index) = target_type
                    writeShort(throws_type_index)

                case 0x40 | 0x41 =>
                    val tt = as[TATLocalvar](target_type)
                    val lvt = tt.localvarTable
                    writeShort(lvt.length)
                    lvt.foreach { lvte =>
                        writeShort(lvte.start_pc)
                        writeShort(lvte.length)
                        writeShort(lvte.index)
                    }

                case 0x42 =>
                    val tt = as[TATCatch](target_type)
                    writeShort(tt.exception_table_index)

                case 0x43 | 0x44 | 0x45 | 0x46 =>
                    val tt = as[TATWithOffset](target_type)
                    writeShort(tt.offset)

                case 0x47 | 0x48 | 0x49 | 0x4A | 0x4B =>
                    val tt = as[TATTypeArgument](target_type)
                    writeShort(tt.offset)
                    writeByte(tt.type_argument_index)

                case 0x13 | 0x14 | 0x15 =>
                // EMPTY_TARGET <=> Nothing to do

            }

            ta.target_path match {
                case TypeAnnotationDirectlyOnType =>
                    writeByte(0)

                case TypeAnnotationPathElements(elements) =>
                    writeByte(elements.length)
                    elements.foreach { tape =>
                        writeByte(tape.type_path_kind)
                        writeByte(tape.type_argument_index)
                    }
            }

            writeShort(ta.type_index)
            val evps = ta.element_value_pairs
            writeShort(evps.length)
            evps.foreach { evp =>
                writeShort(evp.element_name_index)
                serialize(evp.element_value)
            }

        }
    }

    implicit object RichVerificationTypeInfo extends ClassFileElement[VerificationTypeInfo] {
        def write(
            vti: VerificationTypeInfo
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import out._
            val tag = vti.tag
            (tag: @scala.annotation.switch) match {
                case VerificationTypeInfo.ITEM_Object =>
                    val ovi = as[ObjectVariableInfo](vti)
                    writeByte(tag)
                    writeShort(ovi.cpool_index)
                case VerificationTypeInfo.ITEM_Unitialized =>
                    val uvi = as[UninitializedVariableInfo](vti)
                    writeByte(tag)
                    writeShort(uvi.offset)
                case _ =>
                    writeByte(tag)
            }

        }
    }

    implicit object RichAttribute extends ClassFileElement[Attribute] {
        def write(
            a: Attribute
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import a._
            import out._
            writeShort(attribute_name_index)
            writeInt(attribute_length)
            a match {

                case a: TypeAnnotations_attribute =>
                    // Handles:
                    // RuntimeVisibleTypeAnnotations_attribute
                    // RuntimeInvisibleTypeAnnotations_attribute
                    writeShort(a.typeAnnotations.size)
                    a.typeAnnotations.foreach { serialize(_) }

                case a: StackMapTable_attribute =>
                    writeShort(a.stack_map_frames.length)
                    a.stack_map_frames.foreach { smf =>
                        val frame_type = smf.frame_type
                        if (frame_type <= 63) {
                            writeByte(frame_type)
                        } else if (frame_type >= 64 && frame_type <= 127) {
                            val sl1sif = as[SameLocals1StackItemFrame](smf)
                            writeByte(frame_type)
                            serialize(sl1sif.verification_type_info_stack)
                        } else if (frame_type == 247) {
                            val sl1sife = as[SameLocals1StackItemFrameExtended](smf)
                            writeByte(frame_type)
                            writeShort(sl1sife.offset_delta)
                            serialize(sl1sife.verification_type_info_stack)
                        } else if (frame_type >= 248 && frame_type <= 250) {
                            writeByte(frame_type)
                            writeShort(as[ChopFrame](smf).offset_delta)
                        } else if (frame_type == 251) {
                            writeByte(frame_type)
                            writeShort(as[SameFrameExtended](smf).offset_delta)
                        } else if (frame_type >= 252 && frame_type <= 254) {
                            writeByte(frame_type)
                            val af = as[AppendFrame](smf)
                            writeShort(af.offset_delta)
                            af.verification_type_info_locals.foreach { serialize(_) }
                        } else if (frame_type == 255) {
                            val ff = as[FullFrame](smf)
                            writeByte(frame_type)
                            writeShort(ff.offset_delta)
                            writeShort(ff.verification_type_info_locals.length)
                            ff.verification_type_info_locals.foreach { serialize(_) }
                            writeShort(ff.verification_type_info_stack.length)
                            ff.verification_type_info_stack.foreach { serialize(_) }
                        } else {
                            throw new UnknownError(s"unknown stack map frame: $smf")
                        }

                    }

                case a: ParametersAnnotations_attribute =>
                    // Handles:
                    // RuntimeVisibleParameterAnnotations_attribute
                    // RuntimeInvisibleParameterAnnotations_attribute
                    writeByte(a.parameters_annotations.length)
                    a.parameters_annotations.foreach { pas =>
                        writeShort(pas.size)
                        pas.foreach { serialize(_) }
                    }

                case a: MethodParameters_attribute =>
                    writeByte(a.parameters.length)
                    a.parameters.foreach { p =>
                        writeShort(p.name_index)
                        writeShort(p.access_flags)
                    }

                case a: BootstrapMethods_attribute =>
                    val length = a.bootstrap_methods.length
                    writeShort(length)
                    a.bootstrap_methods.foreach { bm =>
                        writeShort(bm.method_ref)
                        writeShort(bm.arguments.length)
                        bm.arguments.foreach { bma => writeShort(bma.cp_ref) }
                    }

                case as: Annotations_attribute =>
                    // Handles:
                    // RuntimeVisibleAnnotations_attribute
                    // RuntimeInvisibleAnnotations_attribute
                    writeShort(as.annotations.size)
                    as.annotations.foreach { serialize(_) }

                case a: LocalVariableTypeTable_attribute =>
                    val length = a.local_variable_type_table.size
                    writeShort(length)
                    a.local_variable_type_table.foreach { lvtte =>
                        writeShort(lvtte.start_pc)
                        writeShort(lvtte.length)
                        writeShort(lvtte.name_index)
                        writeShort(lvtte.signature_index)
                        writeShort(lvtte.index)
                    }

                case a: LocalVariableTable_attribute =>
                    val length = a.local_variable_table.size
                    writeShort(length)
                    a.local_variable_table.foreach { lvte =>
                        writeShort(lvte.start_pc)
                        writeShort(lvte.length)
                        writeShort(lvte.name_index)
                        writeShort(lvte.descriptor_index)
                        writeShort(lvte.index)
                    }

                case a: LineNumberTable_attribute =>
                    val length = a.line_number_table.size
                    writeShort(length)
                    a.line_number_table.foreach { lnte =>
                        writeShort(lnte.start_pc)
                        writeShort(lnte.line_number)
                    }

                case e: EnclosingMethod_attribute =>
                    writeShort(e.class_index)
                    writeShort(e.method_index)

                case c: Code_attribute =>
                    import c._
                    writeShort(max_stack)
                    writeShort(max_locals)
                    val code_length = code.instructions.length
                    writeInt(code_length)
                    out.write(code.instructions, 0, code_length)
                    writeShort(exceptionTable.length)
                    exceptionTable.foreach { ex =>
                        writeShort(ex.start_pc)
                        writeShort(ex.end_pc)
                        writeShort(ex.handler_pc)
                        writeShort(ex.catch_type)
                    }
                    writeShort(attributes.length)
                    attributes foreach { a => serialize(a) }

                case e: Exceptions_attribute =>
                    writeShort(e.exception_index_table.size)
                    e.exception_index_table.foreach(writeShort)

                case i: InnerClasses_attribute =>
                    import i._
                    writeShort(classes.size)
                    classes foreach { c =>
                        writeShort(c.inner_class_info_index)
                        writeShort(c.outer_class_info_index)
                        writeShort(c.inner_name_index)
                        writeShort(c.inner_class_access_flags)
                    }

                case a: SourceDebugExtension_attribute =>
                    out.write(a.debug_extension, 0, attribute_length)

                case a: AnnotationDefault_attribute => serialize(a.element_value)

                case a: SourceFile_attribute        => writeShort(a.sourceFile_index)
                case a: Signature_attribute         => writeShort(a.signature_index)
                case a: ConstantValue_attribute     => writeShort(a.constantValue_index)

                case _: Deprecated_attribute        => // nothing more to do
                case _: Synthetic_attribute         => // nothing more to do

                case a: Module_attribute =>
                    writeShort(a.module_name_index)
                    writeShort(a.module_flags)
                    writeShort(a.module_version_index)

                    writeShort(a.requires.length)
                    a.requires foreach { r =>
                        writeShort(r.requires_index)
                        writeShort(r.requires_flags)
                        writeShort(r.requires_version_index)
                    }

                    writeShort(a.exports.length)
                    a.exports foreach { e =>
                        writeShort(e.exports_index)
                        writeShort(e.exports_flags)
                        writeShort(e.exports_to_index_table.length)
                        e.exports_to_index_table.foreach(writeShort)
                    }

                    writeShort(a.opens.length)
                    a.opens foreach { o =>
                        writeShort(o.opens_index)
                        writeShort(o.opens_flags)
                        writeShort(o.opens_to_index_table.length)
                        o.opens_to_index_table.foreach(writeShort)
                    }

                    writeShort(a.uses.length)
                    a.uses.foreach(writeShort)

                    writeShort(a.provides.length)
                    a.provides foreach { p =>
                        writeShort(p.provides_index)
                        writeShort(p.provides_with_index_table.length)
                        p.provides_with_index_table.foreach(writeShort)
                    }

                case a: ModuleMainClass_attribute =>
                    writeShort(a.main_class_index)

                case a: ModulePackages_attribute =>
                    writeShort(a.package_index_table.length)
                    a.package_index_table.foreach(writeShort)

                case a: NestHost_attribute =>
                    writeShort(a.host_class_index)

                case a: NestMembers_attribute =>
                    writeShort(a.classes_array.length)
                    a.classes_array.foreach(writeShort)

                case a: Record_attribute =>
                    writeShort(a.components.length)
                    a.components foreach { c =>
                        writeShort(c.name_index)
                        writeShort(c.descriptor_index)
                        writeShort(c.attributes.length)
                        c.attributes foreach RichAttribute.write
                    }

                case a: PermittedSubclasses_attribute =>
                    writeShort(a.permitted_subclasses.length)
                    a.permitted_subclasses.foreach(writeShort)

                case a: Unknown_attribute => out.write(a.info, 0, a.info.length)
            }
        }
    }

    implicit object RichFieldInfo extends ClassFileElement[Field_Info] {
        def write(
            f: Field_Info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import f._
            import out._
            writeShort(access_flags)
            writeShort(name_index)
            writeShort(descriptor_index)
            writeShort(attributes.size)
            attributes.foreach(serializeAs[Attribute])
        }
    }

    implicit object RichMethodInfo extends ClassFileElement[Method_Info] {
        def write(
            m: Method_Info
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import m._
            import out._
            writeShort(access_flags)
            writeShort(name_index)
            writeShort(descriptor_index)
            writeShort(attributes.size)
            attributes.foreach(serializeAs[Attribute])
        }
    }

    implicit object RichClassFile extends ClassFileElement[ClassFile] {

        def write(
            classFile: ClassFile
        )(
            implicit
            out: DataOutputStream, segmentInformation: (String, Int) => Unit
        ): Unit = {
            import classFile._
            import out._
            implicit val cp: Constant_Pool = classFile.constant_pool
            writeInt(org.opalj.bi.ClassFileMagic)
            writeShort(minor_version)
            writeShort(major_version)
            segmentInformation("ClassFileMetaInformation", out.size)

            writeShort(cp.length)
            // OLD cp.tail.filter(_ ne null).foreach(serialize(_))
            val cpIt = cp.iterator
            cpIt.next()
            cpIt.filter(_ ne null).foreach(cpe => serialize(cpe))
            segmentInformation("ConstantPool", out.size)

            writeShort(access_flags)
            segmentInformation("ClassAccessFlags", out.size)

            writeShort(this_class)
            writeShort(super_class)
            writeShort(interfaces.size)
            interfaces.foreach { writeShort }
            segmentInformation("TypeInformation", out.size)

            writeShort(fields.size)
            fields.foreach { serializeAs[Field_Info] }
            segmentInformation("Fields", out.size)

            writeShort(methods.size)
            methods foreach { m =>
                serialize(m)
                if ((ACC_STRICT.mask & m.access_flags) != 0 && (classFile.major_version < 46 || classFile.major_version > 60)) {
                    OPALLogger.warn("assembler", s"Writing out ACC_STRICT flag for a method in a classfile of version ${classFile.major_version}, which is not interpreted in class files of version < 46 or > 60")
                }
                segmentInformation("Method: "+cp(m.name_index).toString, out.size)
            }
            segmentInformation("Methods", out.size)

            writeShort(attributes.size)
            attributes foreach { serializeAs[Attribute] }
            segmentInformation("ClassFileAttributes", out.size)
        }
    }

    /**
     * `serializeAs` makes it possible to specify the object type of the given parameter `t` and
     * that type will then be used to pick up the implicit class file element value.
     */
    def serializeAs[T](
        t: AnyRef
    )(
        implicit
        out:                DataOutputStream,
        segmentInformation: (String, Int) => Unit,
        cfe:                ClassFileElement[T]
    ): Unit = {
        cfe.write(as[T](t))
    }

    /**
     * @note    You should use serialize if the concrete/required type of the given parameter is
     *          available/can be automatically inferred by the Scala compiler.
     */
    def serialize[T: ClassFileElement](
        t: T
    )(
        implicit
        out:                DataOutputStream,
        segmentInformation: (String, Int) => Unit
    ): Unit = {
        implicitly[ClassFileElement[T]].write(t)
    }

    /**
     * @param   segmentInformation A function that will be called back to provide information about
     *          the segment that was just written.
     *          This is particularly useful when debugging the serializer to determine which
     *          segments were successfully/completely written.
     */
    def apply(
        classFile:          ClassFile,
        segmentInformation: (String, Int) => Unit = (segmentInformation, bytesWritten) => ()
    ): Array[Byte] = {
        val data = new ByteArrayOutputStream(classFile.size)
        val out = new DataOutputStream(data)
        serialize(classFile)(RichClassFile, out, segmentInformation)
        out.flush()
        data.toByteArray
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy