0

We are using Google App Engine to publish some flat data from our application in a csv format. Google's DataTable and CsvRenderer from visualization-datasource library made the conversion of our data easy and testing succeeded in the local appengine development server.

Deploying to our appspot instance exposed that App Engine does not like the way IBM's ICU library is Logging:

Google App Engine does not support subclasses of java.util.logging.Logger: com/ibm/icu/impl/ICULogger

The stack trace shows the point of origin:

    Caused by: java.lang.SecurityException: Google App Engine does not support subclasses of     java.util.logging.Logger: com/ibm/icu/impl/ICULogger
at com.google.appengine.runtime.Request.process-0b3cd097cad783e6(Request.java)
at java.lang.ClassLoader.loadClass(ClassLoader.java:360)
at com.ibm.icu.util.TimeZone.<clinit>(TimeZone.java:114)

Line 114 of TimeZone:

/**
 * {@icu} A logger for TimeZone. Will be null if logging is not on by way of system
 * property: "icu4j.debug.logging"
 * @draft ICU 4.4
 * @provisional This API might change or be removed in a future release.
 */
public static ICULogger TimeZoneLogger = ICULogger.getICULogger(TimeZone.class.getName());

I put a breakpoint in Eclipse and ran the unit tests in the debugger and TimeZoneLogger is being assigned null since there is no System property turning on the logging as seen further:

    /**
 * Instantiates a new ICULogger object with logging turned off by default
 * unless the system property "icu4j.debug.logging" is set to "all"
 *
 * @param name to be use by the logger (usually is the class name)
 * @param resourceBundleName name to localize messages (can be null)
 * @return a new ICULogger object
 * @draft ICU 4.4
 * @provisional This API might change or be removed in a future release.
 */
public static ICULogger getICULogger(String name, String resourceBundleName) {
    LOGGER_STATUS flag = checkGlobalLoggingFlag();
    if (flag != LOGGER_STATUS.NULL) {
        ICULogger logger = new ICULogger(name, resourceBundleName);

        /* Add a default handler to logger*/
        logger.addHandler(new ConsoleHandler());

        /* Turn off logging by default unless SYSTEM_PROP_LOGGER property is set to "all" */
        if (flag == LOGGER_STATUS.ON) {
            logger.turnOnLogging();
        } else {
            logger.turnOffLogging();
        }

        return logger;
    }
    return null;
}

I put in some logging statements to see if TimeZoneLogger was being instantiated and it shows it is not.

[INFO] Oct 29, 2013 8:45:39 AM  com.example.SomeClass
[INFO] WARNING: icu4j.debug.logging = null
[INFO] Oct 29, 2013 8:45:39 AM com.example.SomeClass
[INFO] WARNING: Time Zone Logger = null

This shows that it's not the instantiation that App Engine doesn't like, but simply the reference to the class that causes the problem.

At this point all I can think of is to write my own CSV Renderer which is the class using the violating code. The effort would not be significant, but I would prefer to use existing libraries...especially when the library and platform both come from Google.

Any other suggestions?

4

1 回答 1

1

您可以提供自己的类实现来避免此问题。

只需从项目中获取 com.ibm.icu.util.TimeZone.java 文件(它是开源的)。然后把它放到你自己的项目中——保持包名和类名相同。然后,“您的”版本将覆盖 jar 库中的版本,您可以更改它。

如果没有,请检查项目的构建路径顺序。在生产服务器上,类在库之前,所以它也可以工作。

我进行了这些骇人听闻的修改以使其正常工作,但您可能会做出更好的修改:)

〜114行:

public static Object TimeZoneLogger = null; // ICULogger.getICULogger(TimeZone.class.getName());

第 ~780 行:也将其注释掉。

       if (TimeZoneLogger != null && TimeZoneLogger.isLoggingOn()) {
             TimeZoneLogger.warning(
               "\"" +ID + "\" is a bogus id so timezone is falling back to Etc/Unknown(GMT).");
      }
于 2013-10-29T21:07:13.037 回答