diff --git a/.idea/modules.xml b/.idea/modules.xml
index e6de17c97dfd..18bb3a5c3d05 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -51,6 +51,7 @@
+
diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant
index e78e38697911..6381e2e9eab8 100644
--- a/build/scripts/layouts.gant
+++ b/build/scripts/layouts.gant
@@ -77,7 +77,7 @@ def layoutFull(String home, String targetDirectory, String patchedDescriptorDir
//noinspection GroovyAssignabilityCheck
List implementationModules = [platformImplementationModules(),
- "notNull",
+ "instrumentation-util",
"platform-main",
"java-psi-impl",
"java-impl",
@@ -170,7 +170,7 @@ def layoutFull(String home, String targetDirectory, String patchedDescriptorDir
module("javac2")
module("forms-compiler")
module("forms_rt")
- module("notNull")
+ module("instrumentation-util")
}
jar("jps-server.jar") {
diff --git a/community-main.iml b/community-main.iml
index a52ba14d3c83..0dbcfb09ce10 100644
--- a/community-main.iml
+++ b/community-main.iml
@@ -31,7 +31,7 @@
-
+
diff --git a/java/compiler/forms-compiler/forms-compiler.iml b/java/compiler/forms-compiler/forms-compiler.iml
index ce591cf3173e..39ba1446f119 100644
--- a/java/compiler/forms-compiler/forms-compiler.iml
+++ b/java/compiler/forms-compiler/forms-compiler.iml
@@ -13,6 +13,7 @@
+
diff --git a/java/compiler/forms-compiler/src/com/intellij/uiDesigner/compiler/AsmCodeGenerator.java b/java/compiler/forms-compiler/src/com/intellij/uiDesigner/compiler/AsmCodeGenerator.java
index b7a344dcf74e..b838594d8f6f 100644
--- a/java/compiler/forms-compiler/src/com/intellij/uiDesigner/compiler/AsmCodeGenerator.java
+++ b/java/compiler/forms-compiler/src/com/intellij/uiDesigner/compiler/AsmCodeGenerator.java
@@ -15,6 +15,7 @@
*/
package com.intellij.uiDesigner.compiler;
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
import com.intellij.uiDesigner.UIFormXmlConstants;
import com.intellij.uiDesigner.lw.*;
import com.intellij.uiDesigner.shared.BorderType;
@@ -28,7 +29,6 @@ import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.io.*;
-import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
@@ -40,7 +40,7 @@ import java.util.Map;
*/
public class AsmCodeGenerator {
private final LwRootContainer myRootContainer;
- private final ClassLoader myLoader;
+ private final InstrumentationClassFinder myFinder;
private final ArrayList myErrors;
private final ArrayList myWarnings;
@@ -96,20 +96,20 @@ public class AsmCodeGenerator {
}
public AsmCodeGenerator(LwRootContainer rootContainer,
- ClassLoader loader,
+ InstrumentationClassFinder finder,
NestedFormLoader formLoader,
final boolean ignoreCustomCreation,
final ClassWriter classWriter) {
myFormLoader = formLoader;
myIgnoreCustomCreation = ignoreCustomCreation;
- if (loader == null){
+ if (finder == null){
throw new IllegalArgumentException("loader cannot be null");
}
if (rootContainer == null){
throw new IllegalArgumentException("rootContainer cannot be null");
}
myRootContainer = rootContainer;
- myLoader = loader;
+ myFinder = finder;
myErrors = new ArrayList();
myWarnings = new ArrayList();
@@ -210,9 +210,9 @@ public class AsmCodeGenerator {
codeGen.generatePushValue(generator, value);
}
- static Class getComponentClass(String className, final ClassLoader classLoader) throws CodeGenerationException {
+ static InstrumentationClassFinder.PseudoClass getComponentClass(String className, final InstrumentationClassFinder finder) throws CodeGenerationException {
try {
- return Class.forName(className, false, classLoader);
+ return finder.loadClass(className);
}
catch (ClassNotFoundException e) {
throw new CodeGenerationException(null, "Class not found: " + className);
@@ -220,6 +220,9 @@ public class AsmCodeGenerator {
catch(UnsupportedClassVersionError e) {
throw new CodeGenerationException(null, "Unsupported class version error: " + className);
}
+ catch (IOException e) {
+ throw new CodeGenerationException(null, e.getMessage(), e);
+ }
}
public static Type typeFromClassName(final String className) {
@@ -252,7 +255,7 @@ public class AsmCodeGenerator {
for (Iterator iterator = myPropertyCodeGenerators.values().iterator(); iterator.hasNext();) {
PropertyCodeGenerator propertyCodeGenerator = (PropertyCodeGenerator)iterator.next();
- propertyCodeGenerator.generateClassStart(this, name, myLoader);
+ propertyCodeGenerator.generateClassStart(this, name, myFinder);
}
}
@@ -394,28 +397,30 @@ public class AsmCodeGenerator {
myIdToLocalMap.put(lwComponent.getId(), new Integer(componentLocal));
- Class componentClass = getComponentClass(className, myLoader);
+ InstrumentationClassFinder.PseudoClass componentClass = getComponentClass(className, myFinder);
validateFieldBinding(lwComponent, componentClass);
if (myIgnoreCustomCreation) {
- boolean creatable = true;
- if ((componentClass.getModifiers() & (Modifier.PRIVATE | Modifier.ABSTRACT)) != 0) {
- creatable = false;
- }
- else {
- try {
- final Constructor constructor = componentClass.getConstructor(new Class[0]);
- if ((constructor.getModifiers() & Modifier.PUBLIC) == 0) {
+ try {
+ boolean creatable = true;
+ if ((componentClass.getModifiers() & (Modifier.PRIVATE | Modifier.ABSTRACT)) != 0) {
+ creatable = false;
+ }
+ else {
+ if (!componentClass.hasDefaultPublicConstructor()) {
creatable = false;
}
}
- catch(NoSuchMethodException ex) {
- creatable = false;
+ if (!creatable) {
+ componentClass = Utils.suggestReplacementClass(componentClass);
+ componentType = Type.getType(componentClass.getDescriptor());
}
}
- if (!creatable) {
- componentClass = Utils.suggestReplacementClass(componentClass);
- componentType = Type.getType(componentClass);
+ catch (ClassNotFoundException e) {
+ throw new CodeGenerationException(lwComponent.getId(), e.getMessage(), e);
+ }
+ catch (IOException e) {
+ throw new CodeGenerationException(lwComponent.getId(), e.getMessage(), e);
}
}
@@ -468,12 +473,11 @@ public class AsmCodeGenerator {
}
}
- private int getNestedFormComponent(GeneratorAdapter generator, Class componentClass, int formLocal) throws CodeGenerationException {
+ private int getNestedFormComponent(GeneratorAdapter generator, InstrumentationClassFinder.PseudoClass componentClass, int formLocal) throws CodeGenerationException {
final Type componentType = Type.getType(JComponent.class);
int componentLocal = generator.newLocal(componentType);
generator.loadLocal(formLocal);
- generator.invokeVirtual(Type.getType(componentClass),
- new Method(GET_ROOT_COMPONENT_METHOD_NAME, componentType, new Type[0]));
+ generator.invokeVirtual(Type.getType(componentClass.getDescriptor()), new Method(GET_ROOT_COMPONENT_METHOD_NAME, componentType, new Type[0]));
generator.storeLocal(componentLocal);
return componentLocal;
}
@@ -502,7 +506,7 @@ public class AsmCodeGenerator {
}
private void generateComponentProperties(final LwComponent lwComponent,
- final Class componentClass,
+ final InstrumentationClassFinder.PseudoClass componentClass,
final GeneratorAdapter generator,
final int componentLocal) throws CodeGenerationException {
// introspected properties
@@ -543,7 +547,12 @@ public class AsmCodeGenerator {
else {
setterClass = Class.forName(propertyClass);
}
- componentClass.getMethod(property.getWriteMethodName(), new Class[] { setterClass } );
+ //componentClass.getMethod(property.getWriteMethodName(), new Class[] { setterClass } );
+ final String descriptor = "(L"+setterClass.getName().replace('.', '/') + ";)V";
+ final InstrumentationClassFinder.PseudoMethod setter = componentClass.findMethod(property.getWriteMethodName(), descriptor);
+ if (setter == null) {
+ continue;
+ }
}
catch (Exception e) {
continue;
@@ -551,9 +560,16 @@ public class AsmCodeGenerator {
}
final PropertyCodeGenerator propGen = (PropertyCodeGenerator) myPropertyCodeGenerators.get(propertyClass);
- if (propGen != null && propGen.generateCustomSetValue(lwComponent, componentClass, property,
- generator, componentLocal, myClassName)) {
- continue;
+ try {
+ if (propGen != null && propGen.generateCustomSetValue(lwComponent, componentClass, property, generator, componentLocal, myClassName)) {
+ continue;
+ }
+ }
+ catch (IOException e) {
+ throw new CodeGenerationException(lwComponent.getId(), e.getMessage(), e);
+ }
+ catch (ClassNotFoundException e) {
+ throw new CodeGenerationException(lwComponent.getId(), e.getMessage(), e);
}
generator.loadLocal(componentLocal);
@@ -602,7 +618,7 @@ public class AsmCodeGenerator {
Type declaringType = (property.getDeclaringClassName() != null)
? typeFromClassName(property.getDeclaringClassName())
- : Type.getType(componentClass);
+ : Type.getType(componentClass.getDescriptor());
generator.invokeVirtual(declaringType, new Method(property.getWriteMethodName(),
Type.VOID_TYPE, new Type[] { setterArgType } ));
}
@@ -611,7 +627,7 @@ public class AsmCodeGenerator {
}
private void generateClientProperties(final LwComponent lwComponent,
- final Class componentClass,
+ final InstrumentationClassFinder.PseudoClass componentClass,
final GeneratorAdapter generator,
final int componentLocal) throws CodeGenerationException {
HashMap props = lwComponent.getDelegeeClientProperties();
@@ -652,7 +668,7 @@ public class AsmCodeGenerator {
}
}
- Type componentType = Type.getType(componentClass);
+ Type componentType = Type.getType(componentClass.getDescriptor());
Type objectType = Type.getType(Object.class);
generator.invokeVirtual(componentType, new Method("putClientProperty",
Type.VOID_TYPE, new Type[] { objectType, objectType } ));
@@ -664,7 +680,7 @@ public class AsmCodeGenerator {
if (component instanceof LwNestedForm) return;
int componentLocal = ((Integer) myIdToLocalMap.get(component.getId())).intValue();
final LayoutCodeGenerator layoutCodeGenerator = getComponentCodeGenerator(component.getParent());
- Class componentClass = getComponentClass(layoutCodeGenerator.mapComponentClass(component.getComponentClassName()), myLoader);
+ InstrumentationClassFinder.PseudoClass componentClass = getComponentClass(layoutCodeGenerator.mapComponentClass(component.getComponentClassName()), myFinder);
final LwIntrospectedProperty[] introspectedProperties = component.getAssignedIntrospectedProperties();
for (int i = 0; i < introspectedProperties.length; i++) {
@@ -681,7 +697,7 @@ public class AsmCodeGenerator {
generator.loadLocal(targetLocal);
Type declaringType = (property.getDeclaringClassName() != null)
? typeFromClassName(property.getDeclaringClassName())
- : Type.getType(componentClass);
+ : Type.getType(componentClass.getDescriptor());
generator.invokeVirtual(declaringType,
new Method(property.getWriteMethodName(),
Type.VOID_TYPE, new Type[] { typeFromClassName(property.getPropertyClassName()) } ));
@@ -702,33 +718,45 @@ public class AsmCodeGenerator {
private void generateButtonGroups(final LwRootContainer rootContainer, final GeneratorAdapter generator) throws CodeGenerationException {
IButtonGroup[] groups = rootContainer.getButtonGroups();
if (groups.length > 0) {
- int groupLocal = generator.newLocal(ourButtonGroupType);
- for(int groupIndex=0; groupIndex 0) {
- generator.newInstance(ourButtonGroupType);
- generator.dup();
- generator.invokeConstructor(ourButtonGroupType, Method.getMethod("void ()"));
- generator.storeLocal(groupLocal);
+ if (ids.length > 0) {
+ generator.newInstance(ourButtonGroupType);
+ generator.dup();
+ generator.invokeConstructor(ourButtonGroupType, Method.getMethod("void ()"));
+ generator.storeLocal(groupLocal);
- if (groups [groupIndex].isBound() && !myIgnoreCustomCreation) {
- validateFieldClass(groups [groupIndex].getName(), ButtonGroup.class, null);
- generator.loadThis();
- generator.loadLocal(groupLocal);
- generator.putField(getMainClassType(), groups [groupIndex].getName(), ourButtonGroupType);
- }
-
- for(int i = 0; i= 0) {
generator.loadLocal(componentLocal);
generator.push(textWithMnemonic.myText);
- generator.invokeVirtual(Type.getType(componentClass),
+ generator.invokeVirtual(Type.getType(componentClass.getDescriptor()),
new Method(property.getWriteMethodName(),
Type.VOID_TYPE, new Type[] { Type.getType(String.class) } ));
String setMnemonicMethodName;
- if (AbstractButton.class.isAssignableFrom(componentClass)) {
+ if (abstractButtonClass.isAssignableFrom(componentClass)) {
setMnemonicMethodName = "setMnemonic";
}
else {
@@ -89,14 +93,14 @@ public class StringPropertyCodeGenerator extends PropertyCodeGenerator implement
generator.loadLocal(componentLocal);
generator.push(textWithMnemonic.getMnemonicChar());
- generator.invokeVirtual(Type.getType(componentClass),
+ generator.invokeVirtual(Type.getType(componentClass.getDescriptor()),
new Method(setMnemonicMethodName,
Type.VOID_TYPE, new Type[] { Type.CHAR_TYPE } ));
if (myHaveSetDisplayedMnemonicIndex) {
generator.loadLocal(componentLocal);
generator.push(textWithMnemonic.myMnemonicIndex);
- generator.invokeVirtual(Type.getType(componentClass),
+ generator.invokeVirtual(Type.getType(componentClass.getDescriptor()),
new Method("setDisplayedMnemonicIndex",
Type.VOID_TYPE, new Type[] { Type.INT_TYPE } ));
}
@@ -105,7 +109,7 @@ public class StringPropertyCodeGenerator extends PropertyCodeGenerator implement
}
else {
Method method;
- if (AbstractButton.class.isAssignableFrom(componentClass)) {
+ if (abstractButtonClass.isAssignableFrom(componentClass)) {
myClassesRequiringLoadButtonText.add(formClassName);
method = myLoadButtonTextMethod;
}
diff --git a/java/compiler/forms-compiler/src/com/intellij/uiDesigner/compiler/Utils.java b/java/compiler/forms-compiler/src/com/intellij/uiDesigner/compiler/Utils.java
index 4b28e2d04628..79fb947cacb5 100644
--- a/java/compiler/forms-compiler/src/com/intellij/uiDesigner/compiler/Utils.java
+++ b/java/compiler/forms-compiler/src/com/intellij/uiDesigner/compiler/Utils.java
@@ -15,6 +15,7 @@
*/
package com.intellij.uiDesigner.compiler;
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.lw.*;
import org.jdom.Document;
@@ -28,6 +29,7 @@ import javax.swing.*;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.awt.*;
+import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.lang.reflect.Constructor;
@@ -43,306 +45,323 @@ import java.util.Set;
* NOTE: the class must be compilable with JDK 1.3, so any methods and filds introduced in 1.4 or later must not be used
*/
public final class Utils {
- public static final String FORM_NAMESPACE = "http://www.intellij.com/uidesigner/form/";
- private static final SAXParser SAX_PARSER = createParser();
+ public static final String FORM_NAMESPACE = "http://www.intellij.com/uidesigner/form/";
+ private static final SAXParser SAX_PARSER = createParser();
- private Utils() {
+ private Utils() {
+ }
+
+ private static SAXParser createParser() {
+ try {
+ return SAXParserFactory.newInstance().newSAXParser();
+ }
+ catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * @param provider if null, no classes loaded and no properties read
+ */
+ public static LwRootContainer getRootContainer(final String formFileContent, final PropertiesProvider provider) throws Exception {
+ if (formFileContent.indexOf(FORM_NAMESPACE) == -1) {
+ throw new AlienFormFileException();
}
- private static SAXParser createParser() {
- try {
- return SAXParserFactory.newInstance().newSAXParser();
- }
- catch (Exception e) {
- return null;
+ final Document document = new SAXBuilder().build(new StringReader(formFileContent), "UTF-8");
+
+ return getRootContainerFromDocument(document, provider);
+ }
+
+ /**
+ * Get root from the url
+ *
+ * @param formFile the document URL
+ * @param provider the provider
+ * @return the root container
+ * @throws Exception if there is a problem with parsing DOM
+ */
+ public static LwRootContainer getRootContainer(final URL formFile, final PropertiesProvider provider) throws Exception {
+ final Document document = new SAXBuilder().build(formFile);
+ return getRootContainerFromDocument(document, provider);
+ }
+
+
+ /**
+ * Get root from the document
+ *
+ * @param document the parsed document
+ * @param provider the provider
+ * @return the root container
+ * @throws Exception if there is a problem with parsing DOM
+ */
+ private static LwRootContainer getRootContainerFromDocument(Document document, PropertiesProvider provider) throws Exception {
+ final LwRootContainer root = new LwRootContainer();
+ root.read(document.getRootElement(), provider);
+ return root;
+ }
+
+ public static LwRootContainer getRootContainer(final InputStream stream, final PropertiesProvider provider) throws Exception {
+ final Document document = new SAXBuilder().build(stream, "UTF-8");
+
+ return getRootContainerFromDocument(document, provider);
+ }
+
+ public synchronized static String getBoundClassName(final String formFileContent) throws Exception {
+ if (formFileContent.indexOf(FORM_NAMESPACE) == -1) {
+ throw new AlienFormFileException();
+ }
+
+ final String[] className = new String[]{null};
+ try {
+ SAX_PARSER.parse(new InputSource(new StringReader(formFileContent)), new DefaultHandler() {
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ if ("form".equals(qName)) {
+ className[0] = attributes.getValue("", "bind-to-class");
+ throw new SAXException("stop parsing");
+ }
}
+ });
+ }
+ catch (Exception e) {
+ // Do nothing.
}
- /**
- * @param provider if null, no classes loaded and no properties read
- */
- public static LwRootContainer getRootContainer(final String formFileContent, final PropertiesProvider provider) throws Exception {
- if (formFileContent.indexOf(FORM_NAMESPACE) == -1) {
- throw new AlienFormFileException();
- }
+ return className[0];
+ }
- final Document document = new SAXBuilder().build(new StringReader(formFileContent), "UTF-8");
-
- return getRootContainerFromDocument(document, provider);
- }
-
- /**
- * Get root from the url
- *
- * @param formFile the document URL
- * @param provider the provider
- * @return the root container
- * @throws Exception if there is a problem with parsing DOM
- */
- public static LwRootContainer getRootContainer(final URL formFile, final PropertiesProvider provider) throws Exception {
- final Document document = new SAXBuilder().build(formFile);
- return getRootContainerFromDocument(document, provider);
- }
-
-
- /**
- * Get root from the document
- *
- * @param document the parsed document
- * @param provider the provider
- * @return the root container
- * @throws Exception if there is a problem with parsing DOM
- */
- private static LwRootContainer getRootContainerFromDocument(Document document, PropertiesProvider provider) throws Exception {
- final LwRootContainer root = new LwRootContainer();
- root.read(document.getRootElement(), provider);
- return root;
- }
-
- public static LwRootContainer getRootContainer(final InputStream stream, final PropertiesProvider provider) throws Exception {
- final Document document = new SAXBuilder().build(stream, "UTF-8");
-
- return getRootContainerFromDocument(document, provider);
- }
-
- public synchronized static String getBoundClassName(final String formFileContent) throws Exception {
- if (formFileContent.indexOf(FORM_NAMESPACE) == -1) {
- throw new AlienFormFileException();
- }
-
- final String[] className = new String[]{null};
- try {
- SAX_PARSER.parse(new InputSource(new StringReader(formFileContent)), new DefaultHandler() {
- public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
- if ("form".equals(qName)) {
- className[0] = attributes.getValue("", "bind-to-class");
- throw new SAXException("stop parsing");
- }
- }
- });
- }
- catch (Exception e) {
- // Do nothing.
- }
-
- return className[0];
- }
-
- /**
- * Validates that specified class represents {@link javax.swing.JComponent} with
- * empty constructor.
- *
- * @return descriptive human readable error message or null if
- * no errors were detected.
- */
+ /**
+ * Validates that specified class represents {@link javax.swing.JComponent} with
+ * empty constructor.
+ *
+ * @return descriptive human readable error message or null if
+ * no errors were detected.
+ */
public static String validateJComponentClass(final ClassLoader loader, final String className, final boolean validateConstructor) {
if (loader == null) {
- throw new IllegalArgumentException("loader cannot be null");
- }
- if (className == null) {
- throw new IllegalArgumentException("className cannot be null");
- }
+ throw new IllegalArgumentException("loader cannot be null");
+ }
+ if (className == null) {
+ throw new IllegalArgumentException("className cannot be null");
+ }
- // These classes are not visible for passed class loader!
- if ("com.intellij.uiDesigner.HSpacer".equals(className) || "com.intellij.uiDesigner.VSpacer".equals(className)) {
- return null;
- }
+ // These classes are not visible for passed class loader!
+ if ("com.intellij.uiDesigner.HSpacer".equals(className) || "com.intellij.uiDesigner.VSpacer".equals(className)) {
+ return null;
+ }
final Class aClass;
- try {
+ try {
aClass = Class.forName(className, false, loader);
- }
- catch (final ClassNotFoundException exc) {
- return "Class \"" + className + "\"not found";
- }
- catch (NoClassDefFoundError exc) {
- return "Cannot load class " + className + ": " + exc.getMessage();
- }
- catch (ExceptionInInitializerError exc) {
- return "Cannot initialize class " + className + ": " + exc.getMessage();
- }
- catch (UnsupportedClassVersionError exc) {
- return "Unsupported class version error: " + className;
- }
+ }
+ catch (final ClassNotFoundException exc) {
+ return "Class \"" + className + "\"not found";
+ }
+ catch (NoClassDefFoundError exc) {
+ return "Cannot load class " + className + ": " + exc.getMessage();
+ }
+ catch (ExceptionInInitializerError exc) {
+ return "Cannot initialize class " + className + ": " + exc.getMessage();
+ }
+ catch (UnsupportedClassVersionError exc) {
+ return "Unsupported class version error: " + className;
+ }
- if (validateConstructor) {
+ if (validateConstructor) {
try {
final Constructor constructor = aClass.getConstructor(new Class[0]);
if ((constructor.getModifiers() & Modifier.PUBLIC) == 0) {
- return "Class \"" + className + "\" does not have default public constructor";
- }
- }
+ return "Class \"" + className + "\" does not have default public constructor";
+ }
+ }
catch (final Exception exc) {
return "Class \"" + className + "\" does not have default constructor";
}
}
- // Check that JComponent is accessible via the loader
+ // Check that JComponent is accessible via the loader
if (!JComponent.class.isAssignableFrom(aClass)) {
- return "Class \"" + className + "\" is not an instance of javax.swing.JComponent";
- }
+ return "Class \"" + className + "\" is not an instance of javax.swing.JComponent";
+ }
- return null;
+ return null;
+ }
+
+ public static void validateNestedFormLoop(final String formName, final NestedFormLoader nestedFormLoader)
+ throws CodeGenerationException, RecursiveFormNestingException {
+ validateNestedFormLoop(formName, nestedFormLoader, null);
+ }
+
+ public static void validateNestedFormLoop(final String formName, final NestedFormLoader nestedFormLoader, final String targetForm)
+ throws CodeGenerationException, RecursiveFormNestingException {
+ HashSet usedFormNames = new HashSet();
+ if (targetForm != null) {
+ usedFormNames.add(targetForm);
}
+ validateNestedFormLoop(usedFormNames, formName, nestedFormLoader);
+ }
- public static void validateNestedFormLoop(final String formName, final NestedFormLoader nestedFormLoader)
- throws CodeGenerationException, RecursiveFormNestingException {
- validateNestedFormLoop(formName, nestedFormLoader, null);
+ private static void validateNestedFormLoop(final Set usedFormNames, final String formName, final NestedFormLoader nestedFormLoader)
+ throws CodeGenerationException, RecursiveFormNestingException {
+ if (usedFormNames.contains(formName)) {
+ throw new RecursiveFormNestingException();
}
-
- public static void validateNestedFormLoop(final String formName, final NestedFormLoader nestedFormLoader, final String targetForm)
- throws CodeGenerationException, RecursiveFormNestingException {
- HashSet usedFormNames = new HashSet();
- if (targetForm != null) {
- usedFormNames.add(targetForm);
- }
- validateNestedFormLoop(usedFormNames, formName, nestedFormLoader);
+ usedFormNames.add(formName);
+ final LwRootContainer rootContainer;
+ try {
+ rootContainer = nestedFormLoader.loadForm(formName);
}
-
- private static void validateNestedFormLoop(final Set usedFormNames, final String formName, final NestedFormLoader nestedFormLoader)
- throws CodeGenerationException, RecursiveFormNestingException {
- if (usedFormNames.contains(formName)) {
- throw new RecursiveFormNestingException();
- }
- usedFormNames.add(formName);
- final LwRootContainer rootContainer;
- try {
- rootContainer = nestedFormLoader.loadForm(formName);
- }
- catch (Exception e) {
- throw new CodeGenerationException(null, "Error loading nested form: " + e.getMessage(), e);
- }
- final Set thisFormNestedForms = new HashSet();
- final CodeGenerationException[] validateExceptions = new CodeGenerationException[1];
- final RecursiveFormNestingException[] recursiveNestingExceptions = new RecursiveFormNestingException[1];
- rootContainer.accept(new ComponentVisitor() {
- public boolean visit(final IComponent component) {
- if (component instanceof LwNestedForm) {
- LwNestedForm nestedForm = (LwNestedForm)component;
- if (!thisFormNestedForms.contains(nestedForm.getFormFileName())) {
- thisFormNestedForms.add(nestedForm.getFormFileName());
- try {
- validateNestedFormLoop(usedFormNames, nestedForm.getFormFileName(), nestedFormLoader);
- }
- catch (RecursiveFormNestingException e) {
- recursiveNestingExceptions[0] = e;
- return false;
- }
- catch (CodeGenerationException e) {
- validateExceptions[0] = e;
- return false;
- }
- }
- }
- return true;
- }
- });
- if (recursiveNestingExceptions[0] != null) {
- throw recursiveNestingExceptions[0];
- }
- if (validateExceptions[0] != null) {
- throw validateExceptions[0];
- }
+ catch (Exception e) {
+ throw new CodeGenerationException(null, "Error loading nested form: " + e.getMessage(), e);
}
-
- public static String findNotEmptyPanelWithXYLayout(final IComponent component) {
- if (!(component instanceof IContainer)) {
- return null;
- }
- final IContainer container = (IContainer)component;
- if (container.getComponentCount() == 0) {
- return null;
- }
- if (container.isXY()) {
- return container.getId();
- }
- for (int i = 0; i < container.getComponentCount(); i++) {
- String id = findNotEmptyPanelWithXYLayout(container.getComponent(i));
- if (id != null) {
- return id;
- }
- }
- return null;
- }
-
- public static int getHGap(LayoutManager layout) {
- if (layout instanceof BorderLayout) {
- return ((BorderLayout)layout).getHgap();
- }
- if (layout instanceof CardLayout) {
- return ((CardLayout)layout).getHgap();
- }
- return 0;
- }
-
- public static int getVGap(LayoutManager layout) {
- if (layout instanceof BorderLayout) {
- return ((BorderLayout)layout).getVgap();
- }
- if (layout instanceof CardLayout) {
- return ((CardLayout)layout).getVgap();
- }
- return 0;
- }
-
- public static int getCustomCreateComponentCount(final IContainer container) {
- final int[] result = new int[1];
- result[0] = 0;
- container.accept(new ComponentVisitor() {
- public boolean visit(IComponent c) {
- if (c.isCustomCreate()) {
- result[0]++;
- }
- return true;
- }
- });
- return result[0];
- }
-
- public static Class suggestReplacementClass(Class componentClass) {
- while (true) {
- componentClass = componentClass.getSuperclass();
- if (componentClass.equals(JComponent.class)) {
- return JPanel.class;
- }
- if ((componentClass.getModifiers() & (Modifier.ABSTRACT | Modifier.PRIVATE)) != 0) {
- continue;
- }
+ final Set thisFormNestedForms = new HashSet();
+ final CodeGenerationException[] validateExceptions = new CodeGenerationException[1];
+ final RecursiveFormNestingException[] recursiveNestingExceptions = new RecursiveFormNestingException[1];
+ rootContainer.accept(new ComponentVisitor() {
+ public boolean visit(final IComponent component) {
+ if (component instanceof LwNestedForm) {
+ LwNestedForm nestedForm = (LwNestedForm)component;
+ if (!thisFormNestedForms.contains(nestedForm.getFormFileName())) {
+ thisFormNestedForms.add(nestedForm.getFormFileName());
try {
- componentClass.getConstructor(new Class[]{});
+ validateNestedFormLoop(usedFormNames, nestedForm.getFormFileName(), nestedFormLoader);
}
- catch (NoSuchMethodException ex) {
- continue;
+ catch (RecursiveFormNestingException e) {
+ recursiveNestingExceptions[0] = e;
+ return false;
}
- return componentClass;
+ catch (CodeGenerationException e) {
+ validateExceptions[0] = e;
+ return false;
+ }
+ }
}
+ return true;
+ }
+ });
+ if (recursiveNestingExceptions[0] != null) {
+ throw recursiveNestingExceptions[0];
}
+ if (validateExceptions[0] != null) {
+ throw validateExceptions[0];
+ }
+ }
- public static int alignFromConstraints(final GridConstraints gc, final boolean horizontal) {
- int anchor = gc.getAnchor();
- int fill = gc.getFill();
- int leftMask = horizontal ? GridConstraints.ANCHOR_WEST : GridConstraints.ANCHOR_NORTH;
- int rightMask = horizontal ? GridConstraints.ANCHOR_EAST : GridConstraints.ANCHOR_SOUTH;
- int fillMask = horizontal ? GridConstraints.FILL_HORIZONTAL : GridConstraints.FILL_VERTICAL;
- if ((fill & fillMask) != 0) return GridConstraints.ALIGN_FILL;
- if ((anchor & rightMask) != 0) return GridConstraints.ALIGN_RIGHT;
- if ((anchor & leftMask) != 0) return GridConstraints.ALIGN_LEFT;
- return GridConstraints.ALIGN_CENTER;
+ public static String findNotEmptyPanelWithXYLayout(final IComponent component) {
+ if (!(component instanceof IContainer)) {
+ return null;
}
+ final IContainer container = (IContainer)component;
+ if (container.getComponentCount() == 0) {
+ return null;
+ }
+ if (container.isXY()) {
+ return container.getId();
+ }
+ for (int i = 0; i < container.getComponentCount(); i++) {
+ String id = findNotEmptyPanelWithXYLayout(container.getComponent(i));
+ if (id != null) {
+ return id;
+ }
+ }
+ return null;
+ }
- public static boolean isBoundField(IComponent component, String fieldName) {
- if (fieldName.equals(component.getBinding())) {
- return true;
- }
- if (component instanceof IContainer) {
- IContainer container = (IContainer)component;
- for (int i = 0; i < container.getComponentCount(); i++) {
- if (isBoundField(container.getComponent(i), fieldName)) {
- return true;
- }
- }
- }
- return false;
+ public static int getHGap(LayoutManager layout) {
+ if (layout instanceof BorderLayout) {
+ return ((BorderLayout)layout).getHgap();
}
+ if (layout instanceof CardLayout) {
+ return ((CardLayout)layout).getHgap();
+ }
+ return 0;
+ }
+
+ public static int getVGap(LayoutManager layout) {
+ if (layout instanceof BorderLayout) {
+ return ((BorderLayout)layout).getVgap();
+ }
+ if (layout instanceof CardLayout) {
+ return ((CardLayout)layout).getVgap();
+ }
+ return 0;
+ }
+
+ public static int getCustomCreateComponentCount(final IContainer container) {
+ final int[] result = new int[1];
+ result[0] = 0;
+ container.accept(new ComponentVisitor() {
+ public boolean visit(IComponent c) {
+ if (c.isCustomCreate()) {
+ result[0]++;
+ }
+ return true;
+ }
+ });
+ return result[0];
+ }
+
+ public static Class suggestReplacementClass(Class componentClass) {
+ while (true) {
+ componentClass = componentClass.getSuperclass();
+ if (componentClass.equals(JComponent.class)) {
+ return JPanel.class;
+ }
+ if ((componentClass.getModifiers() & (Modifier.ABSTRACT | Modifier.PRIVATE)) != 0) {
+ continue;
+ }
+ try {
+ componentClass.getConstructor(new Class[]{});
+ }
+ catch (NoSuchMethodException ex) {
+ continue;
+ }
+ return componentClass;
+ }
+ }
+
+ public static InstrumentationClassFinder.PseudoClass suggestReplacementClass(InstrumentationClassFinder.PseudoClass componentClass) throws ClassNotFoundException, IOException {
+ final InstrumentationClassFinder.PseudoClass jComponentClass = componentClass.getFinder().loadClass(JComponent.class.getName());
+ while (true) {
+ componentClass = componentClass.getSuperClass();
+ if (componentClass.equals(jComponentClass)) {
+ return componentClass.getFinder().loadClass(JPanel.class.getName());
+ }
+ if ((componentClass.getModifiers() & (Modifier.ABSTRACT | Modifier.PRIVATE)) != 0) {
+ continue;
+ }
+ if (!componentClass.hasDefaultPublicConstructor()) {
+ continue;
+ }
+ return componentClass;
+ }
+ }
+
+ public static int alignFromConstraints(final GridConstraints gc, final boolean horizontal) {
+ int anchor = gc.getAnchor();
+ int fill = gc.getFill();
+ int leftMask = horizontal ? GridConstraints.ANCHOR_WEST : GridConstraints.ANCHOR_NORTH;
+ int rightMask = horizontal ? GridConstraints.ANCHOR_EAST : GridConstraints.ANCHOR_SOUTH;
+ int fillMask = horizontal ? GridConstraints.FILL_HORIZONTAL : GridConstraints.FILL_VERTICAL;
+ if ((fill & fillMask) != 0) return GridConstraints.ALIGN_FILL;
+ if ((anchor & rightMask) != 0) return GridConstraints.ALIGN_RIGHT;
+ if ((anchor & leftMask) != 0) return GridConstraints.ALIGN_LEFT;
+ return GridConstraints.ALIGN_CENTER;
+ }
+
+ public static boolean isBoundField(IComponent component, String fieldName) {
+ if (fieldName.equals(component.getBinding())) {
+ return true;
+ }
+ if (component instanceof IContainer) {
+ IContainer container = (IContainer)component;
+ for (int i = 0; i < container.getComponentCount(); i++) {
+ if (isBoundField(container.getComponent(i), fieldName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
diff --git a/java/compiler/impl/compiler-impl.iml b/java/compiler/impl/compiler-impl.iml
index f517eff750db..d9d39953f177 100644
--- a/java/compiler/impl/compiler-impl.iml
+++ b/java/compiler/impl/compiler-impl.iml
@@ -14,7 +14,7 @@
-
+
diff --git a/java/compiler/notNull/notNull.iml b/java/compiler/instrumentation-util/instrumentation-util.iml
similarity index 100%
rename from java/compiler/notNull/notNull.iml
rename to java/compiler/instrumentation-util/instrumentation-util.iml
diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/InstrumentationClassFinder.java b/java/compiler/instrumentation-util/src/com/intellij/compiler/instrumentation/InstrumentationClassFinder.java
similarity index 71%
rename from jps/jps-builders/src/org/jetbrains/jps/incremental/java/InstrumentationClassFinder.java
rename to java/compiler/instrumentation-util/src/com/intellij/compiler/instrumentation/InstrumentationClassFinder.java
index 8b2ee439af91..de009b37c9bf 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/InstrumentationClassFinder.java
+++ b/java/compiler/instrumentation-util/src/com/intellij/compiler/instrumentation/InstrumentationClassFinder.java
@@ -1,10 +1,7 @@
-package org.jetbrains.jps.incremental.java;
+package com.intellij.compiler.instrumentation;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.EmptyVisitor;
import sun.misc.Resource;
@@ -12,6 +9,7 @@ import sun.misc.Resource;
import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
+import java.net.URLClassLoader;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -23,22 +21,81 @@ import java.util.zip.ZipFile;
public class InstrumentationClassFinder {
private static final PseudoClass[] EMPTY_PSEUDOCLASS_ARRAY = new PseudoClass[0];
private static final String CLASS_RESOURCE_EXTENSION = ".class";
+ private static final URL[] URL_EMPTY_ARRAY = new URL[0];
private final Map myLoaded = new HashMap(); // className -> class object
private final ClassFinderClasspath myPlatformClasspath;
private final ClassFinderClasspath myClasspath;
+ private final URL[] myPlatformUrls;
+ private final URL[] myClasspathUrls;
+ private ClassLoader myLoader;
+ private byte[] myBuffer;
- public InstrumentationClassFinder(final URL[] platformClasspath, final URL[] classpath) {
- myPlatformClasspath = new ClassFinderClasspath(platformClasspath);
- myClasspath = new ClassFinderClasspath(classpath);
+ public InstrumentationClassFinder(final URL[] cp) {
+ this(URL_EMPTY_ARRAY, cp);
+ }
+
+ public InstrumentationClassFinder(final URL[] platformUrls, final URL[] classpathUrls) {
+ myPlatformUrls = platformUrls;
+ myClasspathUrls = classpathUrls;
+ myPlatformClasspath = new ClassFinderClasspath(platformUrls);
+ myClasspath = new ClassFinderClasspath(classpathUrls);
+ }
+
+ // compatibility with legacy code requiring ClassLoader
+ public ClassLoader getLoader() {
+ ClassLoader loader = myLoader;
+ if (loader != null) {
+ return loader;
+ }
+ final URLClassLoader platformLoader = myPlatformUrls.length > 0 ? new URLClassLoader(myPlatformUrls, null) : null;
+ final ClassLoader cpLoader = new URLClassLoader(myClasspathUrls, platformLoader);
+ loader = new ClassLoader(cpLoader) {
+
+ public InputStream getResourceAsStream(String name) {
+ InputStream is = null;
+ is = super.getResourceAsStream(name);
+ if (is == null) {
+ try {
+ is = InstrumentationClassFinder.this.getResourceAsStream(name);
+ }
+ catch (IOException ignored) {
+ }
+ }
+ return is;
+ }
+
+ protected Class findClass(String name) throws ClassNotFoundException {
+ final InputStream is = lookupClassBeforeClasspath(name.replace('.', '/'));
+ if (is == null) {
+ throw new ClassNotFoundException(name);
+ }
+ try {
+ final byte[] bytes = loadBytes(is);
+ return defineClass(name, bytes, 0, bytes.length);
+ }
+ finally {
+ try {
+ is.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ }
+ };
+ myLoader = loader;
+ return loader;
}
public void releaseResources() {
myPlatformClasspath.releaseResources();
myClasspath.releaseResources();
myLoaded.clear();
+ myBuffer = null;
+ myLoader = null;
}
- public PseudoClass loadClass(final String internalName) throws IOException, ClassNotFoundException{
+ public PseudoClass loadClass(final String name) throws IOException, ClassNotFoundException{
+ final String internalName = name.replace('.', '/'); // normalize
final PseudoClass aClass = myLoaded.get(internalName);
if (aClass != null) {
return aClass;
@@ -81,12 +138,28 @@ public class InstrumentationClassFinder {
}
}
- @Nullable
+ public InputStream getResourceAsStream(String resourceName) throws IOException {
+ InputStream is = null;
+
+ Resource resource = myPlatformClasspath.getResource(resourceName, false);
+ if (resource != null) {
+ is = resource.getInputStream();
+ }
+
+ if (is == null) {
+ resource = myClasspath.getResource(resourceName, false);
+ if (resource != null) {
+ is = resource.getInputStream();
+ }
+ }
+
+ return is;
+ }
+
protected InputStream lookupClassBeforeClasspath(final String internalClassName) {
return null;
}
- @Nullable
protected InputStream lookupClassAfterClasspath(final String internalClassName) {
return null;
}
@@ -97,20 +170,61 @@ public class InstrumentationClassFinder {
reader.accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
- return new PseudoClass(visitor.myName, visitor.mySuperclassName, visitor.myInterfaces, visitor.myIsInterface);
+ return new PseudoClass(visitor.myName, visitor.mySuperclassName, visitor.myInterfaces, visitor.myModifiers, visitor.myMethods);
}
public final class PseudoClass {
private final String myName;
private final String mySuperClass;
private final String[] myInterfaces;
- private final boolean isInterface;
+ private final int myModifiers;
+ private final List myMethods;
- private PseudoClass(final String name, final String superClass, final String[] interfaces, final boolean anInterface) {
+ private PseudoClass(final String name, final String superClass, final String[] interfaces, final int modifiers, List methods) {
myName = name;
mySuperClass = superClass;
myInterfaces = interfaces;
- isInterface = anInterface;
+ myModifiers = modifiers;
+ myMethods = methods;
+ }
+
+ public int getModifiers() {
+ return myModifiers;
+ }
+
+ public boolean isInterface() {
+ return (myModifiers & Opcodes.ACC_INTERFACE) > 0;
+ }
+
+ public String getName() {
+ return myName;
+ }
+
+ public List getMethods() {
+ return myMethods;
+ }
+
+ public List findMethods(String name) {
+ final List result = new ArrayList();
+ for (PseudoMethod method : myMethods) {
+ if (method.getName().equals(name)){
+ result.add(method);
+ }
+ }
+ return result;
+ }
+
+ public PseudoMethod findMethod(String name, String descriptor) {
+ for (PseudoMethod method : myMethods) {
+ if (method.getName().equals(name) && method.getSignature().equals(descriptor)){
+ return method;
+ }
+ }
+ return null;
+ }
+
+ public InstrumentationClassFinder getFinder() {
+ return InstrumentationClassFinder.this;
}
public PseudoClass getSuperClass() throws IOException, ClassNotFoundException {
@@ -173,36 +287,69 @@ public class InstrumentationClassFinder {
if (x.implementsInterface(this)) {
return true;
}
- if (x.isInterface() && getName().equals("java/lang/Object")) {
+ if (x.isInterface() && "java/lang/Object".equals(getName())) {
return true;
}
return false;
}
- public boolean isInterface() {
- return isInterface;
+ public boolean hasDefaultPublicConstructor() {
+ for (PseudoMethod method : myMethods) {
+ if ("".equals(method.getName()) && "()V".equals(method.getSignature())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String getDescriptor() {
+ return "L" + myName + ";";
+ }
+ }
+
+ public static final class PseudoMethod {
+ private final int myAccess;
+ private final String myName;
+ private final String mySignature;
+
+ public PseudoMethod(int access, String name, String signature) {
+ myAccess = access;
+ myName = name;
+ mySignature = signature;
+ }
+
+ public int getModifiers() {
+ return myAccess;
}
public String getName() {
return myName;
}
+
+ public String getSignature() {
+ return mySignature;
+ }
}
private static class V extends EmptyVisitor {
public String mySuperclassName = null;
public String[] myInterfaces = null;
public String myName = null;
- public boolean myIsInterface = false;
+ public int myModifiers;
+ private final List myMethods = new ArrayList();
- public void visitAttribute(Attribute attr) {
- super.visitAttribute(attr);
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ if ((access & Opcodes.ACC_PUBLIC) > 0) {
+ myMethods.add(new PseudoMethod(access, name, desc));
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
}
public void visit(int version, int access, String pName, String signature, String pSuperName, String[] pInterfaces) {
mySuperclassName = pSuperName;
myInterfaces = pInterfaces;
myName = pName;
- myIsInterface = (access & Opcodes.ACC_INTERFACE) > 0;
+ myModifiers = access;
}
}
@@ -221,7 +368,6 @@ public class InstrumentationClassFinder {
}
}
- @Nullable
public Resource getResource(String s, boolean flag) {
int i = 0;
for (Loader loader; (loader = getLoader(i)) != null; i++) {
@@ -242,7 +388,6 @@ public class InstrumentationClassFinder {
myLoadersMap.clear();
}
- @Nullable
private synchronized Loader getLoader(int i) {
while (myLoaders.size() < i + 1) {
URL url;
@@ -275,7 +420,6 @@ public class InstrumentationClassFinder {
return myLoaders.get(i);
}
- @Nullable
private Loader getLoader(final URL url, int index) throws IOException {
String s;
try {
@@ -317,7 +461,6 @@ public class InstrumentationClassFinder {
return myURL;
}
- @Nullable
public abstract Resource getResource(final String name, boolean flag);
public abstract void releaseResources();
@@ -345,7 +488,6 @@ public class InstrumentationClassFinder {
public void releaseResources() {
}
- @Nullable
public Resource getResource(final String name, boolean check) {
URL url = null;
File file = null;
@@ -410,7 +552,6 @@ public class InstrumentationClassFinder {
}
}
- @NonNls
public String toString() {
return "FileLoader [" + myRootDir + "]";
}
@@ -438,7 +579,6 @@ public class InstrumentationClassFinder {
}
}
- @Nullable
private ZipFile acquireZipFile() throws IOException {
ZipFile zipFile = myZipFile;
if (zipFile == null) {
@@ -448,7 +588,6 @@ public class InstrumentationClassFinder {
return zipFile;
}
- @Nullable
private ZipFile doGetZipFile() throws IOException {
if (FILE_PROTOCOL.equals(myURL.getProtocol())) {
String s = unescapePercentSequences(myURL.getFile().replace('/', File.separatorChar));
@@ -463,7 +602,6 @@ public class InstrumentationClassFinder {
return null;
}
- @Nullable
public Resource getResource(String name, boolean flag) {
try {
final ZipFile file = acquireZipFile();
@@ -501,11 +639,9 @@ public class InstrumentationClassFinder {
return myURL;
}
- @Nullable
public InputStream getInputStream() throws IOException {
- ZipFile file = null;
try {
- file = acquireZipFile();
+ final ZipFile file = acquireZipFile();
if (file == null) {
return null;
}
@@ -527,7 +663,6 @@ public class InstrumentationClassFinder {
}
}
- @NonNls
public String toString() {
return "JarLoader [" + myURL + "]";
}
@@ -535,8 +670,7 @@ public class InstrumentationClassFinder {
}
- @NotNull
- private static String unescapePercentSequences(@NotNull String s) {
+ private static String unescapePercentSequences(String s) {
if (s.indexOf('%') == -1) {
return s;
}
@@ -591,4 +725,27 @@ public class InstrumentationClassFinder {
return -1;
}
+ public byte[] loadBytes(InputStream stream) {
+ byte[] buf = myBuffer;
+ if (buf == null) {
+ buf = new byte[512];
+ myBuffer = buf;
+ }
+
+ final ByteArrayOutputStream result = new ByteArrayOutputStream();
+ try {
+ while (true) {
+ int n = stream.read(buf, 0, buf.length);
+ if (n <= 0) {
+ break;
+ }
+ result.write(buf, 0, n);
+ }
+ result.close();
+ }
+ catch (IOException ignored) {
+ }
+ return result.toByteArray();
+ }
+
}
diff --git a/java/compiler/instrumentation-util/src/com/intellij/compiler/instrumentation/InstrumenterClassWriter.java b/java/compiler/instrumentation-util/src/com/intellij/compiler/instrumentation/InstrumenterClassWriter.java
new file mode 100644
index 000000000000..ffdf058a2fbf
--- /dev/null
+++ b/java/compiler/instrumentation-util/src/com/intellij/compiler/instrumentation/InstrumenterClassWriter.java
@@ -0,0 +1,43 @@
+package com.intellij.compiler.instrumentation;
+
+import org.objectweb.asm.ClassWriter;
+
+/**
+* @author Eugene Zhuravlev
+* Date: 3/27/12
+*/
+public class InstrumenterClassWriter extends ClassWriter {
+ private final InstrumentationClassFinder myFinder;
+
+ public InstrumenterClassWriter(int flags, final InstrumentationClassFinder finder) {
+ super(flags);
+ myFinder = finder;
+ }
+
+ protected String getCommonSuperClass(final String type1, final String type2) {
+ try {
+ final InstrumentationClassFinder.PseudoClass cls1 = myFinder.loadClass(type1);
+ final InstrumentationClassFinder.PseudoClass cls2 = myFinder.loadClass(type2);
+ if (cls1.isAssignableFrom(cls2)) {
+ return cls1.getName();
+ }
+ if (cls2.isAssignableFrom(cls1)) {
+ return cls2.getName();
+ }
+ if (cls1.isInterface() || cls2.isInterface()) {
+ return "java/lang/Object";
+ }
+ else {
+ InstrumentationClassFinder.PseudoClass c = cls1;
+ do {
+ c = c.getSuperClass();
+ }
+ while (!c.isAssignableFrom(cls2));
+ return c.getName();
+ }
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e.toString(), e);
+ }
+ }
+}
diff --git a/java/compiler/notNull/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java b/java/compiler/instrumentation-util/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java
similarity index 100%
rename from java/compiler/notNull/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java
rename to java/compiler/instrumentation-util/src/com/intellij/compiler/notNullVerification/NotNullVerifyingInstrumenter.java
diff --git a/java/compiler/javac2/javac2.iml b/java/compiler/javac2/javac2.iml
index 49c3fa54efee..a8680af11500 100644
--- a/java/compiler/javac2/javac2.iml
+++ b/java/compiler/javac2/javac2.iml
@@ -11,7 +11,7 @@
-
+
diff --git a/java/compiler/javac2/src/com/intellij/ant/AntClassWriter.java b/java/compiler/javac2/src/com/intellij/ant/AntClassWriter.java
deleted file mode 100644
index dc8b6552147d..000000000000
--- a/java/compiler/javac2/src/com/intellij/ant/AntClassWriter.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2000-2009 JetBrains s.r.o.
- *
- * Licensed 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 com.intellij.ant;
-
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassWriter;
-
-import java.io.IOException;
-
-/**
- * @author yole
- */
-public class AntClassWriter extends ClassWriter {
- private final PseudoClassLoader myPseudoClassLoader;
-
- public AntClassWriter(int flags, final PseudoClassLoader pseudoLoader) {
- super(flags);
- myPseudoClassLoader = pseudoLoader;
- }
-
- public AntClassWriter(ClassReader classReader, int flags, final PseudoClassLoader pseudoLoader) {
- super(classReader, flags);
- myPseudoClassLoader = pseudoLoader;
- }
-
- protected String getCommonSuperClass(final String type1, final String type2) {
- try {
- PseudoClassLoader.PseudoClass p1 = myPseudoClassLoader.loadClass(type1);
- PseudoClassLoader.PseudoClass p2 = myPseudoClassLoader.loadClass(type2);
-
- return p1.getCommonSuperClassName(p2);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- throw new RuntimeException(e.getMessage());
- }
- catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException(e.getMessage());
- }
- }
-}
diff --git a/java/compiler/javac2/src/com/intellij/ant/InstrumentationUtil.java b/java/compiler/javac2/src/com/intellij/ant/InstrumentationUtil.java
index 8409618031a9..eb423ae59820 100644
--- a/java/compiler/javac2/src/com/intellij/ant/InstrumentationUtil.java
+++ b/java/compiler/javac2/src/com/intellij/ant/InstrumentationUtil.java
@@ -15,6 +15,8 @@
*/
package com.intellij.ant;
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
+import com.intellij.compiler.instrumentation.InstrumenterClassWriter;
import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter;
import com.intellij.uiDesigner.compiler.*;
import com.intellij.uiDesigner.lw.CompiledClassPropertiesProvider;
@@ -39,14 +41,14 @@ import java.util.*;
*/
public class InstrumentationUtil {
- public static PseudoClassLoader createPseudoClassLoader(final String classPath) throws MalformedURLException {
+ public static InstrumentationClassFinder createInstrumentationClassFinder(final String classPath) throws MalformedURLException {
final ArrayList urls = new ArrayList();
for (StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); tokenizer.hasMoreTokens();) {
final String s = tokenizer.nextToken();
urls.add(new File(s).toURL());
}
final URL[] urlsArr = (URL[])urls.toArray(new URL[urls.size()]);
- return new PseudoClassLoader(urlsArr);
+ return new InstrumentationClassFinder(urlsArr);
}
public static int getClassFileVersion(ClassReader reader) {
@@ -108,12 +110,12 @@ public class InstrumentationUtil {
}
private class AntNestedFormLoader implements NestedFormLoader {
- private final PseudoClassLoader myLoader;
+ private final InstrumentationClassFinder myClassFinder;
private final List myNestedFormPathList;
private final HashMap myFormCache = new HashMap();
- public AntNestedFormLoader(final PseudoClassLoader loader, List nestedFormPathList) {
- myLoader = loader;
+ public AntNestedFormLoader(final InstrumentationClassFinder classFinder, List nestedFormPathList) {
+ myClassFinder = classFinder;
myNestedFormPathList = nestedFormPathList;
}
@@ -143,7 +145,7 @@ public class InstrumentationUtil {
}
}
}
- InputStream resourceStream = myLoader.getLoader ().getResourceAsStream(formFilePath);
+ InputStream resourceStream = myClassFinder.getResourceAsStream(formFilePath);
if (resourceStream != null) {
return loadForm(formFilePath, resourceStream);
}
@@ -164,11 +166,11 @@ public class InstrumentationUtil {
}
}
- public void instrumentForm(final File file, final PseudoClassLoader loader) {
+ public void instrumentForm(final File file, final InstrumentationClassFinder classFinder) {
log("compiling form " + file.getAbsolutePath(), Project.MSG_VERBOSE);
final LwRootContainer rootContainer;
try {
- rootContainer = Utils.getRootContainer(file.toURL(), new CompiledClassPropertiesProvider(loader.getLoader ()));
+ rootContainer = Utils.getRootContainer(file.toURL(), new CompiledClassPropertiesProvider(classFinder.getLoader()));
}
catch (AlienFormFileException e) {
// ignore non-IDEA forms
@@ -216,9 +218,9 @@ public class InstrumentationUtil {
finally {
stream.close();
}
- AntNestedFormLoader formLoader = new AntNestedFormLoader(loader, myNestedFormPathList);
- AntClassWriter classWriter = new AntClassWriter(InstrumentationUtil.getAsmClassWriterFlags(version), loader);
- final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, loader.getLoader(), formLoader, false, classWriter);
+ AntNestedFormLoader formLoader = new AntNestedFormLoader(classFinder, myNestedFormPathList);
+ InstrumenterClassWriter classWriter = new InstrumenterClassWriter(InstrumentationUtil.getAsmClassWriterFlags(version), classFinder);
+ final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, classFinder, formLoader, false, classWriter);
codeGenerator.patchFile(classFile);
final FormErrorInfo[] warnings = codeGenerator.getWarnings();
@@ -243,15 +245,15 @@ public class InstrumentationUtil {
}
}
- public static byte[] instrumentNotNull(final byte[] buffer, final PseudoClassLoader loader) {
+ public static byte[] instrumentNotNull(final byte[] buffer, final InstrumentationClassFinder loader) {
return instrumentNotNull(new ClassReader (buffer), loader);
}
- private static byte[] instrumentNotNull(final ClassReader reader, final PseudoClassLoader loader) {
+ private static byte[] instrumentNotNull(final ClassReader reader, final InstrumentationClassFinder loader) {
int version = getClassFileVersion(reader);
if (version >= Opcodes.V1_5) {
- ClassWriter writer = new AntClassWriter(getAsmClassWriterFlags(version), loader);
+ ClassWriter writer = new InstrumenterClassWriter(getAsmClassWriterFlags(version), loader);
final NotNullVerifyingInstrumenter instrumenter = new NotNullVerifyingInstrumenter(writer);
reader.accept(instrumenter, 0);
@@ -264,7 +266,7 @@ public class InstrumentationUtil {
return null;
}
- public static int instrumentNotNull(final File file, final PseudoClassLoader loader) throws IOException {
+ public static int instrumentNotNull(final File file, final InstrumentationClassFinder loader) throws IOException {
int instrumented = 0;
final String path = file.getPath();
final FileInputStream inputStream = new FileInputStream(file);
diff --git a/java/compiler/javac2/src/com/intellij/ant/Javac2.java b/java/compiler/javac2/src/com/intellij/ant/Javac2.java
index be4354258ac8..5c3035534b44 100644
--- a/java/compiler/javac2/src/com/intellij/ant/Javac2.java
+++ b/java/compiler/javac2/src/com/intellij/ant/Javac2.java
@@ -15,6 +15,8 @@
*/
package com.intellij.ant;
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
+import com.intellij.compiler.instrumentation.InstrumenterClassWriter;
import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter;
import com.intellij.uiDesigner.compiler.*;
import com.intellij.uiDesigner.lw.CompiledClassPropertiesProvider;
@@ -201,26 +203,34 @@ public class Javac2 extends Javac {
* class files.
*/
protected void compile() {
- // compile java
- if (areJavaClassesCompiled()) {
- super.compile();
- }
+ // compile java
+ if (areJavaClassesCompiled()) {
+ super.compile();
+ }
- PseudoClassLoader loader = buildClasspathClassLoader();
- if (loader == null) return;
- instrumentForms(loader);
+ InstrumentationClassFinder finder = buildClasspathClassLoader();
+ if (finder == null) {
+ return;
+ }
+ try {
+ instrumentForms(finder);
//NotNull instrumentation
- final int instrumented = instrumentNotNull(getDestdir(), loader);
+ final int instrumented = instrumentNotNull(getDestdir(), finder);
+
log("Added @NotNull assertions to " + instrumented + " files", Project.MSG_INFO);
+ }
+ finally {
+ finder.releaseResources();
+ }
}
- /**
+ /**
* Instrument forms
*
- * @param loader a classloader to use
+ * @param finder a classloader to use
*/
- private void instrumentForms(final PseudoClassLoader loader) {
+ private void instrumentForms(final InstrumentationClassFinder finder) {
// we instrument every file, because we cannot find which files should not be instrumented without dependency storage
final ArrayList formsToInstrument = myFormFiles;
@@ -237,7 +247,7 @@ public class Javac2 extends Javac {
log("compiling form " + formFile.getAbsolutePath(), Project.MSG_VERBOSE);
final LwRootContainer rootContainer;
try {
- rootContainer = Utils.getRootContainer(formFile.toURL(), new CompiledClassPropertiesProvider(loader.getLoader()));
+ rootContainer = Utils.getRootContainer(formFile.toURL(), new CompiledClassPropertiesProvider(finder.getLoader()));
}
catch (AlienFormFileException e) {
// ignore non-IDEA forms
@@ -283,9 +293,9 @@ public class Javac2 extends Javac {
finally {
stream.close();
}
- AntNestedFormLoader formLoader = new AntNestedFormLoader(loader.getLoader(), myNestedFormPathList);
- AntClassWriter classWriter = new AntClassWriter(getAsmClassWriterFlags(version), loader);
- final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, loader.getLoader(), formLoader, false, classWriter);
+ AntNestedFormLoader formLoader = new AntNestedFormLoader(finder.getLoader(), myNestedFormPathList);
+ InstrumenterClassWriter classWriter = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder);
+ final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, finder, formLoader, false, classWriter);
codeGenerator.patchFile(classFile);
final FormErrorInfo[] warnings = codeGenerator.getWarnings();
@@ -322,7 +332,7 @@ public class Javac2 extends Javac {
*
* @return a URL classloader
*/
- private PseudoClassLoader buildClasspathClassLoader() {
+ private InstrumentationClassFinder buildClasspathClassLoader() {
final StringBuffer classPathBuffer = new StringBuffer();
final Path cp = new Path(getProject());
appendPath(cp, getBootclasspath());
@@ -349,7 +359,7 @@ public class Javac2 extends Javac {
log("classpath=" + classPath, Project.MSG_VERBOSE);
try {
- return InstrumentationUtil.createPseudoClassLoader(classPath);
+ return InstrumentationUtil.createInstrumentationClassFinder(classPath);
}
catch (MalformedURLException e) {
fireError(e.getMessage());
@@ -373,10 +383,10 @@ public class Javac2 extends Javac {
* Instrument classes with NotNull annotations
*
* @param dir the directory with classes to instrument (the directory is processed recursively)
- * @param loader the classloader to use
+ * @param finder the classloader to use
* @return the amount of classes actually affected by instrumentation
*/
- private int instrumentNotNull(File dir, final PseudoClassLoader loader) {
+ private int instrumentNotNull(File dir, final InstrumentationClassFinder finder) {
int instrumented = 0;
final File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
@@ -393,7 +403,7 @@ public class Javac2 extends Javac {
int version = getClassFileVersion(reader);
if (version >= Opcodes.V1_5) {
- ClassWriter writer = new AntClassWriter(getAsmClassWriterFlags(version), loader);
+ ClassWriter writer = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder);
final NotNullVerifyingInstrumenter instrumenter = new NotNullVerifyingInstrumenter(writer);
reader.accept(instrumenter, 0);
@@ -421,7 +431,7 @@ public class Javac2 extends Javac {
}
}
else if (file.isDirectory()) {
- instrumented += instrumentNotNull(file, loader);
+ instrumented += instrumentNotNull(file, finder);
}
}
diff --git a/java/compiler/javac2/src/com/intellij/ant/PseudoClassLoader.java b/java/compiler/javac2/src/com/intellij/ant/PseudoClassLoader.java
deleted file mode 100644
index 97a4172d7b94..000000000000
--- a/java/compiler/javac2/src/com/intellij/ant/PseudoClassLoader.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright 2000-2011 JetBrains s.r.o.
- *
- * Licensed 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 com.intellij.ant;
-
-import org.objectweb.asm.Attribute;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.commons.EmptyVisitor;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-/**
- * @author db
- * Date: 06.06.11
- */
-public class PseudoClassLoader {
- static final WeakHashMap myCache = new WeakHashMap();
-
- final Map myDefinedClasses = new HashMap ();
- final Map myDefinedClassesData = new HashMap ();
-
- private class MemoryClassLoader extends ClassLoader {
- public MemoryClassLoader(URLClassLoader classpathLoader) {
- super(classpathLoader);
- }
-
- protected Class findClass(String name) throws ClassNotFoundException {
- final byte[] data = (byte[])myDefinedClassesData.get(name);
- if (data == null) {
- throw new ClassNotFoundException(name);
- }
- return defineClass(name, data, 0, data.length);
- }
-
- public URL findResource(String name) {
- return super.findResource(name);
- }
- }
-
- public class PseudoClass {
- final String myName;
- final String mySuperClass;
- final String[] myInterfaces;
- final boolean isInterface;
-
- private PseudoClass(final Class repr) {
- final Class superclass = repr.getSuperclass();
- final Class[] interfaces = repr.getInterfaces();
-
- myName = repr.getName().replace('.', '/');
- mySuperClass = superclass == null ? null : superclass.getName().replace('.', '/');
- myInterfaces = interfaces.length == 0 ? null : new String[interfaces.length];
-
- for (int i=0; i 0;
- }
- }
-
- private PseudoClass createPseudoClass(final ClassReader r) {
- final V visitor = new V();
-
- r.accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
-
- return new PseudoClass(visitor.name, visitor.superName, visitor.interfaces, visitor.isInterface);
- }
-
- private class Tag {
- final PseudoClass myClass;
- final long myStamp;
-
- private Tag(PseudoClass aClass, long stamp) {
- myClass = aClass;
- myStamp = stamp;
- }
- }
-
- public PseudoClass loadClass(final String internalName) throws IOException, ClassNotFoundException {
- final PseudoClass defined = (PseudoClass) myDefinedClasses.get(internalName);
-
- if (defined != null) {
- return defined;
- }
-
- final URL resource = myLoader.findResource(internalName + ".class");
-
- if (resource == null) {
- final Class lastResort = myLoader.loadClass(internalName.replace('/', '.'));
- return new PseudoClass(lastResort);
- }
-
- final String fileName = resource.getFile();
- final boolean isFile = fileName.length() > 0;
- final File file = new File(fileName);
-
- if (isFile) {
- final Tag cached = (Tag)myCache.get(internalName);
-
- if (cached != null && cached.myStamp == file.lastModified()) {
- return cached.myClass;
- }
- }
-
- final InputStream content = (InputStream)resource.getContent();
- final ClassReader reader = new ClassReader(content);
- final PseudoClass result = createPseudoClass(reader);
-
- if (isFile) {
- myCache.put(internalName, new Tag(result, file.lastModified()));
- }
-
- return result;
- }
-}
diff --git a/java/java-tests/java-tests.iml b/java/java-tests/java-tests.iml
index 1750b2ea3852..38e0eb6d4c3d 100644
--- a/java/java-tests/java-tests.iml
+++ b/java/java-tests/java-tests.iml
@@ -17,7 +17,7 @@
-
+
diff --git a/jps/jps-builders/jps-builders.iml b/jps/jps-builders/jps-builders.iml
index 9c5878d1e2f3..e27c35289a56 100644
--- a/jps/jps-builders/jps-builders.iml
+++ b/jps/jps-builders/jps-builders.iml
@@ -12,7 +12,7 @@
-
+
diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java
index 10b03b898693..5378c096312a 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java
@@ -1,5 +1,7 @@
package org.jetbrains.jps.incremental.java;
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
+import com.intellij.compiler.instrumentation.InstrumenterClassWriter;
import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter;
import com.intellij.execution.process.BaseOSProcessHandler;
import com.intellij.openapi.application.PathManager;
@@ -37,7 +39,6 @@ import java.io.*;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.URL;
-import java.net.URLClassLoader;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
@@ -274,15 +275,14 @@ public class JavaBuilder extends ModuleLevelBuilder {
context.checkCanceled();
if (!forms.isEmpty() || addNotNullAssertions) {
- final InstrumentationClassFinder finder = createInstrumentationClassFinder(platformCp, classpath, outputSink);
+ final Map chunkSourcePath = ProjectPaths.getSourceRootsWithDependents(chunk, context.isCompilingTests());
+ final InstrumentationClassFinder finder = createInstrumentationClassFinder(platformCp, classpath, chunkSourcePath, outputSink);
try {
if (!forms.isEmpty()) {
try {
context.processMessage(new ProgressMessage("Instrumenting forms [" + chunkName + "]"));
- final Map chunkSourcePath = ProjectPaths.getSourceRootsWithDependents(chunk, context.isCompilingTests());
- final ClassLoader loader = createInstrumentationClassLoader(platformCp, classpath, chunkSourcePath, outputSink);
- instrumentForms(context, chunk, chunkSourcePath, loader, finder, forms, outputSink);
+ instrumentForms(context, chunk, chunkSourcePath, finder, forms, outputSink);
}
finally {
context.processMessage(new ProgressMessage("Finished instrumenting forms [" + chunkName + "]"));
@@ -529,22 +529,24 @@ public class JavaBuilder extends ModuleLevelBuilder {
private static InstrumentationClassFinder createInstrumentationClassFinder(Collection platformCp,
Collection classpath,
- final OutputFilesSink outputSink) throws MalformedURLException {
+ Map chunkSourcePath, final OutputFilesSink outputSink) throws MalformedURLException {
final URL[] platformUrls = new URL[platformCp.size()];
int index = 0;
for (File file : platformCp) {
platformUrls[index++] = file.toURI().toURL();
}
- final URL[] urls = new URL[classpath.size() + 1];
- index = 0;
+ final List urls = new ArrayList(classpath.size() + chunkSourcePath.size() + 1);
for (File file : classpath) {
- urls[index++] = file.toURI().toURL();
+ urls.add(file.toURI().toURL());
}
- urls[index++] = getResourcePath(GridConstraints.class).toURI().toURL(); // forms_rt.jar
+ urls.add(getResourcePath(GridConstraints.class).toURI().toURL()); // forms_rt.jar
//urls.add(getResourcePath(CellConstraints.class).toURI().toURL()); // jgoodies-forms
-
- return new InstrumentationClassFinder(platformUrls, urls) {
+ for (File file : chunkSourcePath.keySet()) { // sourcepath for loading forms resources
+ urls.add(file.toURI().toURL());
+ }
+
+ return new InstrumentationClassFinder(platformUrls, urls.toArray(new URL[urls.size()])) {
protected InputStream lookupClassBeforeClasspath(String internalClassName) {
final OutputFileObject.Content content = outputSink.lookupClassBytes(internalClassName.replace("/", "."));
if (content != null) {
@@ -555,23 +557,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
};
}
- private static ClassLoader createInstrumentationClassLoader(Collection platformCp, Collection classpath,
- Map chunkSourcePath,
- OutputFilesSink outputSink) throws MalformedURLException {
- final List urls = new ArrayList();
- for (Collection cp : Arrays.asList(platformCp, classpath)) {
- for (File file : cp) {
- urls.add(file.toURI().toURL());
- }
- }
- urls.add(getResourcePath(GridConstraints.class).toURI().toURL()); // forms_rt.jar
- //urls.add(getResourcePath(CellConstraints.class).toURI().toURL()); // jgoodies-forms
- for (File file : chunkSourcePath.keySet()) {
- urls.add(file.toURI().toURL());
- }
- return new CompiledClassesLoader(outputSink, urls.toArray(new URL[urls.size()]));
- }
-
private static final Key> JAVAC_OPTIONS = Key.create("_javac_options_");
private static final Key> JAVAC_VM_OPTIONS = Key.create("_javac_vm_options_");
@@ -713,7 +698,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
private static void instrumentForms(CompileContext context,
ModuleChunk chunk,
final Map chunkSourcePath,
- final ClassLoader loader,
final InstrumentationClassFinder finder, Collection formsToInstrument,
OutputFilesSink outputSink) throws ProjectBuildException {
@@ -731,7 +715,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
for (File formFile : formsToInstrument) {
final LwRootContainer rootContainer;
try {
- rootContainer = Utils.getRootContainer(formFile.toURI().toURL(), new CompiledClassPropertiesProvider(loader));
+ rootContainer = Utils.getRootContainer(formFile.toURI().toURL(), new CompiledClassPropertiesProvider(finder.getLoader()));
}
catch (AlienFormFileException e) {
// ignore non-IDEA forms
@@ -774,7 +758,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
final int version = getClassFileVersion(classReader);
final InstrumenterClassWriter classWriter = new InstrumenterClassWriter(getAsmClassWriterFlags(version), finder);
- final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, loader, nestedFormsLoader, false, classWriter);
+ final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, finder, nestedFormsLoader, false, classWriter);
final byte[] patchedBytes = codeGenerator.patchClass(classReader);
if (patchedBytes != null) {
outputClassFile.updateContent(patchedBytes);
@@ -923,42 +907,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
}
- public static class InstrumenterClassWriter extends ClassWriter {
- private final InstrumentationClassFinder myFinder;
-
- public InstrumenterClassWriter(int flags, final InstrumentationClassFinder finder) {
- super(flags);
- myFinder = finder;
- }
-
- protected String getCommonSuperClass(final String type1, final String type2) {
- try {
- final InstrumentationClassFinder.PseudoClass cls1 = myFinder.loadClass(type1);
- final InstrumentationClassFinder.PseudoClass cls2 = myFinder.loadClass(type2);
- if (cls1.isAssignableFrom(cls2)) {
- return cls1.getName();
- }
- if (cls2.isAssignableFrom(cls1)) {
- return cls2.getName();
- }
- if (cls1.isInterface() || cls2.isInterface()) {
- return "java/lang/Object";
- }
- else {
- InstrumentationClassFinder.PseudoClass c = cls1;
- do {
- c = c.getSuperClass();
- }
- while (!c.isAssignableFrom(cls2));
- return c.getName();
- }
- }
- catch (Exception e) {
- throw new RuntimeException(e.toString(), e);
- }
- }
- }
-
private static class MyNestedFormLoader implements NestedFormLoader {
private final Map mySourceRoots;
private final Collection myOutputRoots;
@@ -1039,27 +987,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
return new File(PathManager.getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class"));
}
- private static class CompiledClassesLoader extends URLClassLoader {
- private final OutputFilesSink mySink;
-
- public CompiledClassesLoader(OutputFilesSink sink, URL[] urls) {
- super(urls, null);
- mySink = sink;
- }
-
- protected Class findClass(String name) throws ClassNotFoundException {
- final OutputFileObject.Content content = mySink.lookupClassBytes(name);
- if (content != null) {
- return defineClass(name, content.getBuffer(), content.getOffset(), content.getLength());
- }
- return super.findClass(name);
- }
-
- public URL findResource(String name) {
- return super.findResource(name);
- }
- }
-
private class ClassProcessingConsumer implements OutputFileConsumer {
private final CompileContext myCompileContext;
private final OutputFileConsumer myDelegateOutputFileSink;
diff --git a/jps/jps.iml b/jps/jps.iml
index 44d24bb8c46f..c08dac3c1a16 100644
--- a/jps/jps.iml
+++ b/jps/jps.iml
@@ -34,6 +34,7 @@
+
diff --git a/jps/src/org/jetbrains/jps/ModuleBuildState.groovy b/jps/src/org/jetbrains/jps/ModuleBuildState.groovy
index b82ef2422486..52f15608c417 100644
--- a/jps/src/org/jetbrains/jps/ModuleBuildState.groovy
+++ b/jps/src/org/jetbrains/jps/ModuleBuildState.groovy
@@ -1,7 +1,7 @@
package org.jetbrains.jps
import com.intellij.ant.InstrumentationUtil.FormInstrumenter
-import com.intellij.ant.PseudoClassLoader
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder
import org.jetbrains.ether.ProjectWrapper
import org.jetbrains.ether.dependencyView.Callbacks.Backend
@@ -13,7 +13,7 @@ class ModuleBuildState {
boolean tests
Backend callback
FormInstrumenter formInstrumenter
- PseudoClassLoader loader
+ InstrumentationClassFinder loader
ProjectWrapper projectWrapper
List sourceFiles
List sourceRoots
diff --git a/jps/src/org/jetbrains/jps/builders/StandardBuilders.groovy b/jps/src/org/jetbrains/jps/builders/StandardBuilders.groovy
index babacca78d33..1c7537687a48 100644
--- a/jps/src/org/jetbrains/jps/builders/StandardBuilders.groovy
+++ b/jps/src/org/jetbrains/jps/builders/StandardBuilders.groovy
@@ -3,6 +3,7 @@ package org.jetbrains.jps.builders
import com.intellij.ant.InstrumentationUtil
import com.intellij.ant.InstrumentationUtil.FormInstrumenter
import com.intellij.ant.PrefixedPath
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder
import org.apache.tools.ant.BuildListener
import org.jetbrains.ether.ProjectWrapper
import org.jetbrains.ether.dependencyView.AntListener
@@ -332,17 +333,13 @@ class JetBrainsInstrumentations implements ModuleBuilder {
def processModule(ModuleBuildState state, ModuleChunk moduleChunk, ProjectBuilder projectBuilder) {
if (state.loader == null) {
- final StringBuilder cp = new StringBuilder()
-
- cp.append(state.targetFolder)
- cp.append(File.pathSeparator)
-
+ final ArrayList urls = new ArrayList();
+ urls.add(new File(state.targetFolder).toURL());
state.classpath.each {
- cp.append(it)
- cp.append(File.pathSeparator)
+ urls.add(new File(it).toURL());
}
- state.loader = InstrumentationUtil.createPseudoClassLoader(cp.toString())
+ state.loader = new InstrumentationClassFinder((URL[])urls.toArray(new URL[urls.size()]))
final List formFiles = new ArrayList();
final ProjectWrapper pw = state.projectWrapper;
@@ -409,6 +406,9 @@ class JetBrainsInstrumentations implements ModuleBuilder {
InstrumentationUtil.instrumentNotNull(new File(state.targetFolder + File.separator + it + ".class"), state.loader)
}
}
+ if (state.loader != null) {
+ state.loader.releaseResources();
+ }
}
}
diff --git a/jps/src/org/jetbrains/jps/builders/javacApi/Java16ApiCompiler.groovy b/jps/src/org/jetbrains/jps/builders/javacApi/Java16ApiCompiler.groovy
index 7ca3bb2dc8f3..a235e2fd9c97 100644
--- a/jps/src/org/jetbrains/jps/builders/javacApi/Java16ApiCompiler.groovy
+++ b/jps/src/org/jetbrains/jps/builders/javacApi/Java16ApiCompiler.groovy
@@ -1,17 +1,17 @@
package org.jetbrains.jps.builders.javacApi
-import com.intellij.ant.InstrumentationUtil
-import javax.tools.JavaCompiler
-import javax.tools.JavaCompiler.CompilationTask
-import javax.tools.JavaFileObject
-import javax.tools.StandardLocation
-import javax.tools.ToolProvider
import org.jetbrains.jps.ModuleBuildState
import org.jetbrains.jps.ModuleChunk
import org.jetbrains.jps.ProjectBuilder
import org.jetbrains.jps.Sdk
import org.jetbrains.jps.builders.JavaFileCollector
+import javax.tools.JavaCompiler
+import javax.tools.JavaCompiler.CompilationTask
+import javax.tools.JavaFileObject
+import javax.tools.StandardLocation
+import javax.tools.ToolProvider
+
/**
* @author nik
*/
@@ -89,7 +89,7 @@ class Java16ApiCompiler {
cp.append(state.targetFolder)
fileManager.setLocation(StandardLocation.CLASS_PATH, classpath)
- fileManager.setProperties(state.callback, InstrumentationUtil.createPseudoClassLoader(cp.toString()))
+ fileManager.setProperties(state.callback, toURLs(cp.toString()))
Iterable extends JavaFileObject> toCompile = fileManager.getJavaFileObjectsFromFiles(filesToCompile)
StringWriter out = new StringWriter()
@@ -109,4 +109,13 @@ class Java16ApiCompiler {
}
}
+ private URL[] toURLs(final String classPath) {
+ final List urls = new ArrayList();
+ for (StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); tokenizer.hasMoreTokens();) {
+ final String s = tokenizer.nextToken();
+ urls.add(new File(s).toURL());
+ }
+ return (URL[])urls.toArray(new URL[urls.size()]);
+ }
+
}
diff --git a/jps/src/org/jetbrains/jps/builders/javacApi/OptimizedFileManager.java b/jps/src/org/jetbrains/jps/builders/javacApi/OptimizedFileManager.java
index a4617a93289d..d7163000ea5d 100644
--- a/jps/src/org/jetbrains/jps/builders/javacApi/OptimizedFileManager.java
+++ b/jps/src/org/jetbrains/jps/builders/javacApi/OptimizedFileManager.java
@@ -1,7 +1,7 @@
package org.jetbrains.jps.builders.javacApi;
import com.intellij.ant.InstrumentationUtil;
-import com.intellij.ant.PseudoClassLoader;
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.DefaultFileManager;
import com.sun.tools.javac.util.List;
@@ -14,10 +14,9 @@ import javax.lang.model.SourceVersion;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileObject;
import javax.tools.JavaFileObject;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
+import java.io.*;
import java.lang.reflect.Field;
+import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -34,11 +33,17 @@ public class OptimizedFileManager extends DefaultFileManager {
private final Map myArchives;
private final Map myIsFile = new ConcurrentHashMap();
private Callbacks.Backend callback;
- private PseudoClassLoader loader;
+ private InstrumentationClassFinder classFinder;
+ private Map myCompiledClasses = new HashMap();
- public void setProperties(final Callbacks.Backend c, final PseudoClassLoader l) {
+ public void setProperties(final Callbacks.Backend c, final URL[] classpath) {
callback = c;
- loader = l;
+ classFinder = new InstrumentationClassFinder(classpath) {
+ protected InputStream lookupClassBeforeClasspath(String internalClassName) {
+ final byte[] bytes = myCompiledClasses.get(internalClassName);
+ return bytes != null? new ByteArrayInputStream(bytes) : null;
+ }
+ };
}
public OptimizedFileManager() {
@@ -201,7 +206,7 @@ public class OptimizedFileManager extends DefaultFileManager {
final byte[] buffer = Arrays.copyOfRange(b, off, len);
if (kind.equals(JavaFileObject.Kind.CLASS)) {
- loader.defineClass(className.replaceAll("\\.", "/"), buffer);
+ myCompiledClasses.put(className.replace('.', '/'), buffer);
if (callback != null) {
final ClassReader reader = new ClassReader(buffer);
@@ -212,7 +217,7 @@ public class OptimizedFileManager extends DefaultFileManager {
public void commit() throws IOException {
final OutputStream result = superOpenOutputStream();
- final byte[] instrumented = InstrumentationUtil.instrumentNotNull(buffer, loader);
+ final byte[] instrumented = InstrumentationUtil.instrumentNotNull(buffer, classFinder);
if (instrumented != null) {
result.write(instrumented);
@@ -247,5 +252,8 @@ public class OptimizedFileManager extends DefaultFileManager {
}
myWriters.clear();
+ if (classFinder != null) {
+ classFinder.releaseResources();
+ }
}
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/PreviewFormAction.java b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/PreviewFormAction.java
index 15bb312a9e48..bff58a5533db 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/PreviewFormAction.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/PreviewFormAction.java
@@ -18,6 +18,7 @@ package com.intellij.uiDesigner.actions;
import com.intellij.CommonBundle;
import com.intellij.compiler.PsiClassWriter;
import com.intellij.compiler.impl.FileSetCompileScope;
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
import com.intellij.execution.*;
import com.intellij.execution.configurations.*;
import com.intellij.execution.executors.DefaultRunExecutor;
@@ -128,118 +129,124 @@ public final class PreviewFormAction extends AnAction{
final String classPath = OrderEnumerator.orderEntries(module).recursively().getPathsList().getPathsString() + File.pathSeparator +
sources.getPathsString() + File.pathSeparator + /* resources bundles */
tempPath;
- final ClassLoader loader = Form2ByteCodeCompiler.createClassLoader(classPath);
+ final InstrumentationClassFinder finder = Form2ByteCodeCompiler.createClassFinder(classPath);
- final Document doc = FileDocumentManager.getInstance().getDocument(formFile);
- final LwRootContainer rootContainer;
try {
- rootContainer = Utils.getRootContainer(doc.getText(), new CompiledClassPropertiesProvider(loader));
- }
- catch (Exception e) {
- Messages.showErrorDialog(
- module.getProject(),
- UIDesignerBundle.message("error.cannot.read.form", formFile.getPath().replace('/', File.separatorChar), e.getMessage()),
- CommonBundle.getErrorTitle()
- );
- return;
- }
-
- if (rootContainer.getComponentCount() == 0) {
- Messages.showErrorDialog(
- module.getProject(),
- UIDesignerBundle.message("error.cannot.preview.empty.form", formFile.getPath().replace('/', File.separatorChar)),
- CommonBundle.getErrorTitle()
- );
- return;
- }
-
- setPreviewBindings(rootContainer, CLASS_TO_BIND_NAME);
-
- // 2. Copy previewer class and all its superclasses into TEMP directory and instrument it.
- try {
- PreviewNestedFormLoader nestedFormLoader = new PreviewNestedFormLoader(module, tempPath, loader);
-
- final File tempFile = CopyResourcesUtil.copyClass(tempPath, CLASS_TO_BIND_NAME, true);
- //CopyResourcesUtil.copyClass(tempPath, CLASS_TO_BIND_NAME + "$1", true);
- CopyResourcesUtil.copyClass(tempPath, CLASS_TO_BIND_NAME + "$MyExitAction", true);
- CopyResourcesUtil.copyClass(tempPath, CLASS_TO_BIND_NAME + "$MyPackAction", true);
- CopyResourcesUtil.copyClass(tempPath, CLASS_TO_BIND_NAME + "$MySetLafAction", true);
-
- Locale locale = Locale.getDefault();
- if (locale.getCountry().length() > 0 && locale.getLanguage().length() > 0) {
- CopyResourcesUtil.copyProperties(tempPath, RUNTIME_BUNDLE_PREFIX + "_" + locale.getLanguage() +
- "_" + locale.getCountry() + PropertiesFileType.DOT_DEFAULT_EXTENSION);
+ final Document doc = FileDocumentManager.getInstance().getDocument(formFile);
+ final LwRootContainer rootContainer;
+ try {
+ rootContainer = Utils.getRootContainer(doc.getText(), new CompiledClassPropertiesProvider(finder.getLoader()));
}
- if (locale.getLanguage().length() > 0) {
- CopyResourcesUtil.copyProperties(tempPath, RUNTIME_BUNDLE_PREFIX + "_" + locale.getLanguage() + PropertiesFileType.DOT_DEFAULT_EXTENSION);
- }
- CopyResourcesUtil.copyProperties(tempPath, RUNTIME_BUNDLE_PREFIX + "_" + locale.getLanguage() + PropertiesFileType.DOT_DEFAULT_EXTENSION);
- CopyResourcesUtil.copyProperties(tempPath, RUNTIME_BUNDLE_PREFIX + PropertiesFileType.DOT_DEFAULT_EXTENSION);
-
- final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, loader, nestedFormLoader, true,
- new PsiClassWriter(module));
- codeGenerator.patchFile(tempFile);
- final FormErrorInfo[] errors = codeGenerator.getErrors();
- if(errors.length != 0){
+ catch (Exception e) {
Messages.showErrorDialog(
module.getProject(),
- UIDesignerBundle.message("error.cannot.preview.form",
- formFile.getPath().replace('/', File.separatorChar),
- errors[0].getErrorMessage()),
+ UIDesignerBundle.message("error.cannot.read.form", formFile.getPath().replace('/', File.separatorChar), e.getMessage()),
CommonBundle.getErrorTitle()
);
return;
}
- }
- catch (Exception e) {
- LOG.debug(e);
- Messages.showErrorDialog(
- module.getProject(),
- UIDesignerBundle.message("error.cannot.preview.form", formFile.getPath().replace('/', File.separatorChar),
- e.getMessage() != null ? e.getMessage() : e.toString()),
- CommonBundle.getErrorTitle()
- );
- return;
- }
- // 2.5. Copy up-to-date properties files to the output directory.
- final HashSet bundleSet = new HashSet();
- FormEditingUtil.iterateStringDescriptors(
- rootContainer,
- new FormEditingUtil.StringDescriptorVisitor() {
- public boolean visit(final IComponent component, final StringDescriptor descriptor) {
- if (descriptor.getBundleName() != null) {
- bundleSet.add(descriptor.getDottedBundleName());
- }
- return true;
+ if (rootContainer.getComponentCount() == 0) {
+ Messages.showErrorDialog(
+ module.getProject(),
+ UIDesignerBundle.message("error.cannot.preview.empty.form", formFile.getPath().replace('/', File.separatorChar)),
+ CommonBundle.getErrorTitle()
+ );
+ return;
+ }
+
+ setPreviewBindings(rootContainer, CLASS_TO_BIND_NAME);
+
+ // 2. Copy previewer class and all its superclasses into TEMP directory and instrument it.
+ try {
+ PreviewNestedFormLoader nestedFormLoader = new PreviewNestedFormLoader(module, tempPath, finder);
+
+ final File tempFile = CopyResourcesUtil.copyClass(tempPath, CLASS_TO_BIND_NAME, true);
+ //CopyResourcesUtil.copyClass(tempPath, CLASS_TO_BIND_NAME + "$1", true);
+ CopyResourcesUtil.copyClass(tempPath, CLASS_TO_BIND_NAME + "$MyExitAction", true);
+ CopyResourcesUtil.copyClass(tempPath, CLASS_TO_BIND_NAME + "$MyPackAction", true);
+ CopyResourcesUtil.copyClass(tempPath, CLASS_TO_BIND_NAME + "$MySetLafAction", true);
+
+ Locale locale = Locale.getDefault();
+ if (locale.getCountry().length() > 0 && locale.getLanguage().length() > 0) {
+ CopyResourcesUtil.copyProperties(tempPath, RUNTIME_BUNDLE_PREFIX + "_" + locale.getLanguage() +
+ "_" + locale.getCountry() + PropertiesFileType.DOT_DEFAULT_EXTENSION);
}
- });
+ if (locale.getLanguage().length() > 0) {
+ CopyResourcesUtil.copyProperties(tempPath, RUNTIME_BUNDLE_PREFIX + "_" + locale.getLanguage() + PropertiesFileType.DOT_DEFAULT_EXTENSION);
+ }
+ CopyResourcesUtil.copyProperties(tempPath, RUNTIME_BUNDLE_PREFIX + "_" + locale.getLanguage() + PropertiesFileType.DOT_DEFAULT_EXTENSION);
+ CopyResourcesUtil.copyProperties(tempPath, RUNTIME_BUNDLE_PREFIX + PropertiesFileType.DOT_DEFAULT_EXTENSION);
- if (bundleSet.size() > 0) {
- HashSet virtualFiles = new HashSet();
- HashSet modules = new HashSet();
- PropertiesReferenceManager manager = PropertiesReferenceManager.getInstance(module.getProject());
- for(String bundleName: bundleSet) {
- for(PropertiesFile propFile: manager.findPropertiesFiles(module, bundleName)) {
- virtualFiles.add(propFile.getVirtualFile());
- final Module moduleForFile = ModuleUtil.findModuleForFile(propFile.getVirtualFile(), module.getProject());
- if (moduleForFile != null) {
- modules.add(moduleForFile);
- }
+ final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(
+ rootContainer, finder, nestedFormLoader, true, new PsiClassWriter(module)
+ );
+ codeGenerator.patchFile(tempFile);
+ final FormErrorInfo[] errors = codeGenerator.getErrors();
+ if(errors.length != 0){
+ Messages.showErrorDialog(
+ module.getProject(),
+ UIDesignerBundle.message("error.cannot.preview.form",
+ formFile.getPath().replace('/', File.separatorChar),
+ errors[0].getErrorMessage()),
+ CommonBundle.getErrorTitle()
+ );
+ return;
}
}
- FileSetCompileScope scope = new FileSetCompileScope(virtualFiles, modules.toArray(new Module[modules.size()]));
+ catch (Exception e) {
+ LOG.debug(e);
+ Messages.showErrorDialog(
+ module.getProject(),
+ UIDesignerBundle.message("error.cannot.preview.form", formFile.getPath().replace('/', File.separatorChar),
+ e.getMessage() != null ? e.getMessage() : e.toString()),
+ CommonBundle.getErrorTitle()
+ );
+ return;
+ }
- CompilerManager.getInstance(module.getProject()).make(scope, new CompileStatusNotification() {
- public void finished(boolean aborted, int errors, int warnings, final CompileContext compileContext) {
- if (!aborted && errors == 0) {
- runPreviewProcess(tempPath, sources, module, formFile, stringDescriptorLocale);
+ // 2.5. Copy up-to-date properties files to the output directory.
+ final HashSet bundleSet = new HashSet();
+ FormEditingUtil.iterateStringDescriptors(
+ rootContainer,
+ new FormEditingUtil.StringDescriptorVisitor() {
+ public boolean visit(final IComponent component, final StringDescriptor descriptor) {
+ if (descriptor.getBundleName() != null) {
+ bundleSet.add(descriptor.getDottedBundleName());
+ }
+ return true;
+ }
+ });
+
+ if (bundleSet.size() > 0) {
+ HashSet virtualFiles = new HashSet();
+ HashSet modules = new HashSet();
+ PropertiesReferenceManager manager = PropertiesReferenceManager.getInstance(module.getProject());
+ for(String bundleName: bundleSet) {
+ for(PropertiesFile propFile: manager.findPropertiesFiles(module, bundleName)) {
+ virtualFiles.add(propFile.getVirtualFile());
+ final Module moduleForFile = ModuleUtil.findModuleForFile(propFile.getVirtualFile(), module.getProject());
+ if (moduleForFile != null) {
+ modules.add(moduleForFile);
+ }
}
}
- });
+ FileSetCompileScope scope = new FileSetCompileScope(virtualFiles, modules.toArray(new Module[modules.size()]));
+
+ CompilerManager.getInstance(module.getProject()).make(scope, new CompileStatusNotification() {
+ public void finished(boolean aborted, int errors, int warnings, final CompileContext compileContext) {
+ if (!aborted && errors == 0) {
+ runPreviewProcess(tempPath, sources, module, formFile, stringDescriptorLocale);
+ }
+ }
+ });
+ }
+ else {
+ runPreviewProcess(tempPath, sources, module, formFile, stringDescriptorLocale);
+ }
}
- else {
- runPreviewProcess(tempPath, sources, module, formFile, stringDescriptorLocale);
+ finally {
+ finder.releaseResources();
}
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/make/Form2ByteCodeCompiler.java b/plugins/ui-designer/src/com/intellij/uiDesigner/make/Form2ByteCodeCompiler.java
index b42fd6bf0520..8bcacec4b2ee 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/make/Form2ByteCodeCompiler.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/make/Form2ByteCodeCompiler.java
@@ -17,6 +17,7 @@ package com.intellij.uiDesigner.make;
import com.intellij.compiler.PsiClassWriter;
import com.intellij.compiler.impl.CompilerUtil;
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.diagnostic.Logger;
@@ -50,7 +51,6 @@ import java.io.DataInput;
import java.io.File;
import java.io.IOException;
import java.net.URL;
-import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -71,7 +71,7 @@ public final class Form2ByteCodeCompiler implements ClassInstrumentingCompiler {
}
@NotNull
- public static URLClassLoader createClassLoader(@NotNull final String classPath){
+ public static InstrumentationClassFinder createClassFinder(@NotNull final String classPath){
final ArrayList urls = new ArrayList();
for (StringTokenizer tokenizer = new StringTokenizer(classPath, File.pathSeparator); tokenizer.hasMoreTokens();) {
final String s = tokenizer.nextToken();
@@ -82,7 +82,7 @@ public final class Form2ByteCodeCompiler implements ClassInstrumentingCompiler {
throw new RuntimeException(exc);
}
}
- return new URLClassLoader(urls.toArray(new URL[urls.size()]), null);
+ return new InstrumentationClassFinder(urls.toArray(new URL[urls.size()]));
}
@Override
@@ -274,81 +274,86 @@ public final class Form2ByteCodeCompiler implements ClassInstrumentingCompiler {
List filesToRefresh = new ArrayList();
for (final Module module : module2itemsList.keySet()) {
final String classPath = OrderEnumerator.orderEntries(module).recursively().getPathsList().getPathsString();
- final ClassLoader loader = createClassLoader(classPath);
+ final InstrumentationClassFinder finder = createClassFinder(classPath);
- if (GuiDesignerConfiguration.getInstance(project).COPY_FORMS_RUNTIME_TO_OUTPUT) {
- final String moduleOutputPath = CompilerPaths.getModuleOutputPath(module, false);
- try {
- if (moduleOutputPath != null) {
- filesToRefresh.addAll(CopyResourcesUtil.copyFormsRuntime(moduleOutputPath, false));
+ try {
+ if (GuiDesignerConfiguration.getInstance(project).COPY_FORMS_RUNTIME_TO_OUTPUT) {
+ final String moduleOutputPath = CompilerPaths.getModuleOutputPath(module, false);
+ try {
+ if (moduleOutputPath != null) {
+ filesToRefresh.addAll(CopyResourcesUtil.copyFormsRuntime(moduleOutputPath, false));
+ }
+ final String testsOutputPath = CompilerPaths.getModuleOutputPath(module, true);
+ if (testsOutputPath != null && !testsOutputPath.equals(moduleOutputPath)) {
+ filesToRefresh.addAll(CopyResourcesUtil.copyFormsRuntime(testsOutputPath, false));
+ }
}
- final String testsOutputPath = CompilerPaths.getModuleOutputPath(module, true);
- if (testsOutputPath != null && !testsOutputPath.equals(moduleOutputPath)) {
- filesToRefresh.addAll(CopyResourcesUtil.copyFormsRuntime(testsOutputPath, false));
+ catch (IOException e) {
+ addMessage(
+ context,
+ UIDesignerBundle.message("error.cannot.copy.gui.designer.form.runtime", module.getName(), e.toString()),
+ null, CompilerMessageCategory.ERROR);
}
}
- catch (IOException e) {
- addMessage(
- context,
- UIDesignerBundle.message("error.cannot.copy.gui.designer.form.runtime", module.getName(), e.toString()),
- null, CompilerMessageCategory.ERROR);
+
+ final ArrayList list = module2itemsList.get(module);
+
+ for (final MyInstrumentationItem item : list) {
+ //context.getProgressIndicator().setFraction((double)++formsProcessed / (double)items.length);
+
+ final VirtualFile formFile = item.getFormFile();
+ context.getProgressIndicator().setText2(formFile.getPresentableUrl());
+
+ final String text = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public String compute() {
+ if (!belongsToCompileScope(context, formFile, item.getClassToBindFQname())) {
+ return null;
+ }
+ Document document = FileDocumentManager.getInstance().getDocument(formFile);
+ return document == null ? null : document.getText();
+ }
+ });
+ if (text == null) {
+ continue; // does not belong to current scope
+ }
+
+ final LwRootContainer rootContainer;
+ try {
+ rootContainer = Utils.getRootContainer(text, new CompiledClassPropertiesProvider(finder.getLoader()));
+ }
+ catch (Exception e) {
+ addMessage(context, UIDesignerBundle.message("error.cannot.process.form.file", e), formFile, CompilerMessageCategory.ERROR);
+ continue;
+ }
+
+ final File classFile = VfsUtil.virtualToIoFile(item.getFile());
+ LOG.assertTrue(classFile.exists(), classFile.getPath());
+
+ final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(
+ rootContainer, finder, new PsiNestedFormLoader(module), false, new PsiClassWriter(module)
+ );
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ codeGenerator.patchFile(classFile);
+ }
+ });
+ final FormErrorInfo[] errors = codeGenerator.getErrors();
+ final FormErrorInfo[] warnings = codeGenerator.getWarnings();
+ for (FormErrorInfo warning : warnings) {
+ addMessage(context, warning, formFile, CompilerMessageCategory.WARNING);
+ }
+ for (FormErrorInfo error : errors) {
+ addMessage(context, error, formFile, CompilerMessageCategory.ERROR);
+ }
+ if (errors.length == 0) {
+ compiledItems.add(item);
+ }
}
}
-
- final ArrayList list = module2itemsList.get(module);
-
- for (final MyInstrumentationItem item : list) {
- //context.getProgressIndicator().setFraction((double)++formsProcessed / (double)items.length);
-
- final VirtualFile formFile = item.getFormFile();
- context.getProgressIndicator().setText2(formFile.getPresentableUrl());
-
- final String text = ApplicationManager.getApplication().runReadAction(new Computable() {
- @Override
- public String compute() {
- if (!belongsToCompileScope(context, formFile, item.getClassToBindFQname())) {
- return null;
- }
- Document document = FileDocumentManager.getInstance().getDocument(formFile);
- return document == null ? null : document.getText();
- }
- });
- if (text == null) {
- continue; // does not belong to current scope
- }
-
- final LwRootContainer rootContainer;
- try {
- rootContainer = Utils.getRootContainer(text, new CompiledClassPropertiesProvider(loader));
- }
- catch (Exception e) {
- addMessage(context, UIDesignerBundle.message("error.cannot.process.form.file", e), formFile, CompilerMessageCategory.ERROR);
- continue;
- }
-
- final File classFile = VfsUtil.virtualToIoFile(item.getFile());
- LOG.assertTrue(classFile.exists(), classFile.getPath());
-
- final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, loader,
- new PsiNestedFormLoader(module), false,
- new PsiClassWriter(module));
- ApplicationManager.getApplication().runReadAction(new Runnable() {
- @Override
- public void run() {
- codeGenerator.patchFile(classFile);
- }
- });
- final FormErrorInfo[] errors = codeGenerator.getErrors();
- final FormErrorInfo[] warnings = codeGenerator.getWarnings();
- for (FormErrorInfo warning : warnings) {
- addMessage(context, warning, formFile, CompilerMessageCategory.WARNING);
- }
- for (FormErrorInfo error : errors) {
- addMessage(context, error, formFile, CompilerMessageCategory.ERROR);
- }
- if (errors.length == 0) {
- compiledItems.add(item);
- }
+ finally {
+ finder.releaseResources();
}
}
CompilerUtil.refreshIOFiles(filesToRefresh);
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/make/PreviewNestedFormLoader.java b/plugins/ui-designer/src/com/intellij/uiDesigner/make/PreviewNestedFormLoader.java
index dbb2443c74a5..fbe4c8aaa86e 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/make/PreviewNestedFormLoader.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/make/PreviewNestedFormLoader.java
@@ -17,6 +17,7 @@
package com.intellij.uiDesigner.make;
import com.intellij.compiler.PsiClassWriter;
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
import com.intellij.openapi.module.Module;
import com.intellij.uiDesigner.actions.PreviewFormAction;
import com.intellij.uiDesigner.compiler.AsmCodeGenerator;
@@ -41,13 +42,13 @@ import java.util.Set;
*/
public class PreviewNestedFormLoader extends PsiNestedFormLoader {
private final String myTempPath;
- private final ClassLoader myLoader;
+ private final InstrumentationClassFinder myFinder;
private final Set myGeneratedClasses = new HashSet();
- public PreviewNestedFormLoader(final Module module, final String tempPath, final ClassLoader loader) {
+ public PreviewNestedFormLoader(final Module module, final String tempPath, final InstrumentationClassFinder finder) {
super(module);
myTempPath = tempPath;
- myLoader = loader;
+ myFinder = finder;
}
public LwRootContainer loadForm(String formFileName) throws Exception {
@@ -82,7 +83,7 @@ public class PreviewNestedFormLoader extends PsiNestedFormLoader {
cw.visitEnd();
ByteArrayInputStream bais = new ByteArrayInputStream(cw.toByteArray());
- AsmCodeGenerator acg = new AsmCodeGenerator(rootContainer, myLoader, this, true, new PsiClassWriter(myModule));
+ AsmCodeGenerator acg = new AsmCodeGenerator(rootContainer, myFinder, this, true, new PsiClassWriter(myModule));
byte[] data = acg.patchClass(bais);
FormErrorInfo[] errors = acg.getErrors();
if (errors.length > 0) {
diff --git a/plugins/ui-designer/testSrc/com/intellij/uiDesigner/core/AsmCodeGeneratorTest.java b/plugins/ui-designer/testSrc/com/intellij/uiDesigner/core/AsmCodeGeneratorTest.java
index 3bc39bccc584..d8ff9f5c68a6 100644
--- a/plugins/ui-designer/testSrc/com/intellij/uiDesigner/core/AsmCodeGeneratorTest.java
+++ b/plugins/ui-designer/testSrc/com/intellij/uiDesigner/core/AsmCodeGeneratorTest.java
@@ -15,14 +15,21 @@
*/
package com.intellij.uiDesigner.core;
+import com.intellij.compiler.instrumentation.InstrumentationClassFinder;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.PluginPathManager;
+import com.intellij.openapi.util.SystemInfoRt;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.ui.components.JBTabbedPane;
import com.intellij.uiDesigner.compiler.AsmCodeGenerator;
import com.intellij.uiDesigner.compiler.FormErrorInfo;
import com.intellij.uiDesigner.compiler.NestedFormLoader;
import com.intellij.uiDesigner.compiler.Utils;
import com.intellij.uiDesigner.lw.CompiledClassPropertiesProvider;
import com.intellij.uiDesigner.lw.LwRootContainer;
+import com.intellij.util.PathUtil;
+import com.intellij.util.ui.UIUtil;
import junit.framework.TestCase;
import org.objectweb.asm.ClassWriter;
@@ -32,7 +39,13 @@ import javax.swing.border.TitledBorder;
import java.awt.*;
import java.io.*;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -41,19 +54,46 @@ import java.util.Map;
*/
public class AsmCodeGeneratorTest extends TestCase {
private MyNestedFormLoader myNestedFormLoader;
- private MyClassLoader myClassLoader;
+ private MyClassFinder myClassFinder;
@Override
protected void setUp() throws Exception {
super.setUp();
myNestedFormLoader = new MyNestedFormLoader();
- myClassLoader = new MyClassLoader(getClass().getClassLoader());
+
+ final String swingPath = PathUtil.getJarPathForClass(AbstractButton.class);
+
+ java.util.List cp = new ArrayList();
+ appendPath(cp, JBTabbedPane.class);
+ appendPath(cp, UIUtil.class);
+ appendPath(cp, SystemInfoRt.class);
+ appendPath(cp, ApplicationManager.class);
+ appendPath(cp, PathManager.getResourceRoot(this.getClass(), "/messages/UIBundle.properties"));
+ appendPath(cp, PathManager.getResourceRoot(this.getClass(), "/RuntimeBundle.properties"));
+ appendPath(cp, GridLayoutManager.class); // forms_rt
+ myClassFinder = new MyClassFinder(
+ new URL[] {new File(swingPath).toURI().toURL()},
+ cp.toArray(new URL[cp.size()])
+ );
+ }
+
+ private static void appendPath(Collection container, Class cls) throws MalformedURLException {
+ final String path = PathUtil.getJarPathForClass(cls);
+ appendPath(container, path);
+ }
+
+ private static void appendPath(Collection container, String path) throws MalformedURLException {
+ container.add(new File(path).toURI().toURL());
}
@Override
protected void tearDown() throws Exception {
- myClassLoader = null;
myNestedFormLoader = null;
+ final MyClassFinder classFinder = myClassFinder;
+ if (classFinder != null) {
+ classFinder.releaseResources();
+ myClassFinder = null;
+ }
super.tearDown();
}
@@ -70,7 +110,7 @@ public class AsmCodeGeneratorTest extends TestCase {
String classPath = tmpPath + "/" + className + ".class";
final LwRootContainer rootContainer = loadFormData(formPath);
- final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, myClassLoader, myNestedFormLoader, false,
+ final AsmCodeGenerator codeGenerator = new AsmCodeGenerator(rootContainer, myClassFinder, myNestedFormLoader, false,
new ClassWriter(ClassWriter.COMPUTE_FRAMES));
final FileInputStream classStream = new FileInputStream(classPath);
try {
@@ -109,7 +149,8 @@ public class AsmCodeGeneratorTest extends TestCase {
fos.close();
*/
- return myClassLoader.doDefineClass(className, patchedData);
+ myClassFinder.addClassDefinition(className, patchedData);
+ return myClassFinder.getLoader().loadClass(className);
}
private static byte[] getVerifiedPatchedData(final AsmCodeGenerator codeGenerator) {
@@ -168,10 +209,41 @@ public class AsmCodeGeneratorTest extends TestCase {
public void testGridLayout() throws Exception {
JComponent rootComponent = getInstrumentedRootComponent("TestGridConstraints.form", "BindingTest");
- assertTrue(rootComponent.getLayout() instanceof GridLayoutManager);
- GridLayoutManager gridLayout = (GridLayoutManager) rootComponent.getLayout();
- assertEquals(1, gridLayout.getRowCount());
- assertEquals(1, gridLayout.getColumnCount());
+ final LayoutManager layout = rootComponent.getLayout();
+ assertTrue(isInstanceOf(layout, GridLayoutManager.class.getName()));
+
+
+ assertEquals(1, invokeMethod(layout, "getRowCount"));
+ assertEquals(1, invokeMethod(layout, "getColumnCount"));
+ }
+
+ private static boolean isInstanceOf(Object object, final String className) throws ClassNotFoundException {
+ final Class> ethalon = object.getClass().getClassLoader().loadClass(className);
+ return ethalon.isAssignableFrom(object.getClass());
+ }
+
+ private static Object invokeMethod(Object obj, String methodName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ return invokeMethod(obj, methodName, new Class[0], new Object[0]);
+ }
+
+ private static Object invokeMethod(Object obj, String methodName, Class[] params, Object[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ final Method method = findMethod(obj.getClass(), methodName, params);
+ return method.invoke(obj, args);
+ }
+
+ private static Method findMethod(Class extends Object> aClass, String methodName, Class[] params) {
+ try {
+ final Method method = aClass.getDeclaredMethod(methodName, params);
+ method.setAccessible(true);
+ return method;
+ }
+ catch (NoSuchMethodException ignored) {
+ }
+ final Class> parent = aClass.getSuperclass();
+ if (parent == null) {
+ return null;
+ }
+ return findMethod(parent, methodName, params);
}
public void testCardLayout() throws Exception {
@@ -193,10 +265,14 @@ public class AsmCodeGeneratorTest extends TestCase {
public void testGridConstraints() throws Exception {
JComponent rootComponent = getInstrumentedRootComponent("TestGridConstraints.form", "BindingTest");
assertEquals(1, rootComponent.getComponentCount());
- GridLayoutManager gridLayout = (GridLayoutManager) rootComponent.getLayout();
- final GridConstraints constraints = gridLayout.getConstraints(0);
- assertEquals(1, constraints.getColSpan());
- assertEquals(1, constraints.getRowSpan());
+ final LayoutManager layout = rootComponent.getLayout();
+ assertTrue(isInstanceOf(layout, GridLayoutManager.class.getName()));
+
+ final Object constraints = invokeMethod(layout, "getConstraints", new Class[] {int.class}, new Object[] {0});
+ assertTrue(isInstanceOf(constraints, GridConstraints.class.getName()));
+
+ assertEquals(1, invokeMethod(constraints, "getColSpan"));
+ assertEquals(1, invokeMethod(constraints, "getRowSpan"));
}
public void testIntProperty() throws Exception {
@@ -341,7 +417,7 @@ public class AsmCodeGeneratorTest extends TestCase {
File.separatorChar + "formEmbedding" + File.separatorChar + "Ideadev14081" + File.separatorChar;
AsmCodeGenerator embeddedClassGenerator = initCodeGenerator("Embedded.form", "Embedded", testDataPath);
byte[] embeddedPatchedData = getVerifiedPatchedData(embeddedClassGenerator);
- myClassLoader.doDefineClass("Embedded", embeddedPatchedData);
+ myClassFinder.addClassDefinition("Embedded", embeddedPatchedData);
myNestedFormLoader.registerNestedForm("Embedded.form", testDataPath + "Embedded.form");
AsmCodeGenerator mainClassGenerator = initCodeGenerator("Main.form", "Main", testDataPath);
byte[] mainPatchedData = getVerifiedPatchedData(mainClassGenerator);
@@ -352,30 +428,34 @@ public class AsmCodeGeneratorTest extends TestCase {
fos.close();
*/
- final Class mainClass = myClassLoader.doDefineClass("Main", mainPatchedData);
+ myClassFinder.addClassDefinition("Main", mainPatchedData);
+ final Class mainClass = myClassFinder.getLoader().loadClass("Main");
Object instance = mainClass.newInstance();
assert instance != null : mainClass;
}
- private static class MyClassLoader extends ClassLoader {
- private final byte[] myTestProperties = Charset.defaultCharset().encode(TEST_PROPERTY_CONTENT).array();
+ private static class MyClassFinder extends InstrumentationClassFinder {
private static final String TEST_PROPERTY_CONTENT = "test=Test Value\nmnemonic=Mne&monic";
+ private final byte[] myTestProperties = Charset.defaultCharset().encode(TEST_PROPERTY_CONTENT).array();
+ private final Map myClassData = new HashMap();
- public MyClassLoader(ClassLoader parent) {
- super(parent);
+ private MyClassFinder(URL[] platformUrls, URL[] classpathUrls) {
+ super(platformUrls, classpathUrls);
}
- public Class doDefineClass(String name, byte[] data) {
- return defineClass(name, data, 0, data.length);
+ public void addClassDefinition(String name, byte[] bytes) {
+ myClassData.put(name.replace('.', '/'), bytes);
}
- @Override
- public Class> loadClass(String name) throws ClassNotFoundException {
- return super.loadClass(name);
+ protected InputStream lookupClassBeforeClasspath(String internalClassName) {
+ final byte[] bytes = myClassData.get(internalClassName);
+ if (bytes != null) {
+ return new ByteArrayInputStream(bytes);
+ }
+ return null;
}
- @Override
- public InputStream getResourceAsStream(String name) {
+ public InputStream getResourceAsStream(String name) throws IOException {
if (name.equals("TestProperties.properties")) {
return new ByteArrayInputStream(myTestProperties, 0, TEST_PROPERTY_CONTENT.length());
}