SymbolPrinter.java

package com.jeantessier.classreader;

import java.io.*;
import java.util.*;
import java.util.stream.*;

public abstract class SymbolPrinter {
    private static final Map<Class<? extends Visitable>, Collection<String>> HEADERS = Map.of(
            Classfile.class, List.of("symbol type", "symbol", "simple name"),
            Field_info.class, List.of("symbol type", "symbol", "class", "name", "type"),
            Method_info.class, List.of("symbol type", "symbol", "class", "name", "signature", "return type", "parameter types"),
            LocalVariable.class, List.of("symbol type", "symbol", "method", "name", "type"),
            InnerClass.class, List.of("symbol type", "symbol", "outer class", "inner name")
    );

    private final PrintWriter out;

    public SymbolPrinter(PrintWriter out) {
        this.out = out;
    }

    public PrintWriter getOut() {
        return out;
    }

    public abstract void print(SymbolGatherer gatherer) throws IOException;

    protected Stream<String> getHeadersFor(Class<? extends Visitable> visitableClass) {
        if (Classfile.class.isAssignableFrom(visitableClass)) {
            return HEADERS.get(Classfile.class).stream();
        } else if (Field_info.class.isAssignableFrom(visitableClass)) {
            return HEADERS.get(Field_info.class).stream();
        } else if (Method_info.class.isAssignableFrom(visitableClass)) {
            return HEADERS.get(Method_info.class).stream();
        } else if (LocalVariable.class.isAssignableFrom(visitableClass)) {
            return HEADERS.get(LocalVariable.class).stream();
        } else if (InnerClass.class.isAssignableFrom(visitableClass)) {
            return HEADERS.get(InnerClass.class).stream();
        } else {
            return Stream.empty();
        }
    }

    protected Stream<String> getHeadersFor(Visitable visitable) {
        return getHeadersFor(visitable.getClass());
    }

    protected Stream<?> getValuesFor(Visitable visitable) {
        if (visitable instanceof Classfile classfile) {
            return Stream.of(
                    "class name",
                    classfile,
                    classfile.getSimpleName()
            );
        } else if (visitable instanceof Field_info field) {
            return Stream.of(
                    "field name",
                    field,
                    field.getClassfile(),
                    field.getName(),
                    field.getType()
            );
        } else if (visitable instanceof Method_info method) {
            return Stream.of(
                    "method name",
                    method,
                    method.getClassfile(),
                    method.getName(),
                    method.getSignature(),
                    method.getReturnType(),
                    method.getParameterTypes()
            );
        } else if (visitable instanceof LocalVariable localVariable) {
            return Stream.of(
                    "local variable name",
                    localVariable,
                    localVariable.getMethod(),
                    localVariable.getName(),
                    localVariable.getType()
            );
        } else if (visitable instanceof InnerClass innerClass) {
            return Stream.of(
                    "inner class name",
                    innerClass,
                    innerClass.getOuterClassInfo(),
                    innerClass.getInnerName()
            );
        } else {
            return Stream.empty();
        }
    }

    protected Map<String, ?> visitableToRecord(Visitable visitable) {
        Map<String, ? super Object> result = new LinkedHashMap<>();

        List<String> headers = getHeadersFor(visitable).toList();
        List<?> values = getValuesFor(visitable).toList();

        IntStream.range(0, headers.size())
                .forEach(i -> result.put(headers.get(i), values.get(i)));

        return result;
    }

    protected String format(Stream<?> stream) {
        return stream
                .map(entry -> "\"" + entry + "\"")
                .collect(Collectors.joining(", "));
    }
}