1

我需要在 Java 程序中找出远程 Java vm 上的默认文件编码是什么。

有没有办法在远程 vm 上执行 Charset.defaultCharset() 并取回它的值......而不改变在远程 jvm 上运行的程序?

更新:

我试图找出 WebLogic 11g 或 WebLogic 12c 服务器的默认字符集是什么……我没有启动,无法重新启动,并且我没有“权利”在其上部署代码。

我还需要能够从我正在编写的 Java 程序中确定服务器进程的默认字符集。它可能与服务器在同一台机器上执行......或者不是。服务器和我的程序是否会以相同的环境启动是非常值得怀疑的。

我更喜欢一种依赖于很少假设的方法......所以这通常意味着更多的代码......

我可能无法在服务器上执行 Charset.defaultCharset()……所以我不应该说“执行 Charset.defaultCharset()”。对不起那些人。我需要做一些事情来提供与从服务器进程内部执行 Charset.defaultCharset() 一样正确的答案。

4

3 回答 3

3

编辑:写完我的答案后,我发现它至少部分基于一个错误的假设,因为Charset.defaultCharset()不能保证总是返回相同的值。如果在与目标应用程序相同的主机上尝试过以下一些方法,它们应该仍然有效,但我当然建议您也阅读此问题的前两个答案以了解更多背景信息。

特别是强行覆盖file.encoding而不是试图弄清楚它实际上是什么可能更容易。


作为各州的javadoc :defaultCharset

默认字符集在虚拟机启动期间确定,通常取决于底层操作系统的区域设置和字符集。

这意味着它defaultCharset()在 JVM 进程内是只读的,并且将为在同一台机器上启动的所有 JVM 进程返回相同的字符集,除非它们的环境在启动进程之前已明确更改(例如,启动 JVM 并设置的包装器/启动器脚本当前进程及其子进程的不同语言环境)。如果您确定这两个进程以相同的方式启动,那么Charset.defaultCharset()应该返回与Charset您要求的应用程序相同的内容。

以此为背景,按照烦恼/努力的递增顺序:

  1. 如果您的主机运行的是 Unix/Linux,请尝试procfs。例如。/proc/<vmpid>/environ/proc/<vmpid>/cmdline(在 Linux 上)将是很好的起点,因为它们向您展示了该过程是如何在没有混淆包装脚本的情况下实际启动的。此解决方案还可以获得奖励积分,因为它不需要您重新启动/更改应用程序以进行检查。需要注意的事项:变量(Linux 上的语言环境LANG介绍)和影响语言环境的 JVM 命令行参数。其他操作系统也可能具有某种形式的过程检查,您可以使用它来显示此信息。LC_*

  2. 接下来:在特定的主机/JVM 上编译并运行它:

    import java.nio.charset.Charset;
    
    public class DumpCharset {
      public static void main(String[] args) {
        System.out.println(Charset.defaultCharset().displayName());
      }
    }
    

    如前所述,如果进程以相同的方式启动,Charset.defaultCharset()则应返回相同的值(在同一主机上)。为了非常接近,您甚至可以将包含 main 方法的应用程序的 jar 临时替换为包含上述代码的 jar(确保类名匹配)。

  3. 如果这不能为您提供所需的信息(它应该),请尝试启动该进程以使其接受调试器,附加调试器,然后深入了解语言环境,和/或执行类似于上述代码的表达式。

  4. 如果这仍然不能为您提供所需的信息,那么您可以激进并在类加载时使用动态字节码编织。这可以使用基于加载时间编织的现有 AOP 框架(例如AspectJ)或直接使用ASM 4java.lang.instrumentAPI来实现。请注意,使这项工作存在一些陷阱,因此很难判断这在您的情况下是否会相当简单。但期望它比上述方法(更多?)工作。

于 2013-02-17T18:19:03.827 回答
0

我建议您使用System.getProperty( "os.name" )、 System.getProperty( "os.arch" ) 来识别远程架构。

默认字符集也可能有用:

java.nio.Charset cs = java.nio.Charset.defaultCharset();
于 2013-02-17T16:01:55.617 回答
0

这是我最终做的......(大致)

  mbs = conn.getMBeanServerConnection();
  ObjectName runtime = new ObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME);
  TabularDataSupport foo = 
    (TabularDataSupport) mbs.getAttribute(runtime, "SystemProperties");
  for (Iterator<Object> it = foo.values().iterator(); 
                      it.hasNext() && null == retVal; ) {
    CompositeDataSupport cds = (CompositeDataSupport) it.next();
    for (Iterator<?> iter = cds.values().iterator() ; 
                   iter.hasNext() && null == retVal ;) {
      if ("file.encoding".equals(iter.next()) && iter.hasNext())
        retVal = iter.next().toString();
    }

我连接到 MBeanServer,然后通过 SystemProperties 找到连接另一端进程的 file.encoding。

于 2013-03-20T19:38:50.803 回答