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