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

org.aspectj.weaver.bcel.UnwovenClassFile Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v 2.0
 * which accompanies this distribution and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 *
 * Contributors:
 *     PARC     initial implementation
 * ******************************************************************/

package org.aspectj.weaver.bcel;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

import org.aspectj.apache.bcel.classfile.JavaClass;
import org.aspectj.util.FileUtil;
import org.aspectj.weaver.IUnwovenClassFile;

public class UnwovenClassFile implements IUnwovenClassFile {
	protected String filename;
	protected char[] charfilename;
	protected byte[] bytes;
	// protected JavaClass javaClass = null;
	// protected byte[] writtenBytes = null;
	protected List writtenChildClasses = Collections.emptyList();
	protected String className = null;
	protected boolean isModule = false;

	public UnwovenClassFile(String filename, byte[] bytes) {
		this.filename = filename;
		this.isModule = filename.toLowerCase().endsWith("module-info.java");
		this.bytes = bytes;
	}

	/** Use if the classname is known, saves a bytecode parse */
	public UnwovenClassFile(String filename, String classname, byte[] bytes) {
		this.filename = filename;
		this.isModule = filename.toLowerCase().endsWith("module-info.class");
		this.className = classname;
		this.bytes = bytes;
	}

	public boolean shouldBeWoven() {
		// Skip module-info files for now, they aren't really types
		return !isModule;
	}

	public String getFilename() {
		return filename;
	}

	public String makeInnerFileName(String innerName) {
		String prefix = filename.substring(0, filename.length() - 6); // strip the .class
		return prefix + "$" + innerName + ".class";
	}

	public byte[] getBytes() {
		// if (bytes == null) bytes = javaClass.getBytes();
		return bytes;
	}

	public JavaClass getJavaClass() {
		// XXX need to know when to make a new class and when not to
		// XXX this is an important optimization
		if (getBytes() == null) {
			System.out.println("no bytes for: " + getFilename());
			// Thread.currentThread().dumpStack();
			Thread.dumpStack();
		}
		return Utility.makeJavaClass(filename, getBytes());
		// if (javaClass == null) javaClass = Utility.makeJavaClass(filename, getBytes());
		// return javaClass;
	}

	public void writeUnchangedBytes() throws IOException {
		writeWovenBytes(getBytes(), Collections.emptyList());
	}

	public void writeWovenBytes(byte[] bytes, List childClasses) throws IOException {
		writeChildClasses(childClasses);

		// System.err.println("should write: " + getClassName());

		// System.err.println("about to write: " + this + ", " + writtenBytes + ", ");
		// + writtenBytes != null + " && " + unchanged(bytes, writtenBytes) );

		// if (writtenBytes != null && unchanged(bytes, writtenBytes)) return;

		// System.err.println("    actually wrote it");

		BufferedOutputStream os = FileUtil.makeOutputStream(new File(filename));
		os.write(bytes);
		os.close();

		// writtenBytes = bytes;
	}

	private void writeChildClasses(List childClasses) throws IOException {
		// ??? we only really need to delete writtenChildClasses whose
		// ??? names aren't in childClasses; however, it's unclear
		// ??? how much that will affect performance
		deleteAllChildClasses();

		childClasses.removeAll(writtenChildClasses); // XXX is this right

		for (ChildClass childClass : childClasses) {
			writeChildClassFile(childClass.name, childClass.bytes);
		}

		writtenChildClasses = childClasses;

	}

	private void writeChildClassFile(String innerName, byte[] bytes) throws IOException {
		BufferedOutputStream os = FileUtil.makeOutputStream(new File(makeInnerFileName(innerName)));
		os.write(bytes);
		os.close();
	}

	protected void deleteAllChildClasses() {
		for (ChildClass childClass : writtenChildClasses) {
			deleteChildClassFile(childClass.name);
		}
	}

	protected void deleteChildClassFile(String innerName) {
		File childClassFile = new File(makeInnerFileName(innerName));
		childClassFile.delete();
	}

	/* private */static boolean unchanged(byte[] b1, byte[] b2) {
		int len = b1.length;
		if (b2.length != len)
			return false;
		for (int i = 0; i < len; i++) {
			if (b1[i] != b2[i])
				return false;
		}
		return true;
	}

	public char[] getClassNameAsChars() {
		if (charfilename == null) {
			charfilename = getClassName().replace('.', '/').toCharArray();
		}
		return charfilename;
	}

	public String getClassName() {
		if (className == null)
			className = getJavaClass().getClassName(); // OPTIMIZE quicker way to determine name??? surely?
		return className;
	}

	@Override
	public String toString() {
		return "UnwovenClassFile(" + filename + ", " + getClassName() + ")";
	}

	// record
	// OPTIMIZE why is the 'short name' used here (the bit after the dollar) - seems we mess about a lot trimming it off only to put
	// it back on!
	public static class ChildClass {
		public final String name;
		public final byte[] bytes;

		ChildClass(String name, byte[] bytes) {
			this.name = name;
			this.bytes = bytes;
		}

		@Override
		public boolean equals(Object other) {
			if (!(other instanceof ChildClass))
				return false;
			ChildClass o = (ChildClass) other;
			return o.name.equals(name) && unchanged(o.bytes, bytes);
		}

		@Override
		public int hashCode() {
			return name.hashCode();
		}

		@Override
		public String toString() {
			return "(ChildClass " + name + ")";
		}
	}

	public void setClassNameAsChars(char[] classNameAsChars) {
		this.charfilename = classNameAsChars;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy