You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UnwovenClassFile.java 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.bcel;
  13. import java.io.BufferedOutputStream;
  14. import java.io.File;
  15. import java.io.IOException;
  16. import java.util.Collections;
  17. import java.util.List;
  18. import org.aspectj.apache.bcel.classfile.JavaClass;
  19. import org.aspectj.util.FileUtil;
  20. import org.aspectj.weaver.IUnwovenClassFile;
  21. public class UnwovenClassFile implements IUnwovenClassFile {
  22. protected String filename;
  23. protected char[] charfilename;
  24. protected byte[] bytes;
  25. // protected JavaClass javaClass = null;
  26. // protected byte[] writtenBytes = null;
  27. protected List<ChildClass> writtenChildClasses = Collections.emptyList();
  28. protected String className = null;
  29. protected boolean isModule = false;
  30. public UnwovenClassFile(String filename, byte[] bytes) {
  31. this.filename = filename;
  32. this.isModule = filename.toLowerCase().endsWith("module-info.java");
  33. this.bytes = bytes;
  34. }
  35. /** Use if the classname is known, saves a bytecode parse */
  36. public UnwovenClassFile(String filename, String classname, byte[] bytes) {
  37. this.filename = filename;
  38. this.isModule = filename.toLowerCase().endsWith("module-info.class");
  39. this.className = classname;
  40. this.bytes = bytes;
  41. }
  42. public boolean shouldBeWoven() {
  43. // Skip module-info files for now, they aren't really types
  44. return !isModule;
  45. }
  46. public String getFilename() {
  47. return filename;
  48. }
  49. public String makeInnerFileName(String innerName) {
  50. String prefix = filename.substring(0, filename.length() - 6); // strip the .class
  51. return prefix + "$" + innerName + ".class";
  52. }
  53. public byte[] getBytes() {
  54. // if (bytes == null) bytes = javaClass.getBytes();
  55. return bytes;
  56. }
  57. public JavaClass getJavaClass() {
  58. // XXX need to know when to make a new class and when not to
  59. // XXX this is an important optimization
  60. if (getBytes() == null) {
  61. System.out.println("no bytes for: " + getFilename());
  62. // Thread.currentThread().dumpStack();
  63. Thread.dumpStack();
  64. }
  65. return Utility.makeJavaClass(filename, getBytes());
  66. // if (javaClass == null) javaClass = Utility.makeJavaClass(filename, getBytes());
  67. // return javaClass;
  68. }
  69. public void writeUnchangedBytes() throws IOException {
  70. writeWovenBytes(getBytes(), Collections.<ChildClass>emptyList());
  71. }
  72. public void writeWovenBytes(byte[] bytes, List<ChildClass> childClasses) throws IOException {
  73. writeChildClasses(childClasses);
  74. // System.err.println("should write: " + getClassName());
  75. // System.err.println("about to write: " + this + ", " + writtenBytes + ", ");
  76. // + writtenBytes != null + " && " + unchanged(bytes, writtenBytes) );
  77. // if (writtenBytes != null && unchanged(bytes, writtenBytes)) return;
  78. // System.err.println(" actually wrote it");
  79. BufferedOutputStream os = FileUtil.makeOutputStream(new File(filename));
  80. os.write(bytes);
  81. os.close();
  82. // writtenBytes = bytes;
  83. }
  84. private void writeChildClasses(List<ChildClass> childClasses) throws IOException {
  85. // ??? we only really need to delete writtenChildClasses whose
  86. // ??? names aren't in childClasses; however, it's unclear
  87. // ??? how much that will affect performance
  88. deleteAllChildClasses();
  89. childClasses.removeAll(writtenChildClasses); // XXX is this right
  90. for (ChildClass childClass : childClasses) {
  91. writeChildClassFile(childClass.name, childClass.bytes);
  92. }
  93. writtenChildClasses = childClasses;
  94. }
  95. private void writeChildClassFile(String innerName, byte[] bytes) throws IOException {
  96. BufferedOutputStream os = FileUtil.makeOutputStream(new File(makeInnerFileName(innerName)));
  97. os.write(bytes);
  98. os.close();
  99. }
  100. protected void deleteAllChildClasses() {
  101. for (ChildClass childClass : writtenChildClasses) {
  102. deleteChildClassFile(childClass.name);
  103. }
  104. }
  105. protected void deleteChildClassFile(String innerName) {
  106. File childClassFile = new File(makeInnerFileName(innerName));
  107. childClassFile.delete();
  108. }
  109. /* private */static boolean unchanged(byte[] b1, byte[] b2) {
  110. int len = b1.length;
  111. if (b2.length != len)
  112. return false;
  113. for (int i = 0; i < len; i++) {
  114. if (b1[i] != b2[i])
  115. return false;
  116. }
  117. return true;
  118. }
  119. public char[] getClassNameAsChars() {
  120. if (charfilename == null) {
  121. charfilename = getClassName().replace('.', '/').toCharArray();
  122. }
  123. return charfilename;
  124. }
  125. public String getClassName() {
  126. if (className == null)
  127. className = getJavaClass().getClassName(); // OPTIMIZE quicker way to determine name??? surely?
  128. return className;
  129. }
  130. @Override
  131. public String toString() {
  132. return "UnwovenClassFile(" + filename + ", " + getClassName() + ")";
  133. }
  134. // record
  135. // 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
  136. // it back on!
  137. public static class ChildClass {
  138. public final String name;
  139. public final byte[] bytes;
  140. ChildClass(String name, byte[] bytes) {
  141. this.name = name;
  142. this.bytes = bytes;
  143. }
  144. @Override
  145. public boolean equals(Object other) {
  146. if (!(other instanceof ChildClass))
  147. return false;
  148. ChildClass o = (ChildClass) other;
  149. return o.name.equals(name) && unchanged(o.bytes, bytes);
  150. }
  151. @Override
  152. public int hashCode() {
  153. return name.hashCode();
  154. }
  155. @Override
  156. public String toString() {
  157. return "(ChildClass " + name + ")";
  158. }
  159. }
  160. public void setClassNameAsChars(char[] classNameAsChars) {
  161. this.charfilename = classNameAsChars;
  162. }
  163. }