Java 未正确将字符串转换为长对象

Posted

技术标签:

【中文标题】Java 未正确将字符串转换为长对象【英文标题】:Java Not Converting String to Long Object Properly 【发布时间】:2010-09-22 10:06:06 【问题描述】:

我们在 AIX 的 Websphere Application Server 上使用 Spring/Hibernate。在我的 Windows 机器上,该问题不会发生——仅在运行 AIX 时才会发生。当用户使用帐号登录时,如果他们在登录 ID 前加上“0”前缀,则应用程序会拒绝登录。在 DB2 表中,该列是数字类型,将 '090....' 转换为 '90...' 应该没有问题

还有其他人遇到过这样的问题吗?两台机器都有 Java v1.5。

更具体地说,流程是FormView -> LoginValidator -> LoginController

在 LoginValidator 中,login 的值为 null,带有前缀 0。没有 0,该值就是它应该是的值(但同样,这仅在 AIX 环境中——在 2 个 Windows 环境中它很好)。这是对象等于 null 的代码的 sn-p..

public class LoginValidator implements Validator  

    public boolean supports(Class clazz) 
    return Login.class.equals(clazz);
    

    @SuppressWarnings("all")
    public void validate(Object obj, Errors errors) 
        System.out.println("Inside LoginValidator");
        Login login = (Login) obj;
        //null value
        System.out.println("Before conversion in Validator, store id = " 
              + login.getStoreId()); 
    

我还编写了这个简短的 Java 程序,用于从字符串构造 Long,并使用 WebSphere 打包的 java 二进制文件

public class String2Long 
    public static void main(String[] args)
        String a = "09012179";
        String b = "9012179";

        Long _a = new Long(a);
        Long _b = new Long(b);

        System.out.println(a + " => " + _a); //09012179 => 9012179
        System.out.println(b + " => " + _b); //9012179 => 9012179
        System.out.println("_a.equals(_b) " + _a.equals(_b)); //_a.equals(_b) true
    

SOLUTION

【问题讨论】:

会不会是转换成 Long 的代码看到初始的 0 就认为是八进制? 有可能,但是否依赖于平台? Windows机器上不会也出现这个问题吗? 这当然不应该是问题。但是尝试隔离失败的代码,然后自行重现它 - 一个简短的控制台应用程序对此很有用(或者当然是单元测试)。 哦,显示实际执行从 String 到 Long 转换的代码会很方便。 好吧,您可以通过使用 Long.parseLong() 手动转换为 long 来测试它并查看它返回的内容...或手动执行 Long.parseLong(login, 10) 来制作确定它是十进制的。 (其中 login 是您要转换的变量) 【参考方案1】:

嗯,那里发生了很多事情。您确实需要尝试隔离问题 - 找出发送到数据库的内容、Java 看到的内容等。

尝试将它固定在一个简短但完整的程序中,只是显示问题 - 然后你将处于一个更强大的位置来提交错误或修复你的代码。

【讨论】:

它必须在 Spring 构建 Command 对象时有所作为,因为这是它在进入 Validator 之前所做的第一件事。我会在 setter 中做一个 SystemOut,看看那里发生了什么,谢谢。 建议您使用调试器,而不是使用 System.out。即使您不能在 AIX 机器上使用它,您也应该能够在您的开发机器上看到发生了什么转换 - 这应该可以让您隔离错误代码。【参考方案2】:

解决方案

一位同事对 Spring 更新做了一些研究,显然这个错误在 v. 2.5.3 中是正确的:

CustomNumberEditor 将带有前导零的数字视为十进制(删除了不需要的八进制支持,同时保留了十六进制)

我们使用的是 Spring 2.0.5。我们只是用 Spring 2.5.4 替换了这些 jars,它就可以正常工作了!

感谢大家的帮助/协助。将来我们会使用单元测试,但这只是一个 Spring 错误。

【讨论】:

【参考方案3】:

沿着字符串的路径跟踪程序一直到数据库,并对该路径上的每个方法进行单元测试。并且不要只在这里采取最短的路线,使用不同的输入和预期输出进行多个单元测试,以真正了解可能出了什么问题。假设您没有发现任何错误,请在另一台计算机上运行相同的单元测试,您应该能够查明错误。从我的脑海中,我认为这可能与区分大小写有关,但实际上无法确定。

下次,使用 TDD。

【讨论】:

【参考方案4】:

我对 Java 不太了解,但可能会发生这种情况,因为前导“0”,字符串被解释为八进制字符串。

您可以使用 Long.parseLong(a, 10) 来解决这个问题。

【讨论】:

字符串值不应经过任何八进制解释。但是Java无论如何都不会这样做。如果您查看 JDK 代码,new Long(a) 会调用 Long.parseLong(a, 10) 我没有看 JDK 代码,但我注意到标准中这样说。我只是想也许 IBM 可能有一个包含错误的不同实现。显式调用 Long.parseLong(a, 10) 将检验这个假设。

以上是关于Java 未正确将字符串转换为长对象的主要内容,如果未能解决你的问题,请参考以下文章

将十六进制字符串转换为长字符串

C:如何将字符串转换为长整数格式的整数

如何将此十六进制字符串转换为长字符串?

long()

如何在 C# 中将数据从字符串转换为长整数

当列名是字符串时,转换为长并制作频率表,R