jdk/src/share/classes/java/lang/Package.java
changeset 2 90ce3da70b43
child 51 6fe31bc95bbc
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package java.lang;
       
    27 
       
    28 import java.io.InputStream;
       
    29 import java.util.Enumeration;
       
    30 
       
    31 import java.util.StringTokenizer;
       
    32 import java.io.File;
       
    33 import java.io.FileInputStream;
       
    34 import java.io.FileNotFoundException;
       
    35 import java.io.IOException;
       
    36 import java.net.URL;
       
    37 import java.net.MalformedURLException;
       
    38 import java.security.AccessController;
       
    39 import java.security.PrivilegedAction;
       
    40 
       
    41 import java.util.jar.JarInputStream;
       
    42 import java.util.jar.Manifest;
       
    43 import java.util.jar.Attributes;
       
    44 import java.util.jar.Attributes.Name;
       
    45 import java.util.jar.JarException;
       
    46 import java.util.Map;
       
    47 import java.util.HashMap;
       
    48 import java.util.Iterator;
       
    49 
       
    50 import sun.net.www.ParseUtil;
       
    51 
       
    52 import java.lang.annotation.Annotation;
       
    53 
       
    54 /**
       
    55  * {@code Package} objects contain version information
       
    56  * about the implementation and specification of a Java package.
       
    57  * This versioning information is retrieved and made available
       
    58  * by the {@link ClassLoader} instance that
       
    59  * loaded the class(es).  Typically, it is stored in the manifest that is
       
    60  * distributed with the classes.
       
    61  *
       
    62  * <p>The set of classes that make up the package may implement a
       
    63  * particular specification and if so the specification title, version number,
       
    64  * and vendor strings identify that specification.
       
    65  * An application can ask if the package is
       
    66  * compatible with a particular version, see the {@link
       
    67  * #isCompatibleWith isCompatibleWith}
       
    68  * method for details.
       
    69  *
       
    70  * <p>Specification version numbers use a syntax that consists of nonnegative
       
    71  * decimal integers separated by periods ".", for example "2.0" or
       
    72  * "1.2.3.4.5.6.7".  This allows an extensible number to be used to represent
       
    73  * major, minor, micro, etc. versions.  The version specification is described
       
    74  * by the following formal grammar:
       
    75  * <blockquote>
       
    76  * <dl>
       
    77  * <dt><i>SpecificationVersion:
       
    78  * <dd>Digits RefinedVersion<sub>opt</sub></i>
       
    79 
       
    80  * <p><dt><i>RefinedVersion:</i>
       
    81  * <dd>{@code .} <i>Digits</i>
       
    82  * <dd>{@code .} <i>Digits RefinedVersion</i>
       
    83  *
       
    84  * <p><dt><i>Digits:
       
    85  * <dd>Digit
       
    86  * <dd>Digits</i>
       
    87  *
       
    88  * <p><dt><i>Digit:</i>
       
    89  * <dd>any character for which {@link Character#isDigit} returns {@code true},
       
    90  * e.g. 0, 1, 2, ...
       
    91  * </dl>
       
    92  * </blockquote>
       
    93  *
       
    94  * <p>The implementation title, version, and vendor strings identify an
       
    95  * implementation and are made available conveniently to enable accurate
       
    96  * reporting of the packages involved when a problem occurs. The contents
       
    97  * all three implementation strings are vendor specific. The
       
    98  * implementation version strings have no specified syntax and should
       
    99  * only be compared for equality with desired version identifiers.
       
   100  *
       
   101  * <p>Within each {@code ClassLoader} instance all classes from the same
       
   102  * java package have the same Package object.  The static methods allow a package
       
   103  * to be found by name or the set of all packages known to the current class
       
   104  * loader to be found.
       
   105  *
       
   106  * @see ClassLoader#definePackage
       
   107  */
       
   108 public class Package implements java.lang.reflect.AnnotatedElement {
       
   109     /**
       
   110      * Return the name of this package.
       
   111      *
       
   112      * @return  The fully-qualified name of this package as defined in the
       
   113      *          <em>Java Language Specification, Third Edition</em>
       
   114      *          <a href="http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.5.3">
       
   115      *          &sect;6.5.3</a>, for example, {@code java.lang}
       
   116      */
       
   117     public String getName() {
       
   118         return pkgName;
       
   119     }
       
   120 
       
   121 
       
   122     /**
       
   123      * Return the title of the specification that this package implements.
       
   124      * @return the specification title, null is returned if it is not known.
       
   125      */
       
   126     public String getSpecificationTitle() {
       
   127         return specTitle;
       
   128     }
       
   129 
       
   130     /**
       
   131      * Returns the version number of the specification
       
   132      * that this package implements.
       
   133      * This version string must be a sequence of nonnegative decimal
       
   134      * integers separated by "."'s and may have leading zeros.
       
   135      * When version strings are compared the most significant
       
   136      * numbers are compared.
       
   137      * @return the specification version, null is returned if it is not known.
       
   138      */
       
   139     public String getSpecificationVersion() {
       
   140         return specVersion;
       
   141     }
       
   142 
       
   143     /**
       
   144      * Return the name of the organization, vendor,
       
   145      * or company that owns and maintains the specification
       
   146      * of the classes that implement this package.
       
   147      * @return the specification vendor, null is returned if it is not known.
       
   148      */
       
   149     public String getSpecificationVendor() {
       
   150         return specVendor;
       
   151     }
       
   152 
       
   153     /**
       
   154      * Return the title of this package.
       
   155      * @return the title of the implementation, null is returned if it is not known.
       
   156      */
       
   157     public String getImplementationTitle() {
       
   158         return implTitle;
       
   159     }
       
   160 
       
   161     /**
       
   162      * Return the version of this implementation. It consists of any string
       
   163      * assigned by the vendor of this implementation and does
       
   164      * not have any particular syntax specified or expected by the Java
       
   165      * runtime. It may be compared for equality with other
       
   166      * package version strings used for this implementation
       
   167      * by this vendor for this package.
       
   168      * @return the version of the implementation, null is returned if it is not known.
       
   169      */
       
   170     public String getImplementationVersion() {
       
   171         return implVersion;
       
   172     }
       
   173 
       
   174     /**
       
   175      * Returns the name of the organization,
       
   176      * vendor or company that provided this implementation.
       
   177      * @return the vendor that implemented this package..
       
   178      */
       
   179     public String getImplementationVendor() {
       
   180         return implVendor;
       
   181     }
       
   182 
       
   183     /**
       
   184      * Returns true if this package is sealed.
       
   185      *
       
   186      * @return true if the package is sealed, false otherwise
       
   187      */
       
   188     public boolean isSealed() {
       
   189         return sealBase != null;
       
   190     }
       
   191 
       
   192     /**
       
   193      * Returns true if this package is sealed with respect to the specified
       
   194      * code source url.
       
   195      *
       
   196      * @param url the code source url
       
   197      * @return true if this package is sealed with respect to url
       
   198      */
       
   199     public boolean isSealed(URL url) {
       
   200         return url.equals(sealBase);
       
   201     }
       
   202 
       
   203     /**
       
   204      * Compare this package's specification version with a
       
   205      * desired version. It returns true if
       
   206      * this packages specification version number is greater than or equal
       
   207      * to the desired version number. <p>
       
   208      *
       
   209      * Version numbers are compared by sequentially comparing corresponding
       
   210      * components of the desired and specification strings.
       
   211      * Each component is converted as a decimal integer and the values
       
   212      * compared.
       
   213      * If the specification value is greater than the desired
       
   214      * value true is returned. If the value is less false is returned.
       
   215      * If the values are equal the period is skipped and the next pair of
       
   216      * components is compared.
       
   217      *
       
   218      * @param desired the version string of the desired version.
       
   219      * @return true if this package's version number is greater
       
   220      *          than or equal to the desired version number
       
   221      *
       
   222      * @exception NumberFormatException if the desired or current version
       
   223      *          is not of the correct dotted form.
       
   224      */
       
   225     public boolean isCompatibleWith(String desired)
       
   226         throws NumberFormatException
       
   227     {
       
   228         if (specVersion == null || specVersion.length() < 1) {
       
   229             throw new NumberFormatException("Empty version string");
       
   230         }
       
   231 
       
   232         String [] sa = specVersion.split("\\.", -1);
       
   233         int [] si = new int[sa.length];
       
   234         for (int i = 0; i < sa.length; i++) {
       
   235             si[i] = Integer.parseInt(sa[i]);
       
   236             if (si[i] < 0)
       
   237                 throw NumberFormatException.forInputString("" + si[i]);
       
   238         }
       
   239 
       
   240         String [] da = desired.split("\\.", -1);
       
   241         int [] di = new int[da.length];
       
   242         for (int i = 0; i < da.length; i++) {
       
   243             di[i] = Integer.parseInt(da[i]);
       
   244             if (di[i] < 0)
       
   245                 throw NumberFormatException.forInputString("" + di[i]);
       
   246         }
       
   247 
       
   248         int len = Math.max(di.length, si.length);
       
   249         for (int i = 0; i < len; i++) {
       
   250             int d = (i < di.length ? di[i] : 0);
       
   251             int s = (i < si.length ? si[i] : 0);
       
   252             if (s < d)
       
   253                 return false;
       
   254             if (s > d)
       
   255                 return true;
       
   256         }
       
   257         return true;
       
   258     }
       
   259 
       
   260     /**
       
   261      * Find a package by name in the callers {@code ClassLoader} instance.
       
   262      * The callers {@code ClassLoader} instance is used to find the package
       
   263      * instance corresponding to the named class. If the callers
       
   264      * {@code ClassLoader} instance is null then the set of packages loaded
       
   265      * by the system {@code ClassLoader} instance is searched to find the
       
   266      * named package. <p>
       
   267      *
       
   268      * Packages have attributes for versions and specifications only if the class
       
   269      * loader created the package instance with the appropriate attributes. Typically,
       
   270      * those attributes are defined in the manifests that accompany the classes.
       
   271      *
       
   272      * @param name a package name, for example, java.lang.
       
   273      * @return the package of the requested name. It may be null if no package
       
   274      *          information is available from the archive or codebase.
       
   275      */
       
   276     public static Package getPackage(String name) {
       
   277         ClassLoader l = ClassLoader.getCallerClassLoader();
       
   278         if (l != null) {
       
   279             return l.getPackage(name);
       
   280         } else {
       
   281             return getSystemPackage(name);
       
   282         }
       
   283     }
       
   284 
       
   285     /**
       
   286      * Get all the packages currently known for the caller's {@code ClassLoader}
       
   287      * instance.  Those packages correspond to classes loaded via or accessible by
       
   288      * name to that {@code ClassLoader} instance.  If the caller's
       
   289      * {@code ClassLoader} instance is the bootstrap {@code ClassLoader}
       
   290      * instance, which may be represented by {@code null} in some implementations,
       
   291      * only packages corresponding to classes loaded by the bootstrap
       
   292      * {@code ClassLoader} instance will be returned.
       
   293      *
       
   294      * @return a new array of packages known to the callers {@code ClassLoader}
       
   295      * instance.  An zero length array is returned if none are known.
       
   296      */
       
   297     public static Package[] getPackages() {
       
   298         ClassLoader l = ClassLoader.getCallerClassLoader();
       
   299         if (l != null) {
       
   300             return l.getPackages();
       
   301         } else {
       
   302             return getSystemPackages();
       
   303         }
       
   304     }
       
   305 
       
   306     /**
       
   307      * Get the package for the specified class.
       
   308      * The class's class loader is used to find the package instance
       
   309      * corresponding to the specified class. If the class loader
       
   310      * is the bootstrap class loader, which may be represented by
       
   311      * {@code null} in some implementations, then the set of packages
       
   312      * loaded by the bootstrap class loader is searched to find the package.
       
   313      * <p>
       
   314      * Packages have attributes for versions and specifications only
       
   315      * if the class loader created the package
       
   316      * instance with the appropriate attributes. Typically those
       
   317      * attributes are defined in the manifests that accompany
       
   318      * the classes.
       
   319      *
       
   320      * @param class the class to get the package of.
       
   321      * @return the package of the class. It may be null if no package
       
   322      *          information is available from the archive or codebase.  */
       
   323     static Package getPackage(Class c) {
       
   324         String name = c.getName();
       
   325         int i = name.lastIndexOf('.');
       
   326         if (i != -1) {
       
   327             name = name.substring(0, i);
       
   328             ClassLoader cl = c.getClassLoader();
       
   329             if (cl != null) {
       
   330                 return cl.getPackage(name);
       
   331             } else {
       
   332                 return getSystemPackage(name);
       
   333             }
       
   334         } else {
       
   335             return null;
       
   336         }
       
   337     }
       
   338 
       
   339     /**
       
   340      * Return the hash code computed from the package name.
       
   341      * @return the hash code computed from the package name.
       
   342      */
       
   343     public int hashCode(){
       
   344         return pkgName.hashCode();
       
   345     }
       
   346 
       
   347     /**
       
   348      * Returns the string representation of this Package.
       
   349      * Its value is the string "package " and the package name.
       
   350      * If the package title is defined it is appended.
       
   351      * If the package version is defined it is appended.
       
   352      * @return the string representation of the package.
       
   353      */
       
   354     public String toString() {
       
   355         String spec = specTitle;
       
   356         String ver =  specVersion;
       
   357         if (spec != null && spec.length() > 0)
       
   358             spec = ", " + spec;
       
   359         else
       
   360             spec = "";
       
   361         if (ver != null && ver.length() > 0)
       
   362             ver = ", version " + ver;
       
   363         else
       
   364             ver = "";
       
   365         return "package " + pkgName + spec + ver;
       
   366     }
       
   367 
       
   368     private Class<?> getPackageInfo() {
       
   369         if (packageInfo == null) {
       
   370             try {
       
   371                 packageInfo = Class.forName(pkgName + ".package-info", false, loader);
       
   372             } catch (ClassNotFoundException ex) {
       
   373                 // store a proxy for the package info that has no annotations
       
   374                 class PackageInfoProxy {}
       
   375                 packageInfo = PackageInfoProxy.class;
       
   376             }
       
   377         }
       
   378         return packageInfo;
       
   379     }
       
   380 
       
   381     /**
       
   382      * @throws NullPointerException {@inheritDoc}
       
   383      * @since 1.5
       
   384      */
       
   385     public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
       
   386         return getPackageInfo().getAnnotation(annotationClass);
       
   387     }
       
   388 
       
   389     /**
       
   390      * @throws NullPointerException {@inheritDoc}
       
   391      * @since 1.5
       
   392      */
       
   393     public boolean isAnnotationPresent(
       
   394         Class<? extends Annotation> annotationClass) {
       
   395         return getPackageInfo().isAnnotationPresent(annotationClass);
       
   396     }
       
   397 
       
   398     /**
       
   399      * @since 1.5
       
   400      */
       
   401     public Annotation[] getAnnotations() {
       
   402         return getPackageInfo().getAnnotations();
       
   403     }
       
   404 
       
   405     /**
       
   406      * @since 1.5
       
   407      */
       
   408     public Annotation[] getDeclaredAnnotations()  {
       
   409         return getPackageInfo().getDeclaredAnnotations();
       
   410     }
       
   411 
       
   412     /**
       
   413      * Construct a package instance with the specified version
       
   414      * information.
       
   415      * @param pkgName the name of the package
       
   416      * @param spectitle the title of the specification
       
   417      * @param specversion the version of the specification
       
   418      * @param specvendor the organization that maintains the specification
       
   419      * @param impltitle the title of the implementation
       
   420      * @param implversion the version of the implementation
       
   421      * @param implvendor the organization that maintains the implementation
       
   422      * @return a new package for containing the specified information.
       
   423      */
       
   424     Package(String name,
       
   425             String spectitle, String specversion, String specvendor,
       
   426             String impltitle, String implversion, String implvendor,
       
   427             URL sealbase, ClassLoader loader)
       
   428     {
       
   429         pkgName = name;
       
   430         implTitle = impltitle;
       
   431         implVersion = implversion;
       
   432         implVendor = implvendor;
       
   433         specTitle = spectitle;
       
   434         specVersion = specversion;
       
   435         specVendor = specvendor;
       
   436         sealBase = sealbase;
       
   437         this.loader = loader;
       
   438     }
       
   439 
       
   440     /*
       
   441      * Construct a package using the attributes from the specified manifest.
       
   442      *
       
   443      * @param name the package name
       
   444      * @param man the optional manifest for the package
       
   445      * @param url the optional code source url for the package
       
   446      */
       
   447     private Package(String name, Manifest man, URL url, ClassLoader loader) {
       
   448         String path = name.replace('.', '/').concat("/");
       
   449         String sealed = null;
       
   450         String specTitle= null;
       
   451         String specVersion= null;
       
   452         String specVendor= null;
       
   453         String implTitle= null;
       
   454         String implVersion= null;
       
   455         String implVendor= null;
       
   456         URL sealBase= null;
       
   457         Attributes attr = man.getAttributes(path);
       
   458         if (attr != null) {
       
   459             specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
       
   460             specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
       
   461             specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
       
   462             implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
       
   463             implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
       
   464             implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
       
   465             sealed      = attr.getValue(Name.SEALED);
       
   466         }
       
   467         attr = man.getMainAttributes();
       
   468         if (attr != null) {
       
   469             if (specTitle == null) {
       
   470                 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
       
   471             }
       
   472             if (specVersion == null) {
       
   473                 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
       
   474             }
       
   475             if (specVendor == null) {
       
   476                 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
       
   477             }
       
   478             if (implTitle == null) {
       
   479                 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
       
   480             }
       
   481             if (implVersion == null) {
       
   482                 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
       
   483             }
       
   484             if (implVendor == null) {
       
   485                 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
       
   486             }
       
   487             if (sealed == null) {
       
   488                 sealed = attr.getValue(Name.SEALED);
       
   489             }
       
   490         }
       
   491         if ("true".equalsIgnoreCase(sealed)) {
       
   492             sealBase = url;
       
   493         }
       
   494         pkgName = name;
       
   495         this.specTitle = specTitle;
       
   496         this.specVersion = specVersion;
       
   497         this.specVendor = specVendor;
       
   498         this.implTitle = implTitle;
       
   499         this.implVersion = implVersion;
       
   500         this.implVendor = implVendor;
       
   501         this.sealBase = sealBase;
       
   502         this.loader = loader;
       
   503     }
       
   504 
       
   505     /*
       
   506      * Returns the loaded system package for the specified name.
       
   507      */
       
   508     static Package getSystemPackage(String name) {
       
   509         synchronized (pkgs) {
       
   510             Package pkg = (Package)pkgs.get(name);
       
   511             if (pkg == null) {
       
   512                 name = name.replace('.', '/').concat("/");
       
   513                 String fn = getSystemPackage0(name);
       
   514                 if (fn != null) {
       
   515                     pkg = defineSystemPackage(name, fn);
       
   516                 }
       
   517             }
       
   518             return pkg;
       
   519         }
       
   520     }
       
   521 
       
   522     /*
       
   523      * Return an array of loaded system packages.
       
   524      */
       
   525     static Package[] getSystemPackages() {
       
   526         // First, update the system package map with new package names
       
   527         String[] names = getSystemPackages0();
       
   528         synchronized (pkgs) {
       
   529             for (int i = 0; i < names.length; i++) {
       
   530                 defineSystemPackage(names[i], getSystemPackage0(names[i]));
       
   531             }
       
   532             return (Package[])pkgs.values().toArray(new Package[pkgs.size()]);
       
   533         }
       
   534     }
       
   535 
       
   536     private static Package defineSystemPackage(final String iname,
       
   537                                                final String fn)
       
   538     {
       
   539         return (Package) AccessController.doPrivileged(new PrivilegedAction() {
       
   540             public Object run() {
       
   541                 String name = iname;
       
   542                 // Get the cached code source url for the file name
       
   543                 URL url = (URL)urls.get(fn);
       
   544                 if (url == null) {
       
   545                     // URL not found, so create one
       
   546                     File file = new File(fn);
       
   547                     try {
       
   548                         url = ParseUtil.fileToEncodedURL(file);
       
   549                     } catch (MalformedURLException e) {
       
   550                     }
       
   551                     if (url != null) {
       
   552                         urls.put(fn, url);
       
   553                         // If loading a JAR file, then also cache the manifest
       
   554                         if (file.isFile()) {
       
   555                             mans.put(fn, loadManifest(fn));
       
   556                         }
       
   557                     }
       
   558                 }
       
   559                 // Convert to "."-separated package name
       
   560                 name = name.substring(0, name.length() - 1).replace('/', '.');
       
   561                 Package pkg;
       
   562                 Manifest man = (Manifest)mans.get(fn);
       
   563                 if (man != null) {
       
   564                     pkg = new Package(name, man, url, null);
       
   565                 } else {
       
   566                     pkg = new Package(name, null, null, null,
       
   567                                       null, null, null, null, null);
       
   568                 }
       
   569                 pkgs.put(name, pkg);
       
   570                 return pkg;
       
   571             }
       
   572         });
       
   573     }
       
   574 
       
   575     /*
       
   576      * Returns the Manifest for the specified JAR file name.
       
   577      */
       
   578     private static Manifest loadManifest(String fn) {
       
   579         try {
       
   580             FileInputStream fis = new FileInputStream(fn);
       
   581             JarInputStream jis = new JarInputStream(fis, false);
       
   582             Manifest man = jis.getManifest();
       
   583             jis.close();
       
   584             return man;
       
   585         } catch (IOException e) {
       
   586             return null;
       
   587         }
       
   588     }
       
   589 
       
   590     // The map of loaded system packages
       
   591     private static Map pkgs = new HashMap(31);
       
   592 
       
   593     // Maps each directory or zip file name to its corresponding url
       
   594     private static Map urls = new HashMap(10);
       
   595 
       
   596     // Maps each code source url for a jar file to its manifest
       
   597     private static Map mans = new HashMap(10);
       
   598 
       
   599     private static native String getSystemPackage0(String name);
       
   600     private static native String[] getSystemPackages0();
       
   601 
       
   602     /*
       
   603      * Private storage for the package name and attributes.
       
   604      */
       
   605     private final String pkgName;
       
   606     private final String specTitle;
       
   607     private final String specVersion;
       
   608     private final String specVendor;
       
   609     private final String implTitle;
       
   610     private final String implVersion;
       
   611     private final String implVendor;
       
   612     private final URL sealBase;
       
   613     private transient final ClassLoader loader;
       
   614     private transient Class packageInfo;
       
   615 }