Home | History | Annotate | Download | only in lang
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 /*
     18  * Copyright (C) 2008 The Android Open Source Project
     19  *
     20  * Licensed under the Apache License, Version 2.0 (the "License");
     21  * you may not use this file except in compliance with the License.
     22  * You may obtain a copy of the License at
     23  *
     24  *      http://www.apache.org/licenses/LICENSE-2.0
     25  *
     26  * Unless required by applicable law or agreed to in writing, software
     27  * distributed under the License is distributed on an "AS IS" BASIS,
     28  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     29  * See the License for the specific language governing permissions and
     30  * limitations under the License.
     31  */
     32 
     33 package java.lang;
     34 
     35 import dalvik.system.VMRuntime;
     36 import dalvik.system.VMStack;
     37 import java.io.Console;
     38 import java.io.FileDescriptor;
     39 import java.io.FileInputStream;
     40 import java.io.FileOutputStream;
     41 import java.io.IOException;
     42 import java.io.InputStream;
     43 import java.io.PrintStream;
     44 import java.nio.channels.Channel;
     45 import java.nio.channels.spi.SelectorProvider;
     46 import java.util.AbstractMap;
     47 import java.util.Collections;
     48 import java.util.HashMap;
     49 import java.util.Map;
     50 import java.util.Properties;
     51 import java.util.Set;
     52 import libcore.icu.ICU;
     53 import libcore.io.Libcore;
     54 import libcore.io.StructUtsname;
     55 import libcore.util.ZoneInfoDB;
     56 
     57 /**
     58  * Provides access to system-related information and resources including
     59  * standard input and output. Enables clients to dynamically load native
     60  * libraries. All methods of this class are accessed in a static way and the
     61  * class itself can not be instantiated.
     62  *
     63  * @see Runtime
     64  */
     65 public final class System {
     66 
     67     /**
     68      * Default input stream.
     69      */
     70     public static final InputStream in;
     71 
     72     /**
     73      * Default output stream.
     74      */
     75     public static final PrintStream out;
     76 
     77     /**
     78      * Default error output stream.
     79      */
     80     public static final PrintStream err;
     81 
     82     private static final String lineSeparator;
     83     private static Properties systemProperties;
     84 
     85     static {
     86         // TODO: all three streams are buffered in Harmony.
     87         err = new PrintStream(new FileOutputStream(FileDescriptor.err));
     88         out = new PrintStream(new FileOutputStream(FileDescriptor.out));
     89         in = new FileInputStream(FileDescriptor.in);
     90         lineSeparator = System.getProperty("line.separator");
     91     }
     92 
     93     /**
     94      * Sets the standard input stream to the given user defined input stream.
     95      *
     96      * @param newIn
     97      *            the user defined input stream to set as the standard input
     98      *            stream.
     99      */
    100     public static void setIn(InputStream newIn) {
    101         setFieldImpl("in", "Ljava/io/InputStream;", newIn);
    102     }
    103 
    104     /**
    105      * Sets the standard output stream to the given user defined output stream.
    106      *
    107      * @param newOut
    108      *            the user defined output stream to set as the standard output
    109      *            stream.
    110      */
    111     public static void setOut(PrintStream newOut) {
    112         setFieldImpl("out", "Ljava/io/PrintStream;", newOut);
    113     }
    114 
    115     /**
    116      * Sets the standard error output stream to the given user defined output
    117      * stream.
    118      *
    119      * @param newErr
    120      *            the user defined output stream to set as the standard error
    121      *            output stream.
    122      */
    123     public static void setErr(PrintStream newErr) {
    124         setFieldImpl("err", "Ljava/io/PrintStream;", newErr);
    125     }
    126 
    127     /**
    128      * Prevents this class from being instantiated.
    129      */
    130     private System() {
    131     }
    132 
    133     /**
    134      * Copies {@code length} elements from the array {@code src},
    135      * starting at offset {@code srcPos}, into the array {@code dst},
    136      * starting at offset {@code dstPos}.
    137      *
    138      * @param src
    139      *            the source array to copy the content.
    140      * @param srcPos
    141      *            the starting index of the content in {@code src}.
    142      * @param dst
    143      *            the destination array to copy the data into.
    144      * @param dstPos
    145      *            the starting index for the copied content in {@code dst}.
    146      * @param length
    147      *            the number of elements to be copied.
    148      */
    149     public static native void arraycopy(Object src, int srcPos, Object dst, int dstPos, int length);
    150 
    151     /**
    152      * Returns the current system time in milliseconds since January 1, 1970
    153      * 00:00:00 UTC. This method shouldn't be used for measuring timeouts or
    154      * other elapsed time measurements, as changing the system time can affect
    155      * the results.
    156      *
    157      * @return the local system time in milliseconds.
    158      */
    159     public static native long currentTimeMillis();
    160 
    161     /**
    162      * Returns the current timestamp of the most precise timer available on the
    163      * local system. This timestamp can only be used to measure an elapsed
    164      * period by comparing it against another timestamp. It cannot be used as a
    165      * very exact system time expression.
    166      *
    167      * @return the current timestamp in nanoseconds.
    168      */
    169     public static native long nanoTime();
    170 
    171     /**
    172      * Causes the VM to stop running and the program to exit. If
    173      * {@link #runFinalizersOnExit(boolean)} has been previously invoked with a
    174      * {@code true} argument, then all objects will be properly
    175      * garbage-collected and finalized first.
    176      *
    177      * @param code
    178      *            the return code.
    179      */
    180     public static void exit(int code) {
    181         Runtime.getRuntime().exit(code);
    182     }
    183 
    184     /**
    185      * Indicates to the VM that it would be a good time to run the
    186      * garbage collector. Note that this is a hint only. There is no guarantee
    187      * that the garbage collector will actually be run.
    188      */
    189     public static void gc() {
    190         Runtime.getRuntime().gc();
    191     }
    192 
    193     /**
    194      * Returns the value of the environment variable with the given name {@code
    195      * var}.
    196      *
    197      * @param name
    198      *            the name of the environment variable.
    199      * @return the value of the specified environment variable or {@code null}
    200      *         if no variable exists with the given name.
    201      */
    202     public static String getenv(String name) {
    203         return getenv(name, null);
    204     }
    205 
    206     private static String getenv(String name, String defaultValue) {
    207         if (name == null) {
    208             throw new NullPointerException("name == null");
    209         }
    210         String value = Libcore.os.getenv(name);
    211         return (value != null) ? value : defaultValue;
    212     }
    213 
    214     /*
    215      * Returns an environment variable. No security checks are performed.
    216      * @param var the name of the environment variable
    217      * @return the value of the specified environment variable
    218      */
    219     private static native String getEnvByName(String name);
    220 
    221     /**
    222      * Returns an unmodifiable map of all available environment variables.
    223      *
    224      * @return the map representing all environment variables.
    225      */
    226     public static Map<String, String> getenv() {
    227         Map<String, String> map = new HashMap<String, String>();
    228         for (String entry : Libcore.os.environ()) {
    229             int index = entry.indexOf('=');
    230             if (index != -1) {
    231                 map.put(entry.substring(0, index), entry.substring(index + 1));
    232             }
    233         }
    234         return new SystemEnvironment(map);
    235     }
    236 
    237     /**
    238      * Returns the inherited channel from the creator of the current virtual
    239      * machine.
    240      *
    241      * @return the inherited {@link Channel} or {@code null} if none exists.
    242      * @throws IOException
    243      *             if an I/O error occurred.
    244      * @see SelectorProvider
    245      * @see SelectorProvider#inheritedChannel()
    246      */
    247     public static Channel inheritedChannel() throws IOException {
    248         return SelectorProvider.provider().inheritedChannel();
    249     }
    250 
    251     /**
    252      * Returns the system properties. Note that this is not a copy, so that
    253      * changes made to the returned Properties object will be reflected in
    254      * subsequent calls to getProperty and getProperties.
    255      *
    256      * @return the system properties.
    257      */
    258     public static Properties getProperties() {
    259         if (systemProperties == null) {
    260             initSystemProperties();
    261         }
    262         return systemProperties;
    263     }
    264 
    265     private static void initSystemProperties() {
    266         VMRuntime runtime = VMRuntime.getRuntime();
    267         Properties p = new Properties();
    268 
    269         String projectUrl = "http://www.android.com/";
    270         String projectName = "The Android Project";
    271 
    272         p.put("java.boot.class.path", runtime.bootClassPath());
    273         p.put("java.class.path", runtime.classPath());
    274 
    275         // None of these four are meaningful on Android, but these keys are guaranteed
    276         // to be present for System.getProperty. For java.class.version, we use the maximum
    277         // class file version that dx currently supports.
    278         p.put("java.class.version", "50.0");
    279         p.put("java.compiler", "");
    280         p.put("java.ext.dirs", "");
    281         p.put("java.version", "0");
    282 
    283         p.put("java.home", getenv("JAVA_HOME", "/system"));
    284 
    285         p.put("java.io.tmpdir", "/tmp");
    286         p.put("java.library.path", getenv("LD_LIBRARY_PATH"));
    287 
    288         p.put("java.specification.name", "Dalvik Core Library");
    289         p.put("java.specification.vendor", projectName);
    290         p.put("java.specification.version", "0.9");
    291 
    292         p.put("java.vendor", projectName);
    293         p.put("java.vendor.url", projectUrl);
    294         p.put("java.vm.name", "Dalvik");
    295         p.put("java.vm.specification.name", "Dalvik Virtual Machine Specification");
    296         p.put("java.vm.specification.vendor", projectName);
    297         p.put("java.vm.specification.version", "0.9");
    298         p.put("java.vm.vendor", projectName);
    299         p.put("java.vm.version", runtime.vmVersion());
    300 
    301         p.put("file.separator", "/");
    302         p.put("line.separator", "\n");
    303         p.put("path.separator", ":");
    304 
    305         p.put("java.runtime.name", "Android Runtime");
    306         p.put("java.runtime.version", "0.9");
    307         p.put("java.vm.vendor.url", projectUrl);
    308 
    309         p.put("file.encoding", "UTF-8");
    310         p.put("user.language", "en");
    311         p.put("user.region", "US");
    312 
    313         p.put("user.home", getenv("HOME", ""));
    314         p.put("user.name", getenv("USER", ""));
    315 
    316         StructUtsname info = Libcore.os.uname();
    317         p.put("os.arch", info.machine);
    318         p.put("os.name", info.sysname);
    319         p.put("os.version", info.release);
    320 
    321         // Undocumented Android-only properties.
    322         p.put("android.icu.library.version", ICU.getIcuVersion());
    323         p.put("android.icu.unicode.version", ICU.getUnicodeVersion());
    324         // TODO: it would be nice to have this but currently it causes circularity.
    325         // p.put("android.tzdata.version", ZoneInfoDB.getVersion());
    326         parsePropertyAssignments(p, specialProperties());
    327 
    328         // Override built-in properties with settings from the command line.
    329         parsePropertyAssignments(p, runtime.properties());
    330 
    331         systemProperties = p;
    332     }
    333 
    334     /**
    335      * Returns an array of "key=value" strings containing information not otherwise
    336      * easily available, such as #defined library versions.
    337      */
    338     private static native String[] specialProperties();
    339 
    340     /**
    341      * Adds each element of 'assignments' to 'p', treating each element as an
    342      * assignment in the form "key=value".
    343      */
    344     private static void parsePropertyAssignments(Properties p, String[] assignments) {
    345         for (String assignment : assignments) {
    346             int split = assignment.indexOf('=');
    347             String key = assignment.substring(0, split);
    348             String value = assignment.substring(split + 1);
    349             p.put(key, value);
    350         }
    351     }
    352 
    353     /**
    354      * Returns the value of a particular system property or {@code null} if no
    355      * such property exists.
    356      *
    357      * <p>The following properties are always provided by the Dalvik VM:
    358      * <p><table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
    359      * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
    360      *     <td><b>Name</b></td>        <td><b>Meaning</b></td>                    <td><b>Example</b></td></tr>
    361      * <tr><td>file.separator</td>     <td>{@link java.io.File#separator}</td>    <td>{@code /}</td></tr>
    362      *
    363      * <tr><td>java.class.path</td>    <td>System class path</td>                 <td>{@code .}</td></tr>
    364      * <tr><td>java.class.version</td> <td>(Not useful on Android)</td>           <td>{@code 50.0}</td></tr>
    365      * <tr><td>java.compiler</td>      <td>(Not useful on Android)</td>           <td>Empty</td></tr>
    366      * <tr><td>java.ext.dirs</td>      <td>(Not useful on Android)</td>           <td>Empty</td></tr>
    367      * <tr><td>java.home</td>          <td>Location of the VM on the file system</td> <td>{@code /system}</td></tr>
    368      * <tr><td>java.io.tmpdir</td>     <td>See {@link java.io.File#createTempFile}</td> <td>{@code /sdcard}</td></tr>
    369      * <tr><td>java.library.path</td>  <td>Search path for JNI libraries</td>     <td>{@code /system/lib}</td></tr>
    370      * <tr><td>java.vendor</td>        <td>Human-readable VM vendor</td>          <td>{@code The Android Project}</td></tr>
    371      * <tr><td>java.vendor.url</td>    <td>URL for VM vendor's web site</td>      <td>{@code http://www.android.com/}</td></tr>
    372      * <tr><td>java.version</td>       <td>(Not useful on Android)</td>           <td>{@code 0}</td></tr>
    373      *
    374      * <tr><td>java.specification.version</td>    <td>VM libraries version</td>        <td>{@code 0.9}</td></tr>
    375      * <tr><td>java.specification.vendor</td>     <td>VM libraries vendor</td>         <td>{@code The Android Project}</td></tr>
    376      * <tr><td>java.specification.name</td>       <td>VM libraries name</td>           <td>{@code Dalvik Core Library}</td></tr>
    377      * <tr><td>java.vm.version</td>               <td>VM implementation version</td>   <td>{@code 1.2.0}</td></tr>
    378      * <tr><td>java.vm.vendor</td>                <td>VM implementation vendor</td>    <td>{@code The Android Project}</td></tr>
    379      * <tr><td>java.vm.name</td>                  <td>VM implementation name</td>      <td>{@code Dalvik}</td></tr>
    380      * <tr><td>java.vm.specification.version</td> <td>VM specification version</td>    <td>{@code 0.9}</td></tr>
    381      * <tr><td>java.vm.specification.vendor</td>  <td>VM specification vendor</td>     <td>{@code The Android Project}</td></tr>
    382      * <tr><td>java.vm.specification.name</td>    <td>VM specification name</td>       <td>{@code Dalvik Virtual Machine Specification}</td></tr>
    383      *
    384      * <tr><td>line.separator</td>     <td>The system line separator</td>         <td>{@code \n}</td></tr>
    385      *
    386      * <tr><td>os.arch</td>            <td>OS architecture</td>                   <td>{@code armv7l}</td></tr>
    387      * <tr><td>os.name</td>            <td>OS (kernel) name</td>                  <td>{@code Linux}</td></tr>
    388      * <tr><td>os.version</td>         <td>OS (kernel) version</td>               <td>{@code 2.6.32.9-g103d848}</td></tr>
    389      *
    390      * <tr><td>path.separator</td>     <td>See {@link java.io.File#pathSeparator}</td> <td>{@code :}</td></tr>
    391      *
    392      * <tr><td>user.dir</td>           <td>Base of non-absolute paths</td>        <td>{@code /}</td></tr>
    393      * <tr><td>user.home</td>          <td>(Not useful on Android)</td>           <td>Empty</td></tr>
    394      * <tr><td>user.name</td>          <td>(Not useful on Android)</td>           <td>Empty</td></tr>
    395      *
    396      * </table>
    397      *
    398      * <p>It is a mistake to try to override any of these. Doing so will have unpredictable results.
    399      *
    400      * @param propertyName
    401      *            the name of the system property to look up.
    402      * @return the value of the specified system property or {@code null} if the
    403      *         property doesn't exist.
    404      */
    405     public static String getProperty(String propertyName) {
    406         return getProperty(propertyName, null);
    407     }
    408 
    409     /**
    410      * Returns the value of a particular system property. The {@code
    411      * defaultValue} will be returned if no such property has been found.
    412      *
    413      * @param prop
    414      *            the name of the system property to look up.
    415      * @param defaultValue
    416      *            the return value if the system property with the given name
    417      *            does not exist.
    418      * @return the value of the specified system property or the {@code
    419      *         defaultValue} if the property does not exist.
    420      */
    421     public static String getProperty(String prop, String defaultValue) {
    422         if (prop.isEmpty()) {
    423             throw new IllegalArgumentException();
    424         }
    425         return getProperties().getProperty(prop, defaultValue);
    426     }
    427 
    428     /**
    429      * Sets the value of a particular system property.
    430      *
    431      * @param prop
    432      *            the name of the system property to be changed.
    433      * @param value
    434      *            the value to associate with the given property {@code prop}.
    435      * @return the old value of the property or {@code null} if the property
    436      *         didn't exist.
    437      */
    438     public static String setProperty(String prop, String value) {
    439         if (prop.isEmpty()) {
    440             throw new IllegalArgumentException();
    441         }
    442         return (String) getProperties().setProperty(prop, value);
    443     }
    444 
    445     /**
    446      * Removes a specific system property.
    447      *
    448      * @param key
    449      *            the name of the system property to be removed.
    450      * @return the property value or {@code null} if the property didn't exist.
    451      * @throws NullPointerException
    452      *             if the argument {@code key} is {@code null}.
    453      * @throws IllegalArgumentException
    454      *             if the argument {@code key} is empty.
    455      */
    456     public static String clearProperty(String key) {
    457         if (key == null) {
    458             throw new NullPointerException();
    459         }
    460         if (key.isEmpty()) {
    461             throw new IllegalArgumentException();
    462         }
    463         return (String) getProperties().remove(key);
    464     }
    465 
    466     /**
    467      * Returns the {@link java.io.Console} associated with this VM, or null.
    468      * Not all VMs will have an associated console. A console is typically only
    469      * available for programs run from the command line.
    470      * @since 1.6
    471      */
    472     public static Console console() {
    473         return Console.getConsole();
    474     }
    475 
    476     /**
    477      * Returns null. Android does not use {@code SecurityManager}. This method
    478      * is only provided for source compatibility.
    479      *
    480      * @return null
    481      */
    482     public static SecurityManager getSecurityManager() {
    483         return null;
    484     }
    485 
    486     /**
    487      * Returns an integer hash code for the parameter. The hash code returned is
    488      * the same one that would be returned by the method {@code
    489      * java.lang.Object.hashCode()}, whether or not the object's class has
    490      * overridden hashCode(). The hash code for {@code null} is {@code 0}.
    491      *
    492      * @param anObject
    493      *            the object to calculate the hash code.
    494      * @return the hash code for the given object.
    495      * @see java.lang.Object#hashCode
    496      */
    497     public static native int identityHashCode(Object anObject);
    498 
    499     /**
    500      * Returns the system's line separator. On Android, this is {@code "\n"}. The value
    501      * comes from the value of the {@code line.separator} system property when the VM
    502      * starts. Later changes to the property will not affect the value returned by this
    503      * method.
    504      * @since 1.7
    505      * @hide 1.7 - fix documentation references to "line.separator" in Formatter.
    506      */
    507     public static String lineSeparator() {
    508         return lineSeparator;
    509     }
    510 
    511     /**
    512      * Loads and links the dynamic library that is identified through the
    513      * specified path. This method is similar to {@link #loadLibrary(String)},
    514      * but it accepts a full path specification whereas {@code loadLibrary} just
    515      * accepts the name of the library to load.
    516      *
    517      * @param pathName
    518      *            the path of the file to be loaded.
    519      */
    520     public static void load(String pathName) {
    521         Runtime.getRuntime().load(pathName, VMStack.getCallingClassLoader());
    522     }
    523 
    524     /**
    525      * Loads and links the library with the specified name. The mapping of the
    526      * specified library name to the full path for loading the library is
    527      * implementation-dependent.
    528      *
    529      * @param libName
    530      *            the name of the library to load.
    531      * @throws UnsatisfiedLinkError
    532      *             if the library could not be loaded.
    533      */
    534     public static void loadLibrary(String libName) {
    535         Runtime.getRuntime().loadLibrary(libName, VMStack.getCallingClassLoader());
    536     }
    537 
    538     /**
    539      * @hide internal use only
    540      */
    541     public static void logE(String message) {
    542         log('E', message, null);
    543     }
    544 
    545     /**
    546      * @hide internal use only
    547      */
    548     public static void logE(String message, Throwable th) {
    549         log('E', message, th);
    550     }
    551 
    552     /**
    553      * @hide internal use only
    554      */
    555     public static void logI(String message) {
    556         log('I', message, null);
    557     }
    558 
    559     /**
    560      * @hide internal use only
    561      */
    562     public static void logI(String message, Throwable th) {
    563         log('I', message, th);
    564     }
    565 
    566     /**
    567      * @hide internal use only
    568      */
    569     public static void logW(String message) {
    570         log('W', message, null);
    571     }
    572 
    573     /**
    574      * @hide internal use only
    575      */
    576     public static void logW(String message, Throwable th) {
    577         log('W', message, th);
    578     }
    579 
    580     private static native void log(char type, String message, Throwable th);
    581 
    582     /**
    583      * Provides a hint to the VM that it would be useful to attempt
    584      * to perform any outstanding object finalization.
    585      */
    586     public static void runFinalization() {
    587         Runtime.getRuntime().runFinalization();
    588     }
    589 
    590     /**
    591      * Ensures that, when the VM is about to exit, all objects are
    592      * finalized. Note that all finalization which occurs when the system is
    593      * exiting is performed after all running threads have been terminated.
    594      *
    595      * @param flag
    596      *            the flag determines if finalization on exit is enabled.
    597      * @deprecated this method is unsafe.
    598      */
    599     @SuppressWarnings("deprecation")
    600     @Deprecated
    601     public static void runFinalizersOnExit(boolean flag) {
    602         Runtime.runFinalizersOnExit(flag);
    603     }
    604 
    605     /**
    606      * Sets all system properties. This does not take a copy; the passed-in object is used
    607      * directly. Passing null causes the VM to reinitialize the properties to how they were
    608      * when the VM was started.
    609      */
    610     public static void setProperties(Properties p) {
    611         systemProperties = p;
    612     }
    613 
    614     /**
    615      * Throws {@code SecurityException}.
    616      *
    617      * <p>Security managers do <i>not</i> provide a secure environment for
    618      * executing untrusted code and are unsupported on Android. Untrusted code
    619      * cannot be safely isolated within a single VM on Android.
    620      *
    621      * @param sm a security manager
    622      * @throws SecurityException always
    623      */
    624     public static void setSecurityManager(SecurityManager sm) {
    625         if (sm != null) {
    626             throw new SecurityException();
    627         }
    628     }
    629 
    630     /**
    631      * Returns the platform specific file name format for the shared library
    632      * named by the argument.
    633      *
    634      * @param userLibName
    635      *            the name of the library to look up.
    636      * @return the platform specific filename for the library.
    637      */
    638     public static native String mapLibraryName(String userLibName);
    639 
    640     /**
    641      * Sets the value of the named static field in the receiver to the passed in
    642      * argument.
    643      *
    644      * @param fieldName
    645      *            the name of the field to set, one of in, out, or err
    646      * @param stream
    647      *            the new value of the field
    648      */
    649     private static native void setFieldImpl(String fieldName, String signature, Object stream);
    650 
    651 
    652     /**
    653      * The unmodifiable environment variables map. System.getenv() specifies
    654      * that this map must throw when passed non-String keys.
    655      */
    656     static class SystemEnvironment extends AbstractMap<String, String> {
    657         private final Map<String, String> map;
    658 
    659         public SystemEnvironment(Map<String, String> map) {
    660             this.map = Collections.unmodifiableMap(map);
    661         }
    662 
    663         @Override public Set<Entry<String, String>> entrySet() {
    664             return map.entrySet();
    665         }
    666 
    667         @Override public String get(Object key) {
    668             return map.get(toNonNullString(key));
    669         }
    670 
    671         @Override public boolean containsKey(Object key) {
    672             return map.containsKey(toNonNullString(key));
    673         }
    674 
    675         @Override public boolean containsValue(Object value) {
    676             return map.containsValue(toNonNullString(value));
    677         }
    678 
    679         private String toNonNullString(Object o) {
    680             if (o == null) {
    681                 throw new NullPointerException();
    682             }
    683             return (String) o;
    684         }
    685     }
    686 }
    687