@@ -277,6 +277,12 @@ | |||
</or> | |||
</selector> | |||
<selector id="needs.jakartamail"> | |||
<or> | |||
<filename name="${ant.package}/taskdefs/email/JakartaMimeMailer*"/> | |||
</or> | |||
</selector> | |||
<selector id="needs.netrexx"> | |||
<filename name="${optional.package}/NetRexxC*"/> | |||
</selector> | |||
@@ -360,6 +366,7 @@ | |||
<selector refid="needs.imageio"/> | |||
<selector refid="needs.jai"/> | |||
<selector refid="needs.javamail"/> | |||
<selector refid="needs.jakartamail"/> | |||
<selector refid="needs.jdepend"/> | |||
<selector refid="needs.jmf"/> | |||
<selector refid="needs.jsch"/> | |||
@@ -507,6 +514,9 @@ | |||
<available property="javamail.present" | |||
classname="javax.mail.Transport" | |||
classpathref="classpath" ignoresystemclasses="${ignoresystemclasses}"/> | |||
<available property="jakartamail.present" | |||
classname="jakarta.mail.Transport" | |||
classpathref="classpath" ignoresystemclasses="${ignoresystemclasses}"/> | |||
<available property="graaljs.present" | |||
classname="com.oracle.truffle.js.scriptengine.GraalJSScriptEngine" | |||
classpathref="classpath" ignoresystemclasses="${ignoresystemclasses}"/> | |||
@@ -704,6 +714,7 @@ | |||
<selector refid="needs.commons-logging" unless="commons.logging.present"/> | |||
<selector refid="needs.apache-bsf" unless="bsf.present"/> | |||
<selector refid="needs.javamail" unless="javamail.present"/> | |||
<selector refid="needs.jakartamail" unless="jakartamail.present"/> | |||
<selector refid="needs.netrexx" unless="netrexx.present"/> | |||
<selector refid="needs.commons-net" unless="commons.net.present"/> | |||
<selector refid="needs.antlr" unless="antlr.present"/> | |||
@@ -867,6 +878,7 @@ | |||
<optional-jar dep="commons-logging"/> | |||
<optional-jar dep="apache-bsf"/> | |||
<optional-jar dep="javamail"/> | |||
<optional-jar dep="jakartamail"/> | |||
<optional-jar dep="netrexx"/> | |||
<optional-jar dep="commons-net"/> | |||
<optional-jar dep="antlr"/> | |||
@@ -962,6 +974,7 @@ | |||
<optional-src-jar dep="commons-logging"/> | |||
<optional-src-jar dep="apache-bsf"/> | |||
<optional-src-jar dep="javamail"/> | |||
<optional-src-jar dep="jakartamail"/> | |||
<optional-src-jar dep="netrexx"/> | |||
<optional-src-jar dep="commons-net"/> | |||
<optional-src-jar dep="antlr"/> | |||
@@ -335,6 +335,12 @@ Set -Ddest=LOCATION on the command line | |||
<f2 project="which"/> | |||
</target> | |||
<target name="javamail" | |||
description="load Java Mail" | |||
depends="init"> | |||
<f2 project="com.sun.mail" archive="javax.mail"/> | |||
</target> | |||
<target name="jakartamail" | |||
description="load Jakarta Mail" | |||
depends="init"> | |||
@@ -51,7 +51,9 @@ hamcrest-core.version=1.3 | |||
hamcrest-library.version=${hamcrest-core.version} | |||
jai-core.version=1.1.3 | |||
jai-codec.version=1.1.3 | |||
jakarta.mail.version=1.6.4 | |||
# Later 1.6 versions call themselves "jakarta.mail" but do not use the namespace yet | |||
javax.mail.version=1.6.2 | |||
jakarta.mail.version=2.0.1 | |||
jakarta-regexp.version=1.4 | |||
# Later versions of Tomcat provide a jspc task | |||
jasper-compiler.version=4.1.36 | |||
@@ -0,0 +1,98 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
https://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. | |||
--> | |||
<!-- | |||
This POM has been created manually by the Ant Development Team. | |||
Please contact us if you are not satisfied with the data contained in this POM. | |||
URL : https://ant.apache.org | |||
--> | |||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd"> | |||
<parent> | |||
<groupId>org.apache.ant</groupId> | |||
<artifactId>ant-parent</artifactId> | |||
<relativePath>../pom.xml</relativePath> | |||
<version>1.10.12-SNAPSHOT</version> | |||
</parent> | |||
<modelVersion>4.0.0</modelVersion> | |||
<url>https://ant.apache.org/</url> | |||
<groupId>org.apache.ant</groupId> | |||
<artifactId>ant-jakartamail</artifactId> | |||
<version>1.10.12-SNAPSHOT</version> | |||
<name>Apache Ant + JakartaMail</name> | |||
<description>implementation of the mail task based on Jakarta EE mail. | |||
Required to send emails to SMTP servers using user/password combinations | |||
or to send mail over SSL</description> | |||
<dependencies> | |||
<dependency> | |||
<groupId>org.apache.ant</groupId> | |||
<artifactId>ant</artifactId> | |||
<version>1.10.12-SNAPSHOT</version> | |||
<scope>compile</scope> | |||
</dependency> | |||
<dependency> | |||
<!-- This brings in the necessary dependencies. | |||
See https://eclipse-ee4j.github.io/mail/ --> | |||
<groupId>com.sun.mail</groupId> | |||
<artifactId>jakarta.mail</artifactId> | |||
<version>2.0.1</version> | |||
<scope>compile</scope> | |||
</dependency> | |||
</dependencies> | |||
<build> | |||
<plugins> | |||
<plugin> | |||
<groupId>org.apache.maven.plugins</groupId> | |||
<artifactId>maven-compiler-plugin</artifactId> | |||
<configuration> | |||
<includes> | |||
<include>org/apache/tools/ant/taskdefs/email/JakartaMimeMailer*</include> | |||
</includes> | |||
</configuration> | |||
</plugin> | |||
<plugin> | |||
<groupId>org.apache.maven.plugins</groupId> | |||
<artifactId>maven-jar-plugin</artifactId> | |||
<configuration> | |||
<archive> | |||
<index>true</index> | |||
<manifest> | |||
<addExtensions>true</addExtensions> | |||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries> | |||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> | |||
</manifest> | |||
</archive> | |||
</configuration> | |||
</plugin> | |||
</plugins> | |||
<resources> | |||
<resource> | |||
<directory>../../../..</directory> | |||
<targetPath>META-INF</targetPath> | |||
<includes> | |||
<include>LICENSE</include> | |||
<include>NOTICE</include> | |||
</includes> | |||
</resource> | |||
</resources> | |||
<sourceDirectory>../../../../src/main</sourceDirectory> | |||
<testSourceDirectory>../../../../src/testcases</testSourceDirectory> | |||
<outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory> | |||
<testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory> | |||
<directory>../../../../target/${project.artifactId}</directory> | |||
</build> | |||
</project> |
@@ -48,8 +48,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/m | |||
<!-- This brings in the necessary dependencies. | |||
See https://eclipse-ee4j.github.io/mail/ --> | |||
<groupId>com.sun.mail</groupId> | |||
<artifactId>jakarta.mail</artifactId> | |||
<version>1.6.4</version> | |||
<artifactId>javax.mail</artifactId> | |||
<version>1.6.2</version> | |||
<scope>compile</scope> | |||
</dependency> | |||
</dependencies> | |||
@@ -160,7 +160,7 @@ | |||
<exclude>org/apache/tools/ant/launch/</exclude> | |||
<exclude>org/apache/tools/ant/listener/CommonsLoggingListener*</exclude> | |||
<exclude>org/apache/tools/ant/listener/Log4jListener*</exclude> | |||
<exclude>org/apache/tools/ant/taskdefs/email/MimeMailer*</exclude> | |||
<exclude>org/apache/tools/ant/taskdefs/email/*MimeMailer*</exclude> | |||
<exclude>${modules.exclude}</exclude> | |||
<exclude>org/apache/tools/ant/taskdefs/optional/NetRexxC*</exclude> | |||
<exclude>org/apache/tools/ant/taskdefs/optional/Xalan2TraceSupport*</exclude> | |||
@@ -95,6 +95,7 @@ | |||
<module>ant-imageio</module> | |||
<module>ant-jai</module> | |||
<module>ant-javamail</module> | |||
<module>ant-jakartamail</module> | |||
<module>ant-jdepend</module> | |||
<module>ant-jmf</module> | |||
<module>ant-jsch</module> | |||
@@ -449,16 +449,9 @@ public class EmailTask extends Task { | |||
// prepare for the auto select mechanism | |||
boolean autoFound = false; | |||
// try MIME format | |||
if (MIME.equals(encoding) | |||
|| (AUTO.equals(encoding) && !autoFound)) { | |||
if (MIME.equals(encoding) || AUTO.equals(encoding)) { | |||
try { | |||
//check to make sure that activation.jar | |||
//and mail.jar are available - see bug 31969 | |||
Class.forName("javax.activation.DataHandler"); | |||
Class.forName("javax.mail.internet.MimeMessage"); | |||
mailer = ClasspathUtils.newInstance( | |||
"org.apache.tools.ant.taskdefs.email.MimeMailer", | |||
mailer = ClasspathUtils.newInstance(getMailerImplementation(), | |||
EmailTask.class.getClassLoader(), Mailer.class); | |||
autoFound = true; | |||
@@ -600,6 +593,32 @@ public class EmailTask extends Task { | |||
} | |||
} | |||
private String getMailerImplementation() { | |||
//check to make sure that activation.jar | |||
//and mail.jar are available - see bug 31969 | |||
try { | |||
Class.forName("jakarta.activation.DataHandler"); | |||
Class.forName("jakarta.mail.internet.MimeMessage"); | |||
return "org.apache.tools.ant.taskdefs.email.JakartaMimeMailer"; | |||
} catch (ClassNotFoundException cnfe) { | |||
logBuildException("Could not find Jakarta MIME mail: ", | |||
new BuildException(cnfe)); | |||
} | |||
try { | |||
Class.forName("javax.activation.DataHandler"); | |||
Class.forName("javax.mail.internet.MimeMessage"); | |||
return "org.apache.tools.ant.taskdefs.email.MimeMailer"; | |||
} catch (ClassNotFoundException cnfe) { | |||
logBuildException("Could not find MIME mail: ", | |||
new BuildException(cnfe)); | |||
} | |||
return "org.apache.tools.ant.taskdefs.email.Mailer"; | |||
} | |||
private void logBuildException(String reason, BuildException e) { | |||
Throwable t = e.getCause() == null ? e : e.getCause(); | |||
log(reason + t.getMessage(), Project.MSG_WARN); | |||
@@ -0,0 +1,340 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* https://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs.email; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.io.PrintStream; | |||
import java.io.UnsupportedEncodingException; | |||
import java.security.Provider; | |||
import java.security.Security; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Locale; | |||
import java.util.Properties; | |||
import java.util.StringTokenizer; | |||
import java.util.Vector; | |||
import jakarta.activation.DataHandler; | |||
import jakarta.activation.DataSource; | |||
import jakarta.activation.FileDataSource; | |||
import jakarta.mail.Address; | |||
import jakarta.mail.Authenticator; | |||
import jakarta.mail.Message; | |||
import jakarta.mail.MessagingException; | |||
import jakarta.mail.PasswordAuthentication; | |||
import jakarta.mail.SendFailedException; | |||
import jakarta.mail.Session; | |||
import jakarta.mail.Transport; | |||
import jakarta.mail.internet.AddressException; | |||
import jakarta.mail.internet.InternetAddress; | |||
import jakarta.mail.internet.MimeBodyPart; | |||
import jakarta.mail.internet.MimeMessage; | |||
import jakarta.mail.internet.MimeMultipart; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
/** | |||
* Uses the JakartaMail classes to send Mime format email. | |||
* | |||
* @since Ant 1.10.12 | |||
*/ | |||
public class JakartaMimeMailer extends Mailer { | |||
private static final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; | |||
private static final String GENERIC_ERROR = | |||
"Problem while sending mime mail:"; | |||
/** Default character set */ | |||
private static final String DEFAULT_CHARSET | |||
= System.getProperty("file.encoding"); | |||
// To work properly with national charsets we have to use | |||
// implementation of interface jakarta.activation.DataSource | |||
/** | |||
* String data source implementation. | |||
*/ | |||
class StringDataSource implements DataSource { | |||
private String data = null; | |||
private String type = null; | |||
private String charset = null; | |||
private ByteArrayOutputStream out; | |||
@Override | |||
public InputStream getInputStream() throws IOException { | |||
if (data == null && out == null) { | |||
throw new IOException("No data"); | |||
} | |||
if (out != null) { | |||
final String encodedOut = out.toString(charset); | |||
data = (data != null) ? data.concat(encodedOut) : encodedOut; | |||
out = null; | |||
} | |||
return new ByteArrayInputStream(data.getBytes(charset)); | |||
} | |||
@Override | |||
public OutputStream getOutputStream() throws IOException { | |||
out = (out == null) ? new ByteArrayOutputStream() : out; | |||
return out; | |||
} | |||
public void setContentType(final String type) { | |||
this.type = type.toLowerCase(Locale.ENGLISH); | |||
} | |||
@Override | |||
public String getContentType() { | |||
if (type != null && type.indexOf("charset") > 0 | |||
&& type.startsWith("text/")) { | |||
return type; | |||
} | |||
// Must be like "text/plain; charset=windows-1251" | |||
return (type != null ? type : "text/plain") + | |||
"; charset=" + charset; | |||
} | |||
@Override | |||
public String getName() { | |||
return "StringDataSource"; | |||
} | |||
public void setCharset(final String charset) { | |||
this.charset = charset; | |||
} | |||
public String getCharset() { | |||
return charset; | |||
} | |||
} | |||
/** | |||
* Send the email. | |||
* | |||
* @throws BuildException if the email can't be sent. | |||
*/ | |||
@Override | |||
public void send() { | |||
try { | |||
final Properties props = new Properties(); | |||
props.put("mail.smtp.host", host); | |||
props.put("mail.smtp.port", String.valueOf(port)); | |||
// Aside, the JDK is clearly unaware of the Scottish | |||
// 'session', which involves excessive quantities of | |||
// alcohol :-) | |||
Session sesh; | |||
Authenticator auth = null; | |||
if (SSL) { | |||
try { | |||
final Provider p = | |||
Class.forName("com.sun.net.ssl.internal.ssl.Provider") | |||
.asSubclass(Provider.class).getDeclaredConstructor().newInstance(); | |||
Security.addProvider(p); | |||
} catch (final Exception e) { | |||
throw new BuildException( | |||
"could not instantiate ssl security provider, check that you have JSSE in your classpath"); | |||
} | |||
// SMTP provider | |||
props.put("mail.smtp.socketFactory.class", SSL_FACTORY); | |||
props.put("mail.smtp.socketFactory.fallback", "false"); | |||
props.put("mail.smtps.host", host); | |||
if (isPortExplicitlySpecified()) { | |||
props.put("mail.smtps.port", String.valueOf(port)); | |||
props.put("mail.smtp.socketFactory.port", | |||
String.valueOf(port)); | |||
} | |||
} | |||
if (user != null || password != null) { | |||
props.put("mail.smtp.auth", "true"); | |||
auth = new SimpleAuthenticator(user, password); | |||
} | |||
if (isStartTLSEnabled()) { | |||
props.put("mail.smtp.starttls.enable", "true"); | |||
} | |||
sesh = Session.getInstance(props, auth); | |||
//create the message | |||
final MimeMessage msg = new MimeMessage(sesh); | |||
final MimeMultipart attachments = new MimeMultipart(); | |||
//set the sender | |||
if (from.getName() == null) { | |||
msg.setFrom(new InternetAddress(from.getAddress())); | |||
} else { | |||
msg.setFrom(new InternetAddress(from.getAddress(), | |||
from.getName())); | |||
} | |||
// set the reply to addresses | |||
msg.setReplyTo(internetAddresses(replyToList)); | |||
msg.setRecipients(Message.RecipientType.TO, | |||
internetAddresses(toList)); | |||
msg.setRecipients(Message.RecipientType.CC, | |||
internetAddresses(ccList)); | |||
msg.setRecipients(Message.RecipientType.BCC, | |||
internetAddresses(bccList)); | |||
// Choosing character set of the mail message | |||
// First: looking it from MimeType | |||
String charset = parseCharSetFromMimeType(message.getMimeType()); | |||
if (charset != null) { | |||
// Assign/reassign message charset from MimeType | |||
message.setCharset(charset); | |||
} else { | |||
// Next: looking if charset having explicit definition | |||
charset = message.getCharset(); | |||
if (charset == null) { | |||
// Using default | |||
charset = DEFAULT_CHARSET; | |||
message.setCharset(charset); | |||
} | |||
} | |||
// Using jakarta.activation.DataSource paradigm | |||
final StringDataSource sds = new StringDataSource(); | |||
sds.setContentType(message.getMimeType()); | |||
sds.setCharset(charset); | |||
if (subject != null) { | |||
msg.setSubject(subject, charset); | |||
} | |||
msg.addHeader("Date", getDate()); | |||
if (headers != null) { | |||
for (Header h : headers) { | |||
msg.addHeader(h.getName(), h.getValue()); | |||
} | |||
} | |||
final PrintStream out = new PrintStream(sds.getOutputStream()); | |||
message.print(out); | |||
out.close(); | |||
final MimeBodyPart textbody = new MimeBodyPart(); | |||
textbody.setDataHandler(new DataHandler(sds)); | |||
attachments.addBodyPart(textbody); | |||
for (File file : files) { | |||
MimeBodyPart body = new MimeBodyPart(); | |||
if (!file.exists() || !file.canRead()) { | |||
throw new BuildException( | |||
"File \"%s\" does not exist or is not readable.", | |||
file.getAbsolutePath()); | |||
} | |||
final FileDataSource fileData = new FileDataSource(file); | |||
final DataHandler fileDataHandler = new DataHandler(fileData); | |||
body.setDataHandler(fileDataHandler); | |||
body.setFileName(file.getName()); | |||
attachments.addBodyPart(body); | |||
} | |||
msg.setContent(attachments); | |||
try { | |||
// Send the message using SMTP, or SMTPS if the host uses SSL | |||
final Transport transport = sesh.getTransport(SSL ? "smtps" : "smtp"); | |||
transport.connect(host, user, password); | |||
transport.sendMessage(msg, msg.getAllRecipients()); | |||
} catch (final SendFailedException sfe) { | |||
if (!shouldIgnoreInvalidRecipients()) { | |||
throw new BuildException(GENERIC_ERROR, sfe); | |||
} | |||
if (sfe.getValidSentAddresses() == null | |||
|| sfe.getValidSentAddresses().length == 0) { | |||
throw new BuildException("Couldn't reach any recipient", | |||
sfe); | |||
} | |||
Address[] invalid = sfe.getInvalidAddresses(); | |||
if (invalid == null) { | |||
invalid = new Address[0]; | |||
} | |||
for (Address address : invalid) { | |||
didntReach(address, "invalid", sfe); | |||
} | |||
Address[] validUnsent = sfe.getValidUnsentAddresses(); | |||
if (validUnsent == null) { | |||
validUnsent = new Address[0]; | |||
} | |||
for (Address address : validUnsent) { | |||
didntReach(address, "valid", sfe); | |||
} | |||
} | |||
} catch (MessagingException | IOException e) { | |||
throw new BuildException(GENERIC_ERROR, e); | |||
} | |||
} | |||
private static InternetAddress[] internetAddresses(final Vector<EmailAddress> list) | |||
throws AddressException, UnsupportedEncodingException { | |||
final List<InternetAddress> addrs = new ArrayList<>(); | |||
for (final EmailAddress addr : list) { | |||
final String name = addr.getName(); | |||
addrs.add((name == null) | |||
? new InternetAddress(addr.getAddress()) | |||
: new InternetAddress(addr.getAddress(), name)); | |||
} | |||
return addrs.toArray(new InternetAddress[addrs.size()]); | |||
} | |||
private String parseCharSetFromMimeType(final String type) { | |||
if (type == null) { | |||
return null; | |||
} | |||
final int pos = type.indexOf("charset"); | |||
if (pos < 0) { | |||
return null; | |||
} | |||
// Assuming mime type in form "text/XXXX; charset=XXXXXX" | |||
final StringTokenizer token = new StringTokenizer(type.substring(pos), "=; "); | |||
token.nextToken(); // Skip 'charset=' | |||
return token.nextToken(); | |||
} | |||
private void didntReach(final Address addr, final String category, | |||
final MessagingException ex) { | |||
final String msg = "Failed to send mail to " + category + " address " | |||
+ addr + " because of " + ex.getMessage(); | |||
if (task != null) { | |||
task.log(msg, Project.MSG_WARN); | |||
} else { | |||
System.err.println(msg); | |||
} | |||
} | |||
static class SimpleAuthenticator extends Authenticator { | |||
private String user = null; | |||
private String password = null; | |||
public SimpleAuthenticator(final String user, final String password) { | |||
this.user = user; | |||
this.password = password; | |||
} | |||
@Override | |||
public PasswordAuthentication getPasswordAuthentication() { | |||
return new PasswordAuthentication(user, password); | |||
} | |||
} | |||
} | |||
@@ -58,7 +58,9 @@ import org.apache.tools.ant.Project; | |||
* Uses the JavaMail classes to send Mime format email. | |||
* | |||
* @since Ant 1.5 | |||
* @deprecated see org.apache.tools.ant.taskdefs.email.JakartaMimeMailer | |||
*/ | |||
@Deprecated | |||
public class MimeMailer extends Mailer { | |||
private static final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; | |||
@@ -26,6 +26,7 @@ import org.apache.tools.ant.types.Path; | |||
import org.apache.tools.ant.types.Reference; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.reflect.Modifier; | |||
// CheckStyle:HideUtilityClassConstructorCheck OFF - bc | |||
@@ -251,6 +252,9 @@ public class ClasspathUtils { | |||
try { | |||
@SuppressWarnings("unchecked") | |||
Class<T> clazz = (Class<T>) Class.forName(className, true, userDefinedLoader); | |||
if (Modifier.isAbstract(clazz.getModifiers())) { | |||
throw new BuildException("Abstract class " + className); | |||
} | |||
T o = clazz.getDeclaredConstructor().newInstance(); | |||
if (!expectedType.isInstance(o)) { | |||
throw new BuildException( | |||