没有比人更高的山

Java反编译工具Jad详解1

做项目过程中需要反编译一个jar包,于是作了一些学习,记录下来。

Jad(JAva Decompiler)是一个Java的反编译器,可以通过命令行把Java的class文件反编译成源代码。

如果你在使用编写代码的时候遇到找不到源代码的第三方库,而且你又需要看看这个库的具体实现,那么你就需要使用这个东西。而且如果你是使用Eclipse的话,还有一个Eclipse插件JadClipseJadClipse提供一个class文件查看器可以直接打开class文件查看其反编译后的源代码, 太方便了,太方便了!

不过,可惜的是这个开源项目似乎已经关闭了,官方网站已经上不去了,有个叫Tomas Varaneckas的好心人收集了所有的版本提供给大家下载:JAD Java Decompiler Download

而且这个最新的版本也只支持Java 4,不支持Java 5。还有一个叫做JD-Core的工具支持Java 5的新特性,如enum等,而且它提供独立的GUI程序JD-GUI和基于Eclipse的插件JD-Eclipse,也很方便。但是对于JD-Core,作者没有提供下载的链接,他说“Open the sources of JD-Core is not on my roadmap: I spent too many time on this project.”当然后面也有一大篇文章是别人用来骂他的,可以看Add JD-Core to the download list,蛮有意思。

我的项目中需要将第三方库反编译出来,让后对其进行修改,然后再编译,不仅仅是查看,因此只能用命令行的Jad来做。

使用方法:

[1] 反编译一个class文件:jad example.class,会生成example.jad,用文本编辑器打开就是java源代码

[2] 指定生成源代码的后缀名:jad -sjava example.class,生成example.java

[3] 改变生成的源代码的名称,可以先使用-p将反编译后的源代码输出到控制台窗口,然后使用重定向,输出到文件:jad -p example.class > myexample.java

[4] 把源代码文件输出到指定的目录:jad -dnewdir -sjava example.class,在newdir目录下生成example.java

[5] 把packages目录下的class文件全部反编译:jad -sjava packages/*.class

[6] 把packages目录以及子目录下的文件全部反编译:jad -sjava packages/**/*.class,不过你仍然会发现所有的源代码文件被放到了同一个文件中,没有按照class文件的包路径建立起路径

[7] 把packages目录以及子目录下的文件全部反编译并建立和java包一致的文件夹路径,可以使用-r命令:jad -r -sjava packages/**/*.class

[8] 当重复使用命令反编译时,Jad会提示“whether you want to overwrite it or not”,使用-o可以强制覆盖旧文件

[9] 还有其他的参数可以设置生成的源代码的格式,可以输入jad命令查看帮助,这里有个人做了简单的翻译:jad命令总结

[10] 当然,你会发现有些源文件头部有些注释信息,不用找了,jad没有参数可以去掉它,用别的办法吧。

最后,jad不能直接反编译jar包,直接解压了再反编译吧(这个方法很显然,我实在不好意思写出来)。

VN:F [1.7.5_995]
Rating: 0.0/10 (0 votes cast)
VN:F [1.7.5_995]
Rating: 0 (from 2 votes)

Java注释中的@deprecated与源代码中的@Deprecated0

首先,请注意标题,这两个标记有大小写之分,一个是D,一个是d

源代码标记@Deprecated是在JDK1.5中作为内置的annotation引入的,用于表明类(class)、方法(method)、字段(field)已经不再推荐使用,并且在以后的JDK版本中可能将其删除,编译器在默认情况下检测到有此标记的时候会提示警告信息。

Java注释中的@deprecated用于在用Javadoc工具生成文档的时候,标注此类/接口、方法、字段已经被废止。

不过后者还有一个功能就是和源代码标记@Deprecated同样的功能,在JDK1.4版本之后,该功能被@Deprecated所取代。

VN:F [1.7.5_995]
Rating: 0.0/10 (0 votes cast)
VN:F [1.7.5_995]
Rating: -1 (from 1 vote)

Java int型转换中文大写数字表示方法0

之前写过一篇博客,记录的是如何将Java中文大写数字转int型,今天遇到的问题是将Java int型转换成中文大写数字表示。

下面是程序,很容易理解,不过,只支持10000以内的数字转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public static String intToChnNumConverter(int num){
    String resultNumber = null;
    if(num > 10000 || num < 0){
        return "";
    }
    HashMap chnNumbers = new HashMap();
    chnNumbers.put(0, "零");
    chnNumbers.put(1, "一");
    chnNumbers.put(2, "二");
    chnNumbers.put(3, "三");
    chnNumbers.put(4, "四");
    chnNumbers.put(5, "五");
    chnNumbers.put(6, "六");
    chnNumbers.put(7, "七");
    chnNumbers.put(8, "八");
    chnNumbers.put(9, "九");
 
    HashMap unitMap = new HashMap();
    unitMap.put(1, "");
    unitMap.put(10, "十");
    unitMap.put(100, "百");
    unitMap.put(1000, "千");
    int[] unitArray = {1000, 100, 10, 1};
 
    StringBuilder result = new StringBuilder();
    int i = 0;
    while(num > 0){
        int n1 = num / unitArray[i];
        if(n1 > 0){
            result.append(chnNumbers.get(n1)).append(unitMap.get(unitArray[i]));
        }
        if(n1 == 0){
            if(result.lastIndexOf("零") != result.length()-1){
                result.append("零");
            }
        }
        num = num % unitArray[i++];
        if(num == 0){
            break;
        }
    }
    resultNumber = result.toString();
    if(resultNumber.startsWith("零")){
        resultNumber = resultNumber.substring(1);
    }
    if(resultNumber.startsWith("一十")){
        resultNumber = resultNumber.substring(1);
    }
    return resultNumber;
}
VN:F [1.7.5_995]
Rating: 5.5/10 (2 votes cast)
VN:F [1.7.5_995]
Rating: +1 (from 1 vote)

JSP中获取表单中多选列表(Multiple Select)提交的值0

在select标签中添加multiple=”multiple”属性,可以使下拉列表(drop down list)变成多选列表(multiple select list),但是在jsp与servlet中使用获取表单值常用的request.getParameter(”value”)获取到的只是多选列表中的第一个选中值,经过查询资料,原来HttpServletRequest还有一个方法getParameterValues(String key),其返回值为String类型的数组,里面存放的正是多选列表中的选中的值。

也就是说,jsp和servlet中对于表单中的多选控件提交的值都是通过此getParameterValues方法来获取的,比如checkbox list(复选框列表)等,示例代码如下:
<form action=”index.jsp” method=”POST”>
    <select name=”value” multiple=”multiple”>
        <option value=”val1″>Value 1</option>
        <option value=”val2″>Value 2</option>
        <option value=”val3″>Value 3</option>
        <option value=”val4″>Value 4</option>
        <option value=”val5″>Value 5</option>
     </select>
     <input type=”submit” value=”Submit”>
</form>

<%
out.write(”<h3>selected values : <h3>”);
String[] selected = request.getParameterValues(”value”);
if(selected != null){
    for(int i=0; i<selected.length; i++){
        out.write(”<p>” + selected[i] + “<p>”);
    }
}else{
    out.write(”<p> No value selected <p>”);
}
%>

VN:F [1.7.5_995]
Rating: 9.0/10 (3 votes cast)
VN:F [1.7.5_995]
Rating: 0 (from 0 votes)

JSF异常消息机制及应用0

JSF有两种异常消息:

[1] JSF提供的标准异常信息,如标准的验证器和转换器生成的异常信息等

[2] 自定义的异常信息

与消息相关的类是javax.faces.application.FacesMessage,他封装了单一的、本地化的、人类可以理解的消息,除了消息字符串本身外,FacesMessage还有三个属性:severity(严重性),summary(摘要),detail(详细信息)

serverity被定义成FacesMessage的内部类,有四种类型:Info、Warn、Error、Fatal
FacesContext负责维护FacesMessage的两个逻辑集合,一个和组件相关的消息集合、一个不与组件相关的消息集合,定义了如下的和消息相关的方法
public Iterator<FacesMessage> getMessages();
public Iterator<FacesMessage> getMessages(String clientId);
public Iterator<String> getClientIdsWithMessages();//返回有消息绑定的组件id
public void addMessage(String clientId, javax.faces.application.FacesMessage message);//向FacesContext中加入一条FacesMessage
public FacesMessage.Severity getMaximumSeverity();//返回最严重的问题的严重性

FacesMessage的部分源代码如下:


private FacesMessage.Severity _severity;
private String _summary;
private String _detail;

public FacesMessage()
{
    _severity = SEVERITY_INFO;
}

public FacesMessage(String summary)
{
    _summary = summary;
    _severity = SEVERITY_INFO;
}

public FacesMessage(String summary, String detail)
{
    _summary = summary;
    _detail = detail;
    _severity = SEVERITY_INFO;
}

public FacesMessage(FacesMessage.Severity severity, String summary, String detail)
{
    if(severity == null) throw new NullPointerException("severity");
    _severity = severity;
    _summary = summary;
    _detail = detail;
}

和消息相关的两个标签是<h:message>与<h:messages>:
<h:message> 有一个必设属性for,标示消息的绑定组件id;showDetail属性默认为false,showSummary属性默认为true
<h:messages>渲染所有的排队消息,在globalOnly设为true时只渲染哪些没有组件标识符的消息。

我一般会在项目中新建一个MessageUtil类,处理消息,其代码如下:

public class MessageUtil {

    public static void addErrorMessage(FacesContext context, String clientId, String message){
        context.addMessage(clientId, new FacesMessage(message));
    }

    public static void addErrorMessage(FacesContext context, String message) {
        addErrorMessage(context, null, message);
    }

    /**
    * Add a global message, the detail is null and the servity is info by default
    * @param message message summary
    */
    public static void addErrorMessage(String message){
        addErrorMessage(FacesContext.getCurrentInstance(), message);
    }

    /**
    * Binding messages to a ui component
    * @param clientId The ui component id
    * @param message message summary
    */
    public static void addErrorMessage(String clientId, String message){
        addErrorMessage(FacesContext.getCurrentInstance(), clientId, message);
    }
}

如 我们在登录时需要向用户提示“用户名或者密码错误”,可以调用public static void addErrorMessage(String message),然后在页面上使用<h:messages globalOnly=”true”/>来显示这个信息。

VN:F [1.7.5_995]
Rating: 9.0/10 (1 vote cast)
VN:F [1.7.5_995]
Rating: 0 (from 0 votes)


Switch to our mobile site