old: generic error message new: step by step diagnostics with instructions. The code treats ant tasks and ant optional tasks specially, based on package names. Also: moved some constants into the appropriate places. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277750 13f79535-47bb-0310-9956-ffa450edef68master
@@ -17,6 +17,9 @@ | |||||
package org.apache.tools.ant; | package org.apache.tools.ant; | ||||
import java.lang.reflect.InvocationTargetException; | |||||
import java.lang.reflect.Constructor; | |||||
/** | /** | ||||
* This class contains all the information | * This class contains all the information | ||||
@@ -143,15 +146,8 @@ public class AntTypeDefinition { | |||||
* @return the type of the definition. | * @return the type of the definition. | ||||
*/ | */ | ||||
public Class getTypeClass(Project project) { | public Class getTypeClass(Project project) { | ||||
if (clazz != null) { | |||||
return clazz; | |||||
} | |||||
try { | try { | ||||
if (classLoader == null) { | |||||
clazz = Class.forName(className); | |||||
} else { | |||||
clazz = classLoader.loadClass(className); | |||||
} | |||||
return innerGetTypeClass(); | |||||
} catch (NoClassDefFoundError ncdfe) { | } catch (NoClassDefFoundError ncdfe) { | ||||
project.log("Could not load a dependent class (" | project.log("Could not load a dependent class (" | ||||
+ ncdfe.getMessage() + ") for type " | + ncdfe.getMessage() + ") for type " | ||||
@@ -160,6 +156,24 @@ public class AntTypeDefinition { | |||||
project.log("Could not load class (" + className | project.log("Could not load class (" + className | ||||
+ ") for type " + name, Project.MSG_DEBUG); | + ") for type " + name, Project.MSG_DEBUG); | ||||
} | } | ||||
return null; | |||||
} | |||||
/** | |||||
* Try and load a class, with no attempt to catch any fault. | |||||
* @return the class that implements this component | |||||
* @throws ClassNotFoundException | |||||
* @throws NoClassDefFoundError | |||||
*/ | |||||
public Class innerGetTypeClass() throws ClassNotFoundException { | |||||
if (clazz != null) { | |||||
return clazz; | |||||
} | |||||
if (classLoader == null) { | |||||
clazz = Class.forName(className); | |||||
} else { | |||||
clazz = classLoader.loadClass(className); | |||||
} | |||||
return clazz; | return clazz; | ||||
} | } | ||||
@@ -238,23 +252,9 @@ public class AntTypeDefinition { | |||||
*/ | */ | ||||
private Object createAndSet(Project project, Class c) { | private Object createAndSet(Project project, Class c) { | ||||
try { | try { | ||||
java.lang.reflect.Constructor ctor = null; | |||||
boolean noArg = false; | |||||
// DataType can have a "no arg" constructor or take a single | |||||
// Project argument. | |||||
try { | |||||
ctor = c.getConstructor(new Class[0]); | |||||
noArg = true; | |||||
} catch (NoSuchMethodException nse) { | |||||
ctor = c.getConstructor(new Class[] {Project.class}); | |||||
noArg = false; | |||||
} | |||||
Object o = ctor.newInstance( | |||||
((noArg) ? new Object[0] : new Object[] {project})); | |||||
project.setProjectReference(o); | |||||
Object o = innerCreateAndSet(c, project); | |||||
return o; | return o; | ||||
} catch (java.lang.reflect.InvocationTargetException ex) { | |||||
} catch (InvocationTargetException ex) { | |||||
Throwable t = ex.getTargetException(); | Throwable t = ex.getTargetException(); | ||||
throw new BuildException( | throw new BuildException( | ||||
"Could not create type " + name + " due to " + t, t); | "Could not create type " + name + " due to " + t, t); | ||||
@@ -262,12 +262,60 @@ public class AntTypeDefinition { | |||||
String msg = "Type " + name + ": A class needed by class " | String msg = "Type " + name + ": A class needed by class " | ||||
+ c + " cannot be found: " + ncdfe.getMessage(); | + c + " cannot be found: " + ncdfe.getMessage(); | ||||
throw new BuildException(msg, ncdfe); | throw new BuildException(msg, ncdfe); | ||||
} catch (Throwable t) { | |||||
} catch (NoSuchMethodException nsme) { | |||||
throw new BuildException("Could not create type " + name | |||||
+ " as the class " + c +" has no compatible constructor" ); | |||||
} catch (InstantiationException nsme) { | |||||
throw new BuildException("Could not create type " + | |||||
name | |||||
+ " as the class " + c + " is abstract"); | |||||
} catch(IllegalAccessException e) { | |||||
throw new BuildException("Could not create type " + | |||||
name | |||||
+ " as the constructor " + c + " is not accessible"); | |||||
} catch (Throwable t) { | |||||
throw new BuildException( | throw new BuildException( | ||||
"Could not create type " + name + " due to " + t, t); | "Could not create type " + name + " due to " + t, t); | ||||
} | } | ||||
} | } | ||||
/** | |||||
* Inner implementation of the {@see #createAndSet} logic, with no | |||||
* exception catching | |||||
* @param newclass class to create | |||||
* @param project | |||||
* @return a newly constructed and bound instance. | |||||
* @throws NoSuchMethodException | |||||
* @throws InstantiationException | |||||
* @throws IllegalAccessException | |||||
* @throws InvocationTargetException | |||||
*/ | |||||
public Object innerCreateAndSet(Class newclass, Project project) | |||||
throws NoSuchMethodException, | |||||
InstantiationException, | |||||
IllegalAccessException, | |||||
InvocationTargetException { | |||||
Constructor ctor = null; | |||||
boolean noArg = false; | |||||
// DataType can have a "no arg" constructor or take a single | |||||
// Project argument. | |||||
try { | |||||
ctor = newclass.getConstructor(new Class[0]); | |||||
noArg = true; | |||||
} catch (NoSuchMethodException nse) { | |||||
//can throw the same exception, if there is no this(Project) ctor. | |||||
ctor = newclass.getConstructor(new Class[] {Project.class}); | |||||
noArg = false; | |||||
} | |||||
//now we instantiate | |||||
Object o = ctor.newInstance( | |||||
((noArg) ? new Object[0] : new Object[] {project})); | |||||
//set up project references. | |||||
project.setProjectReference(o); | |||||
return o; | |||||
} | |||||
/** | /** | ||||
* Equality method for this definition (assumes the names are the same). | * Equality method for this definition (assumes the names are the same). | ||||
* | * | ||||
@@ -28,10 +28,15 @@ import java.util.Stack; | |||||
import java.util.Vector; | import java.util.Vector; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.File; | |||||
import java.io.StringWriter; | |||||
import java.io.PrintWriter; | |||||
import java.lang.ref.WeakReference; | import java.lang.ref.WeakReference; | ||||
import java.lang.reflect.Modifier; | import java.lang.reflect.Modifier; | ||||
import java.lang.reflect.InvocationTargetException; | |||||
import org.apache.tools.ant.taskdefs.Typedef; | import org.apache.tools.ant.taskdefs.Typedef; | ||||
import org.apache.tools.ant.launch.Launcher; | |||||
/** | /** | ||||
* Component creation and configuration. | * Component creation and configuration. | ||||
@@ -83,6 +88,9 @@ public class ComponentHelper { | |||||
private ComponentHelper next; | private ComponentHelper next; | ||||
private Project project; | private Project project; | ||||
private static final String ERROR_NO_TASK_LIST_LOAD = "Can't load default task list"; | |||||
private static final String ERROR_NO_TYPE_LIST_LOAD = "Can't load default type list"; | |||||
public static final String COMPONENT_HELPER_REFERENCE = "ant.ComponentHelper"; | |||||
/** | /** | ||||
* Find a project component for a specific project, creating | * Find a project component for a specific project, creating | ||||
@@ -93,14 +101,14 @@ public class ComponentHelper { | |||||
public static ComponentHelper getComponentHelper(Project project) { | public static ComponentHelper getComponentHelper(Project project) { | ||||
// Singleton for now, it may change ( per/classloader ) | // Singleton for now, it may change ( per/classloader ) | ||||
ComponentHelper ph = (ComponentHelper) project.getReference( | ComponentHelper ph = (ComponentHelper) project.getReference( | ||||
"ant.ComponentHelper"); | |||||
COMPONENT_HELPER_REFERENCE); | |||||
if (ph != null) { | if (ph != null) { | ||||
return ph; | return ph; | ||||
} | } | ||||
ph = new ComponentHelper(); | ph = new ComponentHelper(); | ||||
ph.setProject(project); | ph.setProject(project); | ||||
project.addReference("ant.ComponentHelper", ph); | |||||
project.addReference(COMPONENT_HELPER_REFERENCE, ph); | |||||
return ph; | return ph; | ||||
} | } | ||||
@@ -654,14 +662,14 @@ public class ComponentHelper { | |||||
&& !("only".equals(project.getProperty("build.sysclasspath")))) { | && !("only".equals(project.getProperty("build.sysclasspath")))) { | ||||
classLoader = project.getCoreLoader(); | classLoader = project.getCoreLoader(); | ||||
} | } | ||||
String dataDefs = "/org/apache/tools/ant/taskdefs/defaults.properties"; | |||||
String dataDefs = MagicNames.TASKDEF_PROPERTIES_RESOURCE; | |||||
InputStream in = null; | InputStream in = null; | ||||
try { | try { | ||||
Properties props = new Properties(); | Properties props = new Properties(); | ||||
in = this.getClass().getResourceAsStream(dataDefs); | in = this.getClass().getResourceAsStream(dataDefs); | ||||
if (in == null) { | if (in == null) { | ||||
throw new BuildException("Can't load default task list"); | |||||
throw new BuildException(ERROR_NO_TASK_LIST_LOAD); | |||||
} | } | ||||
props.load(in); | props.load(in); | ||||
@@ -678,7 +686,7 @@ public class ComponentHelper { | |||||
antTypeTable.put(name, def); | antTypeTable.put(name, def); | ||||
} | } | ||||
} catch (IOException ex) { | } catch (IOException ex) { | ||||
throw new BuildException("Can't load default type list"); | |||||
throw new BuildException(ERROR_NO_TASK_LIST_LOAD); | |||||
} finally { | } finally { | ||||
if (in != null) { | if (in != null) { | ||||
try { | try { | ||||
@@ -699,14 +707,14 @@ public class ComponentHelper { | |||||
&& !("only".equals(project.getProperty("build.sysclasspath")))) { | && !("only".equals(project.getProperty("build.sysclasspath")))) { | ||||
classLoader = project.getCoreLoader(); | classLoader = project.getCoreLoader(); | ||||
} | } | ||||
String dataDefs = "/org/apache/tools/ant/types/defaults.properties"; | |||||
String dataDefs = MagicNames.TYPEDEFS_PROPERTIES_RESOURCE; | |||||
InputStream in = null; | InputStream in = null; | ||||
try { | try { | ||||
Properties props = new Properties(); | Properties props = new Properties(); | ||||
in = this.getClass().getResourceAsStream(dataDefs); | in = this.getClass().getResourceAsStream(dataDefs); | ||||
if (in == null) { | if (in == null) { | ||||
throw new BuildException("Can't load default datatype list"); | |||||
throw new BuildException(ERROR_NO_TYPE_LIST_LOAD); | |||||
} | } | ||||
props.load(in); | props.load(in); | ||||
@@ -721,7 +729,7 @@ public class ComponentHelper { | |||||
antTypeTable.put(name, def); | antTypeTable.put(name, def); | ||||
} | } | ||||
} catch (IOException ex) { | } catch (IOException ex) { | ||||
throw new BuildException("Can't load default type list"); | |||||
throw new BuildException(ERROR_NO_TYPE_LIST_LOAD); | |||||
} finally { | } finally { | ||||
if (in != null) { | if (in != null) { | ||||
try { | try { | ||||
@@ -761,6 +769,146 @@ public class ComponentHelper { | |||||
definer.execute(); | definer.execute(); | ||||
} | } | ||||
/** | |||||
* Handler called to do decent diagnosis on instantiation failure | |||||
* @param componentName | |||||
* @return a string containing as much diagnostics info as possible. | |||||
*/ | |||||
public String diagnoseCreationFailure(String componentName,String type) { | |||||
StringWriter errorText=new StringWriter(); | |||||
PrintWriter out=new PrintWriter(errorText); | |||||
out.println("Problem: failed to create "+ type +" "+componentName); | |||||
//class of problem | |||||
boolean lowlevel=false; | |||||
boolean jars=false; | |||||
boolean definitions=false; | |||||
boolean antTask; | |||||
//look up the name | |||||
AntTypeDefinition def = getDefinition(componentName); | |||||
if(def==null) { | |||||
//not a known type | |||||
out.println("Cause: The name is undefined."); | |||||
out.println("Action: Check the spelling."); | |||||
out.println("Action: Check that any custom tasks/types have been declared"); | |||||
out.println("Action: Check that any <presetdef>/<macrodefs> declarations have taken place"); | |||||
definitions=true; | |||||
} else{ | |||||
//we are defined, so it is an instantiation problem | |||||
final String classname = def.getClassName(); | |||||
antTask = classname.startsWith("org.apache.tools.ant."); | |||||
boolean optional = classname.startsWith("org.apache.tools.ant.taskdefs.optional"); | |||||
optional |= classname.startsWith("org.apache.tools.ant.types.optional"); | |||||
String home = System.getProperty(Launcher.USER_HOMEDIR); | |||||
File libDir = new File(home, | |||||
Launcher.ANT_PRIVATEDIR + | |||||
File.separator + | |||||
Launcher.ANT_PRIVATELIB); | |||||
//start with instantiating the class. | |||||
Class clazz= null; | |||||
try { | |||||
clazz = def.innerGetTypeClass(); | |||||
} catch (ClassNotFoundException e) { | |||||
out.println("Cause: the class " + | |||||
classname | |||||
+ " was not found"); | |||||
jars = true; | |||||
if (optional) { | |||||
out.println(" This looks like one of Ant's optional components"); | |||||
out.println("Action: check that the appropriate optional JAR exists " | |||||
+ "in ANT_HOME/lib or in "); | |||||
out.println(" " + libDir); | |||||
} else { | |||||
out.println("Action: check that the component has been correctly declared"); | |||||
out.println(" And that the implementing JAR is in ANT_HOME/lib or in"); | |||||
out.println(" " + libDir); | |||||
definitions = true; | |||||
} | |||||
} catch (NoClassDefFoundError ncdfe) { | |||||
jars = true; | |||||
out.println("Cause: Could not load a dependent class " | |||||
+ ncdfe.getMessage()); | |||||
if(optional) { | |||||
out.println(" It is not enough to have Ant's optional JAR, you need the JAR"); | |||||
out.println(" files that it depends upon"); | |||||
out.println("Ant's optional task dependencies are listed in the manual"); | |||||
} else { | |||||
out.println(" This class may be in a separate JAR, that is not installed."); | |||||
} | |||||
out.println("Action: determine what extra JAR files are needed, and place them"); | |||||
out.println(" In ANT_HOME/lib or"); | |||||
out.println(" in " + libDir ); | |||||
} | |||||
//here we successfully loaded the class or failed. | |||||
if(clazz!=null) { | |||||
//success: proceed with more steps | |||||
try { | |||||
def.innerCreateAndSet(clazz,project); | |||||
//hey, there is nothing wrong with us | |||||
out.println("The component could be instantiated"); | |||||
} catch (NoSuchMethodException e) { | |||||
lowlevel = true; | |||||
out.println("Cause: The class " + classname | |||||
+ " has no compatible constructor"); | |||||
} catch (InstantiationException e) { | |||||
lowlevel = true; | |||||
out.println("Cause: The class " + | |||||
classname | |||||
+ " is abstract and cannot be instantiated"); | |||||
} catch (IllegalAccessException e) { | |||||
lowlevel = true; | |||||
out.println("Cause: The constructor for " + | |||||
classname | |||||
+ " is private and cannot be invoked"); | |||||
} catch (InvocationTargetException ex) { | |||||
lowlevel = true; | |||||
Throwable t = ex.getTargetException(); | |||||
out.println("Cause: The constructor threw the exception "); | |||||
out.println(t.toString()); | |||||
t.printStackTrace(out); | |||||
} catch (NoClassDefFoundError ncdfe) { | |||||
jars = true; | |||||
out.println("Cause: A class needed by class " | |||||
+ classname + " cannot be found: "); | |||||
out.println(" "+ ncdfe.getMessage()); | |||||
out.println("Action: determine what extra JAR files are needed, and place them"); | |||||
out.println(" In ANT_HOME/lib or"); | |||||
out.println(" in " + libDir); | |||||
} | |||||
} | |||||
out.println(); | |||||
out.println("Do not panic, this is a common problem."); | |||||
if(definitions) { | |||||
out.println("It may just be a typing error in the build file " + | |||||
"or the task/type declaration"); | |||||
} | |||||
if (jars) { | |||||
out.println("The commonest cause is a missing JAR. "); | |||||
} | |||||
if (lowlevel) { | |||||
out.println("This is quite a low level problem, which may need" + | |||||
"consultation with the author of the task"); | |||||
if(antTask) { | |||||
out.println("This may be the Ant team. Please file a " + | |||||
"defect or contact the developer team"); | |||||
} else { | |||||
out.println("This does not appear to be a task bundled with Ant"); | |||||
out.println("Please take it up with the supplier of the third-party "+type); | |||||
out.println("If you have written it yourself, you probably have a bug to fix"); | |||||
} | |||||
} else { | |||||
out.println(); | |||||
out.println("It is not an Ant bug; there is no need to file a bug" + | |||||
" report or contact the developers"); | |||||
} | |||||
} | |||||
out.flush(); | |||||
out.close(); | |||||
return errorText.toString(); | |||||
} | |||||
/** | /** | ||||
* Map that contains the component definitions. | * Map that contains the component definitions. | ||||
*/ | */ | ||||
@@ -72,7 +72,7 @@ public final class Diagnostics { | |||||
public static void validateVersion() throws BuildException { | public static void validateVersion() throws BuildException { | ||||
try { | try { | ||||
Class optional | Class optional | ||||
= Class.forName("org.apache.tools.ant.taskdefs.optional.Test"); | |||||
= Class.forName(TEST_CLASS); | |||||
String coreVersion = getImplementationVersion(Main.class); | String coreVersion = getImplementationVersion(Main.class); | ||||
String optionalVersion = getImplementationVersion(optional); | String optionalVersion = getImplementationVersion(optional); | ||||
@@ -94,7 +94,7 @@ public final class Diagnostics { | |||||
* <tt>null</tt> if an error occurs. | * <tt>null</tt> if an error occurs. | ||||
*/ | */ | ||||
public static File[] listLibraries() { | public static File[] listLibraries() { | ||||
String home = System.getProperty("ant.home"); | |||||
String home = System.getProperty(Launcher.ANTHOME_PROPERTY); | |||||
if (home == null) { | if (home == null) { | ||||
return null; | return null; | ||||
} | } | ||||
@@ -211,8 +211,7 @@ public final class Diagnostics { | |||||
Class optional = null; | Class optional = null; | ||||
try { | try { | ||||
optional = Class.forName( | |||||
"org.apache.tools.ant.taskdefs.optional.Test"); | |||||
optional = Class.forName(TEST_CLASS); | |||||
out.println("optional tasks : " | out.println("optional tasks : " | ||||
+ getImplementationVersion(optional)); | + getImplementationVersion(optional)); | ||||
} catch (ClassNotFoundException e) { | } catch (ClassNotFoundException e) { | ||||
@@ -340,7 +339,7 @@ public final class Diagnostics { | |||||
*/ | */ | ||||
private static void doReportTasksAvailability(PrintStream out) { | private static void doReportTasksAvailability(PrintStream out) { | ||||
InputStream is = Main.class.getResourceAsStream( | InputStream is = Main.class.getResourceAsStream( | ||||
"/org/apache/tools/ant/taskdefs/defaults.properties"); | |||||
MagicNames.TASKDEF_PROPERTIES_RESOURCE); | |||||
if (is == null) { | if (is == null) { | ||||
out.println("None available"); | out.println("None available"); | ||||
} else { | } else { | ||||
@@ -24,11 +24,43 @@ package org.apache.tools.ant; | |||||
* @since Ant 1.6 | * @since Ant 1.6 | ||||
*/ | */ | ||||
public class MagicNames { | public class MagicNames { | ||||
/** The name of the script repository used by the script repo task */ | |||||
/** | |||||
* The name of the script repository used by the script repo task | |||||
* Value {@value} | |||||
*/ | |||||
public static final String SCRIPT_REPOSITORY = "org.apache.ant.scriptrepo"; | public static final String SCRIPT_REPOSITORY = "org.apache.ant.scriptrepo"; | ||||
/** The name of the reference to the System Class Loader */ | |||||
/** | |||||
* The name of the reference to the System Class Loader | |||||
* Value {@value} | |||||
**/ | |||||
public static final String SYSTEM_LOADER_REF = "ant.coreLoader"; | public static final String SYSTEM_LOADER_REF = "ant.coreLoader"; | ||||
/** | |||||
* Name of the property which can provide an override of the repository dir | |||||
* for the libraries task | |||||
* Value {@value} | |||||
*/ | |||||
public static final String REPOSITORY_DIR_PROPERTY = "ant.maven.repository.dir"; | |||||
/** | |||||
* Name of the property which can provide an override of the repository URL | |||||
* for the libraries task | |||||
* Value {@value} | |||||
*/ | |||||
public static final String REPOSITORY_URL_PROPERTY = "ant.maven.repository.url"; | |||||
/** | |||||
* name of the resource that taskdefs are stored under | |||||
* Value: {@value} | |||||
*/ | |||||
public static final String TASKDEF_PROPERTIES_RESOURCE = | |||||
"/org/apache/tools/ant/taskdefs/defaults.properties"; | |||||
/** | |||||
* name of the resource that typedefs are stored under | |||||
* Value: {@value} | |||||
*/ | |||||
public static final String TYPEDEFS_PROPERTIES_RESOURCE = | |||||
"/org/apache/tools/ant/types/defaults.properties"; | |||||
} | } | ||||
@@ -463,45 +463,8 @@ public class UnknownElement extends Task { | |||||
*/ | */ | ||||
protected BuildException getNotFoundException(String what, | protected BuildException getNotFoundException(String what, | ||||
String elementName) { | String elementName) { | ||||
String lSep = System.getProperty("line.separator"); | |||||
String msg = "Could not create " + what + " of type: " + elementName | |||||
+ "." + lSep + lSep | |||||
+ "Ant could not find the task or a class this " | |||||
+ "task relies upon." + lSep + lSep | |||||
+ "This is common and has a number of causes; the usual " + lSep | |||||
+ "solutions are to read the manual pages then download and" + lSep | |||||
+ "install needed JAR files, or fix the build file: " + lSep | |||||
+ " - You have misspelt '" + elementName + "'." + lSep | |||||
+ " Fix: check your spelling." + lSep | |||||
+ " - The task needs an external JAR file to execute" + lSep | |||||
+ " and this is not found at the right place in the classpath." + lSep | |||||
+ " Fix: check the documentation for dependencies." + lSep | |||||
+ " Fix: declare the task." + lSep | |||||
+ " - The task is an Ant optional task and the JAR file and/or libraries" + lSep | |||||
+ " implementing the functionality were not found at the time you" + lSep | |||||
+ " yourself built your installation of Ant from the Ant sources." + lSep | |||||
+ " Fix: Look in the ANT_HOME/lib for the 'ant-' JAR corresponding to the" + lSep | |||||
+ " task and make sure it contains more than merely a META-INF/MANIFEST.MF." + lSep | |||||
+ " If all it contains is the manifest, then rebuild Ant with the needed" + lSep | |||||
+ " libraries present in ${ant.home}/lib/optional/ , or alternatively," + lSep | |||||
+ " download a pre-built release version from apache.org" + lSep | |||||
+ " - The build file was written for a later version of Ant" + lSep | |||||
+ " Fix: upgrade to at least the latest release version of Ant" + lSep | |||||
+ " - The task is not an Ant core or optional task " + lSep | |||||
+ " and needs to be declared using <taskdef>." + lSep | |||||
+ " - You are attempting to use a task defined using " + lSep | |||||
+ " <presetdef> or <macrodef> but have spelt wrong or not " + lSep | |||||
+ " defined it at the point of use" + lSep | |||||
+ lSep | |||||
+ "Remember that for JAR files to be visible to Ant tasks implemented" + lSep | |||||
+ "in ANT_HOME/lib, the files must be in the same directory or on the" + lSep | |||||
+ "classpath" + lSep | |||||
+ lSep | |||||
+ "Please neither file bug reports on this problem, nor email the" + lSep | |||||
+ "Ant mailing lists, until all of these causes have been explored," + lSep | |||||
+ "as this is not an Ant bug."; | |||||
ComponentHelper helper = ComponentHelper.getComponentHelper(getProject()); | |||||
String msg = helper.diagnoseCreationFailure(elementName, what); | |||||
return new BuildException(msg, getLocation()); | return new BuildException(msg, getLocation()); | ||||
} | } | ||||
@@ -32,7 +32,10 @@ import java.util.Iterator; | |||||
* @since Ant 1.6 | * @since Ant 1.6 | ||||
*/ | */ | ||||
public class Launcher { | public class Launcher { | ||||
/** The Ant Home property */ | |||||
/** | |||||
* Ant home directory | |||||
* Value : {@value} | |||||
*/ | |||||
public static final String ANTHOME_PROPERTY = "ant.home"; | public static final String ANTHOME_PROPERTY = "ant.home"; | ||||
/** The Ant Library Directory property */ | /** The Ant Library Directory property */ | ||||