This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to annotated tag 0.8 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 2841d8723ada03eaa333eecd464b3221350da049 Author: Martin Desruisseaux <[email protected]> AuthorDate: Sat Nov 4 21:51:32 2017 +0000 Port bug fixes from 1.0 development branch to 0.8 branch: - omission of redundant parameters in CoordinateOperation WKT - consolidation of logging messages when SIS_DATA is defined but no EPSG database is available git-svn-id: https://svn.apache.org/repos/asf/sis/branches/0.8@1814325 13f79535-47bb-0310-9956-ffa450edef68 --- .../sis/internal/referencing/WKTUtilities.java | 29 +++++++++++++ .../internal/referencing/provider/Molodensky.java | 45 ++++++++++++++++++- .../apache/sis/referencing/AuthorityFactories.java | 4 +- .../factory/ConcurrentAuthorityFactory.java | 25 +++++++++-- .../sis/referencing/factory/sql/EPSGFactory.java | 50 ++++++++++++++++------ .../sis/referencing/factory/sql/EPSGInstaller.java | 13 +++--- .../operation/AbstractCoordinateOperation.java | 21 ++++++++- .../DefaultConcatenatedOperationTest.java | 6 +-- .../java/org/apache/sis/util/logging/Logging.java | 5 ++- 9 files changed, 167 insertions(+), 31 deletions(-) diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java index 03bd5b6..0ae34c1 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java @@ -22,7 +22,9 @@ import javax.measure.quantity.Angle; import org.opengis.parameter.ParameterValue; import org.opengis.parameter.ParameterValueGroup; import org.opengis.parameter.GeneralParameterValue; +import org.opengis.parameter.GeneralParameterDescriptor; import org.opengis.referencing.IdentifiedObject; +import org.opengis.referencing.ReferenceIdentifier; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.cs.CoordinateSystem; import org.opengis.referencing.cs.CoordinateSystemAxis; @@ -46,6 +48,7 @@ import org.apache.sis.measure.Units; import org.apache.sis.util.Static; import org.apache.sis.util.CharSequences; import org.apache.sis.util.resources.Vocabulary; +import org.apache.sis.internal.util.Constants; /** @@ -246,6 +249,32 @@ public final class WKTUtilities extends Static { } /** + * Returns {@code true} if the given parameter is defined in the EPSG code space. We handle EPSG + * parameters in a special way because Apache SIS uses the EPSG geodetic dataset as the primary + * source of coordinate operation definitions. + * + * <p>We intentionally don't define {@code isEPSG(OperationMethod)} method because the operation + * method may be the inverse of an EPSG method (for example "Inverse of Mercator (variant A)") + * which would not be recognized. Instead, {@code isEPSG(method.getParameters())} should work.</p> + * + * @param descriptor the parameter or group of parameters to inspect. + * @param ifUndefined the value to return if the code space is undefined. + * @return whether the given parameter is an EPSG parameter. + */ + public static boolean isEPSG(final GeneralParameterDescriptor descriptor, final boolean ifUndefined) { + if (descriptor != null) { + final ReferenceIdentifier id = descriptor.getName(); + if (id != null) { + final String cs = id.getCodeSpace(); + if (cs != null) { + return Constants.EPSG.equalsIgnoreCase(cs); + } + } + } + return ifUndefined; + } + + /** * Returns the WKT type of the given interface. * * For {@link CoordinateSystem} base type, the returned value shall be one of diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java index f2c82c5..d84075e 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java @@ -19,6 +19,7 @@ package org.apache.sis.internal.referencing.provider; import java.util.Map; import java.util.Collections; import javax.xml.bind.annotation.XmlTransient; +import javax.measure.Unit; import org.opengis.util.FactoryException; import org.opengis.parameter.ParameterValueGroup; import org.opengis.parameter.ParameterDescriptor; @@ -34,9 +35,11 @@ import org.apache.sis.referencing.datum.DefaultEllipsoid; import org.apache.sis.referencing.operation.transform.MolodenskyTransform; import org.apache.sis.internal.referencing.NilReferencingObject; import org.apache.sis.internal.referencing.Formulas; +import org.apache.sis.internal.system.Loggers; import org.apache.sis.internal.util.Constants; import org.apache.sis.measure.Units; import org.apache.sis.util.resources.Errors; +import org.apache.sis.util.logging.Logging; import org.apache.sis.util.Debug; @@ -226,6 +229,7 @@ public final class Molodensky extends GeocentricAffineBetweenGeographic { final Ellipsoid target = new Ellipsoid(name, ta, tb, -Δa, -Δf); source.other = target; target.other = source; + source.computeDifferences(values); return MolodenskyTransform.createGeodeticTransformation(factory, source, sourceDimensions >= 3, target, targetDimensions >= 3, @@ -258,7 +262,7 @@ public final class Molodensky extends GeocentricAffineBetweenGeographic { @SuppressWarnings("serial") private static final class Ellipsoid extends DefaultEllipsoid { /** The EPSG parameter values, or NaN if unspecified. */ - private final double Δa, Δf; + private double Δa, Δf; /** The ellipsoid for which Δa and Δf are valid. */ Ellipsoid other; @@ -270,6 +274,45 @@ public final class Molodensky extends GeocentricAffineBetweenGeographic { this.Δf = Δf; } + /** + * Computes Δa and Δf now if not already done and tries to store the result in the given parameters. + * The parameters are set in order to complete them when the user specified the OGC parameters (axis + * lengths) and not the EPSG ones (axis and flattening differences). + */ + void computeDifferences(final Parameters values) { + if (Double.isNaN(Δa)) { + Δa = super.semiMajorAxisDifference(other); + setIfPresent(values, AXIS_LENGTH_DIFFERENCE, Δa, getAxisUnit()); + } + if (Double.isNaN(Δf)) { + Δf = super.flatteningDifference(other); + setIfPresent(values, FLATTENING_DIFFERENCE, Δf, Units.UNITY); + } + } + + /** + * Tries to set the given parameter values. This method should be invoked only when completing parameters + * without explicit values. This approach complete the work done in {@code DefaultMathTransformFactory}, + * which already completed the {@code src_semi_major}, {@code src_semi_minor}, {@code tgt_semi_major} and + * {@code tgt_semi_minor} parameters. + * + * @param values the group in which to set the parameter values. + * @param parameter descriptor of the parameter to set. + * @param value the new value. + * @param unit unit of measurement for the new value. + */ + private static void setIfPresent(final Parameters values, final ParameterDescriptor<Double> parameter, + final double value, final Unit<?> unit) + { + try { + values.getOrCreate(parameter).setValue(value, unit); + } catch (ParameterNotFoundException | InvalidParameterValueException e) { + // Nonn-fatal since this attempt was only for information purpose. + Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION), + Molodensky.class, "createMathTransform", e); + } + } + /** Returns Δa as specified in the parameters if possible, or compute it otherwise. */ @Override public double semiMajorAxisDifference(final org.opengis.referencing.datum.Ellipsoid target) { return (target == other && !Double.isNaN(Δa)) ? Δa : super.semiMajorAxisDifference(target); diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java index 51be16c..f412dc8 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java @@ -194,8 +194,10 @@ final class AuthorityFactories<T extends AuthorityFactory> extends LazySet<T> { message = e.toString(); } final LogRecord record = new LogRecord(isWarning ? Level.WARNING : Level.CONFIG, message); + if (isWarning && !(e instanceof UnavailableFactoryException)) { + record.setThrown(e); + } record.setLoggerName(Loggers.CRS_FACTORY); - if (isWarning) record.setThrown(e); Logging.log(CRS.class, "getAuthorityFactory", record); } diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java index 09f5122..8ac3a6d 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java @@ -28,6 +28,7 @@ import java.util.IdentityHashMap; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.logging.LogRecord; +import java.util.logging.Level; import java.lang.ref.WeakReference; import java.lang.ref.PhantomReference; import java.io.PrintWriter; @@ -50,6 +51,7 @@ import org.apache.sis.util.Disposable; import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.logging.Logging; import org.apache.sis.util.collection.Cache; +import org.apache.sis.internal.simple.SimpleCitation; import org.apache.sis.internal.system.ReferenceQueueConsumer; import org.apache.sis.internal.system.DelayedExecutor; import org.apache.sis.internal.system.DelayedRunnable; @@ -114,6 +116,12 @@ public abstract class ConcurrentAuthorityFactory<DAO extends GeodeticAuthorityFa private static final long DURATION_FOR_LOGGING = 10_000_000L; // 10 milliseconds. /** + * Sentinel value when {@link #authority} can not be determined because the data access object + * can not be constructed. + */ + private static final Citation UNAVAILABLE = new SimpleCitation("unavailable"); + + /** * The authority, cached after first requested. */ private transient volatile Citation authority; @@ -703,7 +711,7 @@ public abstract class ConcurrentAuthorityFactory<DAO extends GeodeticAuthorityFa @Override public Citation getAuthority() { Citation c = authority; - if (c == null) try { + if (c == null || c == UNAVAILABLE) try { final DAO factory = getDataAccess(); try { /* @@ -715,8 +723,19 @@ public abstract class ConcurrentAuthorityFactory<DAO extends GeodeticAuthorityFa release("getAuthority", Citation.class, null); } } catch (FactoryException e) { - Logging.unexpectedException(Logging.getLogger(Loggers.CRS_FACTORY), - ConcurrentAuthorityFactory.class, "getAuthority", e); + authority = UNAVAILABLE; + /* + * Use the warning level only on the first failure, then the fine level on all subsequent failures. + * Do not log the stack trace if we failed because of UnavailableFactoryException since it may be + * normal (the EPSG geodetic dataset is optional, even if strongly recommended). + */ + final LogRecord record = new LogRecord(c == null ? Level.WARNING : Level.FINE, e.getLocalizedMessage()); + if (!(e instanceof UnavailableFactoryException)) { + record.setThrown(e); + } + record.setLoggerName(Loggers.CRS_FACTORY); + Logging.log(ConcurrentAuthorityFactory.class, "getAuthority", record); + c = null; } return c; } diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java index 860798a..bf9ff38 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java @@ -45,6 +45,7 @@ import org.apache.sis.internal.system.DefaultFactories; import org.apache.sis.internal.util.Constants; import org.apache.sis.referencing.factory.ConcurrentAuthorityFactory; import org.apache.sis.referencing.factory.UnavailableFactoryException; +import org.apache.sis.util.resources.Messages; import org.apache.sis.util.logging.Logging; import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.Classes; @@ -270,7 +271,7 @@ public class EPSGFactory extends ConcurrentAuthorityFactory<EPSGDataAccess> impl throw new UnavailableFactoryException(Initializer.unspecified(locale)); } } catch (Exception e) { - throw new UnavailableFactoryException(message(e), e); + throw new UnavailableFactoryException(canNotUse(e), e); } dataSource = ds; nameFactory = factory(NameFactory.class, "nameFactory", properties); @@ -293,12 +294,19 @@ public class EPSGFactory extends ConcurrentAuthorityFactory<EPSGDataAccess> impl /** * Returns the message to put in an {@link UnavailableFactoryException} having the given exception as its cause. */ - private String message(final Exception e) { + private String canNotUse(final Exception e) { String message = Exceptions.getLocalizedMessage(e, locale); if (message == null) { message = Classes.getShortClassName(e); } - return Resources.forLocale(locale).getString(Resources.Keys.CanNotUseGeodeticParameters_2, Constants.EPSG, message); + return canNotUse(message); + } + + /** + * Returns the message to put in an {@link UnavailableFactoryException} having the given cause. + */ + private String canNotUse(final String cause) { + return Resources.forLocale(locale).getString(Resources.Keys.CanNotUseGeodeticParameters_2, Constants.EPSG, cause); } /** @@ -367,15 +375,18 @@ public class EPSGFactory extends ConcurrentAuthorityFactory<EPSGDataAccess> impl * See <a href="https://issues.apache.org/jira/browse/LEGAL-183">LEGAL-183</a> for more information.</p> * * @param connection connection to the database where to create the EPSG schema. - * @throws FileNotFoundException if a SQL script has not been found, - * typically because a required resource is not on the classpath. - * @throws IOException if an I/O error occurred while reading a SQL script. - * @throws SQLException if an error occurred while writing to the database. + * @throws UnavailableFactoryException if installation failed. The exception will have a + * {@link FileNotFoundException} cause if a SQL script has not been found + * (typically because a required resource is not on the classpath), an + * {@link IOException} if an I/O error occurred while reading a SQL script, or a + * {@link SQLException} if an error occurred while writing to the database. * * @see InstallationScriptProvider */ - public synchronized void install(final Connection connection) throws IOException, SQLException { + public synchronized void install(final Connection connection) throws UnavailableFactoryException { ArgumentChecks.ensureNonNull("connection", connection); + String message = null; + Exception failure = null; try (EPSGInstaller installer = new EPSGInstaller(connection)) { final boolean ac = connection.getAutoCommit(); if (ac) { @@ -403,9 +414,21 @@ public class EPSGFactory extends ConcurrentAuthorityFactory<EPSGDataAccess> impl } } } catch (IOException | SQLException e) { - installer.logFailure(locale, e); - throw e; + message = installer.failure(locale, e); + failure = e; } + } catch (SQLException e) { + message = Messages.getResources(locale).getString(Messages.Keys.CanNotCreateSchema_1, Constants.EPSG); + failure = e; + } + if (failure != null) { + /* + * Derby sometime wraps SQLException into another SQLException. For making the stack strace a + * little bit simpler, keep only the root cause provided that the exception type is compatible. + */ + UnavailableFactoryException exception = new UnavailableFactoryException(message, Exceptions.unwrap(failure)); + exception.setUnavailableFactory(this); + throw exception; } } @@ -455,7 +478,7 @@ public class EPSGFactory extends ConcurrentAuthorityFactory<EPSGDataAccess> impl return newDataAccess(connection, tr); } else { connection.close(); - exception = new UnavailableFactoryException(SQLTranslator.tableNotFound(locale)); + exception = new UnavailableFactoryException(canNotUse(SQLTranslator.tableNotFound(locale))); } } catch (Exception e) { // Really want to catch all exceptions here. if (connection != null) try { @@ -463,11 +486,14 @@ public class EPSGFactory extends ConcurrentAuthorityFactory<EPSGDataAccess> impl } catch (SQLException e2) { e.addSuppressed(e2); } + if (e instanceof FactoryException) { + throw (FactoryException) e; + } /* * Derby sometime wraps SQLException into another SQLException. For making the stack strace a * little bit simpler, keep only the root cause provided that the exception type is compatible. */ - exception = new UnavailableFactoryException(message(e), Exceptions.unwrap(e)); + exception = new UnavailableFactoryException(canNotUse(e), Exceptions.unwrap(e)); } exception.setUnavailableFactory(this); throw exception; diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGInstaller.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGInstaller.java index 7d611cf..5cb3915 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGInstaller.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGInstaller.java @@ -25,7 +25,6 @@ import java.sql.SQLException; import java.util.StringTokenizer; import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import java.util.logging.LogRecord; import java.io.BufferedReader; import org.apache.sis.util.StringBuilders; import org.apache.sis.internal.metadata.sql.ScriptRunner; @@ -280,18 +279,16 @@ final class EPSGInstaller extends ScriptRunner { } /** - * Logs a message reporting the failure to create EPSG database. This method is invoked when {@link EPSGFactory} - * caught an exception. This log completes rather than replaces the exception message since {@code EPSGFactory} - * lets the exception propagate. Another code (for example {@link org.apache.sis.referencing.CRS#forCode(String)}) - * may catch that exception and log another record with the exception message. + * Creates a message reporting the failure to create EPSG database. This method is invoked when {@link EPSGFactory} + * caught an exception. This method completes the exception message with the file name and line number where the + * error occurred, if such information is available. */ - final void logFailure(final Locale locale, final Exception cause) { + final String failure(final Locale locale, final Exception cause) { String message = Messages.getResources(locale).getString(Messages.Keys.CanNotCreateSchema_1, EPSG); String status = status(locale); if (status != null) { message = message + ' ' + status; } - message = Exceptions.formatChainedMessages(locale, message, cause); - InstallationScriptProvider.log(new LogRecord(Level.WARNING, message)); + return Exceptions.formatChainedMessages(locale, message, cause); } } diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java index c16e1f2..8831d30 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java @@ -53,6 +53,7 @@ import org.apache.sis.util.collection.Containers; import org.apache.sis.util.UnsupportedImplementationException; import org.apache.sis.util.logging.Logging; import org.apache.sis.parameter.Parameterized; +import org.apache.sis.metadata.iso.citation.Citations; import org.apache.sis.referencing.cs.CoordinateSystems; import org.apache.sis.referencing.AbstractIdentifiedObject; import org.apache.sis.referencing.operation.transform.MathTransforms; @@ -64,6 +65,7 @@ import org.apache.sis.internal.referencing.Resources; import org.apache.sis.internal.referencing.WKTUtilities; import org.apache.sis.internal.metadata.WKTKeywords; import org.apache.sis.internal.metadata.MetadataUtilities; +import org.apache.sis.internal.util.Constants; import org.apache.sis.internal.util.CollectionsExt; import org.apache.sis.internal.util.UnmodifiableArrayList; import org.apache.sis.internal.system.Semaphores; @@ -963,10 +965,27 @@ check: for (int isTarget=0; ; isTarget++) { // 0 == source check; 1 parameters = null; } if (parameters != null) { + /* + * Format the parameter values. Apache SIS uses the EPSG geodetic dataset as the main source of + * parameter definitions. When a parameter is defined by both OGC and EPSG with different names, + * the Formatter class is responsible for choosing an appropriate name. But when the difference + * is more fundamental, we may have duplication. For example in the "Molodensky" operation, OGC + * uses source and target axis lengths while EPSG uses only difference between those lengths. + * In this case, OGC and EPSG parameters are defined separately and are redundant. To simplify + * the CoordinateOperation WKT, we omit non-EPSG parameters when we have determined that we are + * about to describe an EPSG operation. We could generalize this filtering to any authority, but + * we don't because few authorities are as complete as EPSG, so other authorities are more likely + * to mix EPSG or someone else components with their own. Note also that we don't apply filtering + * on MathTransform WKT neither for more reliable debugging. + */ + final boolean filter = WKTUtilities.isEPSG(parameters.getDescriptor(), false) && // NOT method.getName() + Constants.EPSG.equalsIgnoreCase(Citations.getCodeSpace(formatter.getNameAuthority())); formatter.newLine(); formatter.indent(+1); for (final GeneralParameterValue param : parameters.values()) { - WKTUtilities.append(param, formatter); + if (!filter || WKTUtilities.isEPSG(param.getDescriptor(), true)) { + WKTUtilities.append(param, formatter); + } } formatter.indent(-1); } diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperationTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperationTest.java index 7c46ad0..9db7789 100644 --- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperationTest.java +++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperationTest.java @@ -43,7 +43,7 @@ import static org.apache.sis.test.TestUtilities.getSingleton; * Tests the {@link DefaultConcatenatedOperation} class. * * @author Martin Desruisseaux (Geomatys) - * @version 0.7 + * @version 0.8 * @since 0.7 * @module */ @@ -114,9 +114,7 @@ public final strictfp class DefaultConcatenatedOperationTest extends XMLTestCase " Axis[“Latitude (B)”, north, Unit[“degree”, 0.017453292519943295]],\n" + " Axis[“Ellipsoidal height (h)”, up, Unit[“metre”, 1]]]],\n" + " CoordinateOperationStep[“Geographic to geocentric”,\n" + - " Method[“Geographic/geocentric conversions”],\n" + - " Parameter[“semi_major”, 6377397.155, Unit[“metre”, 1]],\n" + - " Parameter[“semi_minor”, 6356078.962818189, Unit[“metre”, 1]]],\n" + + " Method[“Geographic/geocentric conversions”]],\n" + // Omit non-EPSG parameters for EPSG method. " CoordinateOperationStep[“Tokyo to JGD2000 (GSI)”,\n" + " Method[“Geocentric translations”],\n" + " Parameter[“X-axis translation”, -146.414],\n" + diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java b/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java index f9f7934..dbbef43 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java +++ b/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java @@ -241,13 +241,16 @@ public final class Logging extends Static { * @param record the record where to set the class and method names. * @return the record to use for logging the record. */ - static Logger inferCaller(Logger logger, String classe, String method, + private static Logger inferCaller(Logger logger, String classe, String method, final StackTraceElement[] trace, final LogRecord record) { for (final StackTraceElement element : trace) { /* * Search for the first stack trace element with a classname matching the expected one. * We compare against the name of the class given in argument if it was non-null. + * + * Note: a previous version also compared logger name with package name. + * This has been removed because those names are only loosely related. */ final String classname = element.getClassName(); if (classe != null) {
