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

org.netbeans.lib.nbjavac.services.NBClassReader Maven / Gradle / Ivy

There is a newer version: RELEASE230
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.netbeans.lib.nbjavac.services;

import com.sun.tools.javac.code.ClassFinder.BadClassFile;
import java.util.Set;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.jvm.ClassFile;
import com.sun.tools.javac.jvm.ClassFile.Version;
import com.sun.tools.javac.jvm.ClassReader;
import com.sun.tools.javac.resources.CompilerProperties.Warnings;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.tools.ForwardingJavaFileObject;
import javax.tools.JavaFileObject;

/**
 *
 * @author lahvac
 */
public class NBClassReader extends ClassReader {

    private static final Logger LOG = Logger.getLogger(NBClassReader.class.getName());

    public static void preRegister(Context context) {
        context.put(classReaderKey, new Context.Factory() {
            @Override
            public ClassReader make(Context c) {
                return new NBClassReader(c);
            }
        });
    }

    private final Names names;
    private final NBNames nbNames;
    private final Log log;

    public NBClassReader(Context context) {
        super(context);

        names = Names.instance(context);
        nbNames = NBNames.instance(context);
        log = Log.instance(context);

        NBAttributeReader[] readers = {
            new NBAttributeReader(nbNames._org_netbeans_EnclosingMethod, Version.V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
                public void read(Symbol sym, int attrLen) {
                    int newbp = bp + attrLen;
                    readEnclosingMethodAttr(sym);
                    bp = newbp;
                }
            },
            new NBAttributeReader(nbNames._org_netbeans_SourceLevelAnnotations, Version.V49, CLASS_OR_MEMBER_ATTRIBUTE) {
                protected void read(Symbol sym, int attrLen) {
                    attachAnnotations(sym);
                }

            },
            new NBAttributeReader(nbNames._org_netbeans_SourceLevelParameterAnnotations, Version.V49, CLASS_OR_MEMBER_ATTRIBUTE) {
                protected void read(Symbol sym, int attrLen) {
                    attachParameterAnnotations(sym);
                }

            },
            new NBAttributeReader(nbNames._org_netbeans_SourceLevelTypeAnnotations, Version.V52, CLASS_OR_MEMBER_ATTRIBUTE) {
                protected void read(Symbol sym, int attrLen) {
                    attachTypeAnnotations(sym);
                }

            },
        };

        for (NBAttributeReader r: readers)
            attributeReaders.put(r.getName(), r);
    }

    @Override
    public void readClassFile(ClassSymbol c) {
        try {
            super.readClassFile(c);
        } catch (BadClassFile cf) {
            if ("compiler.misc.bad.class.file.header".equals(cf.getDiagnostic().getCode())) {
                JavaFileObject origFile = c.classfile;
                try (InputStream in = origFile.openInputStream()) {
                    byte[] data = readFile(in);
                    if (data.length > 8) {
                        int major = (Byte.toUnsignedInt(data[6]) << 8) + Byte.toUnsignedInt(data[7]);
                        int maxMajor = ClassFile.Version.MAX().major;
                        if (maxMajor < major) {
                            if (log.currentSourceFile() != null) {
                                log.warning(0, Warnings.BigMajorVersion(origFile, major, maxMajor));
                            }
                            data[6] = (byte) (maxMajor >> 8);
                            data[7] = (byte) (maxMajor & 0xFF);
                            byte[] dataFin = data;
                            c.classfile = new ForwardingJavaFileObject(origFile) {
                                @Override
                                public InputStream openInputStream() throws IOException {
                                    return new ByteArrayInputStream(dataFin);
                                }
                            };
                            super.readClassFile(c);
                            return ;
                        }
                    }
                } catch (IOException ex) {
                    LOG.log(Level.FINE, null, ex);
                } finally {
                    c.classfile = origFile;
                }
            }
            throw cf;
        }
    }

    static byte[] readFile(final InputStream in) throws IOException {
        byte[] data = new byte[Math.max(in.available(), 256)];
        int off = 0;
        int read;
        while ((read = in.read(data, off, data.length - off)) != (-1)) {
            off += read;
            if (data.length == off) {
                data = Arrays.copyOf(data, 2 * (data.length + in.available()));
            }
        }
        return Arrays.copyOf(data, off);
    }

    private void attachAnnotations(Symbol sym) {
        try {
            Method m = ClassReader.class.getDeclaredMethod("attachAnnotations", Symbol.class);
            m.setAccessible(true);
            m.invoke(this, sym);
        } catch (NoSuchMethodException | SecurityException |
                 IllegalAccessException | IllegalArgumentException |
                 InvocationTargetException ex) {
            LOG.log(Level.SEVERE, null, ex);
        }
    }

    private void attachParameterAnnotations(Symbol sym) {
        try {
            Method m = ClassReader.class.getDeclaredMethod("readParameterAnnotations", Symbol.class);
            m.setAccessible(true);
            m.invoke(this, sym);
        } catch (NoSuchMethodException | SecurityException |
                 IllegalAccessException | IllegalArgumentException |
                 InvocationTargetException ex) {
            LOG.log(Level.SEVERE, null, ex);
        }
    }

    private void attachTypeAnnotations(Symbol sym) {
        try {
            Method m = ClassReader.class.getDeclaredMethod("attachTypeAnnotations", Symbol.class);
            m.setAccessible(true);
            m.invoke(this, sym);
        } catch (NoSuchMethodException | SecurityException |
                 IllegalAccessException | IllegalArgumentException |
                 InvocationTargetException ex) {
            LOG.log(Level.SEVERE, null, ex);
        }
    }

    private abstract class NBAttributeReader extends AttributeReader {

        private NBAttributeReader(Name name, Version version, Set kinds) {
            super(name, version, kinds);
        }
        
        private Name getName() {
            return name;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy