代码中如何获得 Java 方法的形式参数名

对于一个 Java 方法 foo(int id, String name); 我们如何能在代码中获得形式参数名 id 和 name 呢?

我们知道通过反射 API Method.getGenericParameterTypes() 可以获得方法的参数类型,但是对于参数名一般就是 arg0, arg1, arg2 ..., 因为 Java 编译时把形式参数名擦除了。所以对完全擦除了形式参数名的字节码应该是没办法了,但我们自己写的类还是有能力去管控的。

对于自己写的类,有两种办法获得形式参数名,分别是

1) Java8 的 -parameters 编译参数,然后用 Java8 新引入的反射 API Parameter

我们先在 Java8 下运行下面的代码 阅读全文 >>

Mac OS X 下吾所倾爱的三个程序员编辑器

作为编程,讲救效率自然是用各种 IDE,诸如 Idea, Eclipse, NetBeans 等。但平时总也离不开一款趁手的纯文本编辑器,如阅读各种语言的代码,简单编辑。我就经常会用 Sublime 这类工具的列编辑功能,奇怪于为何 IDE 们鲜有提供列编辑的特性的。

在 Mac 下的 TextEdit 其实是一款富文本编辑器,且未给编程带来任何便利。根据本人从开始扑向 Mac OS X 平台起到现在,选择过三款程序编辑器,它们分别是 TextMate, Sublime 和 Atom,前两为付费的,最后一个是免费的。

1. TextMate

最早听说很多人喜欢用它写 Ruby 程序,也不知是不是真的. TextMate 以其卓越的 Bundle 们驰行于天下。只是最近几年来它却裹足不前了,似乎失去了前进的方向,一直稳定在 1.5.11 版本上,2.0 已经 alpha 很久了. 其间好像思考过开源,出现在了 GitHub 上 https://github.com/textmate/textmate,少有维护。 阅读全文 >>

Java 和 Scala 调用变参的方式

Java 和 Scala 都支持变参方法, 写在最后的位置上,最基本的调用方式也都是一样的,一个个罗列过去。也可以传入数组参数,因为变参本质上就是一个数组,就是把 ... 开始位置到最后一个参数都收纳到数组中去,所以变参之所以要放在最后的位置上,且一个方法中最多只能有一个变参类型。

这里主要是对比 Scala 对变参方法的调用,基本调用法当然是没问题的,但是在传入数组作为变参的参数列表与 Java 相对时就稍有变化了。

另外提一下,如果想传入 List 作为变参列表,而不是整体作为变参的第一个元素就是调用集合的 toArray() 方法转换成一个数组传入。

下面看 Java 中对变参方法的调用,参数列表和数组

阅读全文 >>

为 Jackson 自定义序列化对象的 JSON 格式

伴随着 Play1, 我们原来使用的 JSON 库是 Gson. 回忆下 Gson 是怎么自定义序列化对象的 JSON 格式,大概是这样子的

GsonBuilder()..registerTypeHierarchyAdapter(Cat.class, new Cat());

然后 Cat 需要实现 JsonSerializer 的 serialize() 方法。

来到了 Play2 中,JSON 库变成了 Jackson,那么 Jackson 该如何为对象自定义 JSON 格式呢?

例如,默认时 Jackson 对 Map 类型输出的是一个 JSON 对象

Map("key1"->"value1", "key2"->"value2")     转换成 JSON 是 {"key1":"value1", "key2":"value2"}

当为适应某些客户端,对于 LinkedHashMap 类型,我们想要输出的是一个有序的 JSON 数组: [{"key1":"value1"},{"key2":"value2"}]

我们就应该自定义某些 Map 的序列化格式,实现方法有两种,addSerializer 和 @JsonSerialize,不管哪种方式都需事先具体化 JsonSerializer 类,并实现它的 serialize 抽象方法

所以我先来实现一个能序列化 Map 的 JsonArrayMapSerializer 类 阅读全文 >>

sbt 中自定义的 Task

sbt, 又是一种自动化构建工具,意为 Simple Build Tool,目前还难副其名,它管理依赖也是用的 Ivy。Scala 相关的项目一般会用它,如 Play2,所以需要来研究下它怎么自定义任务。

sbt 项目可以用 build.sbt 或 project/Build.scala 来定义项目,build.sbt 里写些简单的 settings 表达式,而 Build.scala 就强大,可以写 val, object 和方法定义。而且单个 Build.scala 可以定义多个项目,build.sbt 只用来定义当前项目。build.sbt 和 project/Build.scala 能同时存在,它们的内容会编译到一块。还有一个全局的 build.sbt 文件 ~/.sbt/build.sbt,这里控制所有的项目。

所以我们分别看在 project/Build.scala 和 build.sbt 中如何定义自己的 task

首先看 project/Build.scala,分别由两行完成

val mytask = taskKey[Unit]("This is my customized task")
mytask := { println("Execute customized task")}

完整的一个 project/Build.scala 如下 阅读全文 >>

logback.xml 给变量指定默认值

随着通用日志组件转入 Slf4j,logback 也变成了默认的日志实现,像 log4j 一样,logback.xml 中也可以使用系统属性或环境变量,如 ${catalina.home}。在 log4j.properties 中,如果变量在系统属性和环境变量中找不到的话默认为 "" 空字符串,而到了 logback.xml 中如果某个变量找不到默认就是 "变量名_IS_UNDEFINED" 了,这样就比较奇怪了。

那如何在没有配置 catalina.home 系统属性或环境变量时设置一个默认值呢,例如,没有 catalina.home  时取值为 ".",这时值日志文件的路径就是

./logs/unmi-%d{yyyy-MM-dd}.log

了,也就是生成中当前目录下的 logs 子目录中,这样算是很友好的方式。下面就来分析怎么一步步找到答案的,没耐心或是只求结果的话,直接滚屏到下面就行。

我们的问题是,对于下面那样的 logback.xml 配置: 阅读全文 >>

Mac OS X 下安装使用 Docker

前注: 欢迎进到本页, 本篇写时较早, 而 Mac OS X 下 Docker 早不建议用 boot2docker 了, 取而代之的是 docker-machine. 请点击链接 Mac OS X 下安装使用 Docker (新) 查看最新安装过程与体验

云主机可以选择操作系统镜像快速创建主机,这比虚拟机更便捷了,我们本地也可以这么做了,因为有了 Docker 这个东西。它依赖于 LXC(Linux Container),能从网络上获得配置好的 Linux 镜像,非常容易在隔离的系统中运行自己的应用。也因为它的底层核心是个 LXC,所以在 Mac OS X 下需要在 VirtualBox 中跑一个精小的 LXC(这里是一个 Tiny Core Linux,完全在内存中运行,个头只约 24MB,启动时间小于 5 秒的 boot2docker) 虚拟机,构建在 VirtualBox 中。以后的通信过程就是 docker --> boot2docker --> container,端口或磁盘映射也是遵照这一关系。

理解了上面的关系,开始说说 Docker 安装过程

1. 安装 VirtualBox, 不多讲, 因要在它当中创建一个 boot2docker-vm 虚拟机

2. 安装 boot2docker

brew install boot2docker

你也可以手工安装 阅读全文 >>

Play2 中使用自定义的路由器文件 routes

用过 PlayFramework 的都知道默认的路由器文件是 conf/routes,Play2 可以定义自己的 routes 文件。在默认的 application.conf 中有这么一段注释

# Router
# ~~~~~
# Define the Router object to use for this application.
# This router will be looked up first when the application is starting up,
# so make sure this is the entry point.
# Furthermore, it's assumed your route file is named properly.
# So for an application router like conf/my.application.Router,
# you may need to define a router file my.application.routes.
# Default to Routes in the root package (and conf/routes)
# application.router=my.application.Routes

也就是通过 application.router 可以定义自己的 routes 文件。上面的解释很容易把人搞混,问题在于何处是文件路径,何处是类路径,至少写着的 'conf/my.applicaton.Router 就是在混淆视听。对于上面的解释要明白下面几点 阅读全文 >>

Play1 直接调用 Action 方法,不作 302 跳转

用过 PlayFramework 的同学们应该都知道,Action 方法间的调用是进行的  302 重定向操作。

简单例子说明一下,当基于下面的 r1, r2 路由配置时,如果 Application.f1() 方法中调用了 f2() 方法,实际运作是 f1() 在调用 f2() 时,会先反向出 f2() 方法对应的路由  GET /r2,然后向 /r2 发出的一个 302 跳转.

上面也算是绕个弯形成了对 f2() 方法的调用,这也是非常合理,在 Action 中很容易理解的。

GET     /r1                                                                     Application.f1
GET     /r2                                                                    Application.f2
GET     /r3                                                                    Application.f3

为什么说会反向出 f2() 方法对应的路由,可以反证一下。

例如说在 f1() 中调用了一个 public static void f4() 方法,但是 f4() 并未出现在 routes 配置中,也就是 f4() 没有对应的路由配置,我们将会看到这样一个异常 阅读全文 >>

Mac OS X 下开发 Android 程序时使用 USB 连真机调试

本人很早一篇 Mac OS X 下开发 Android 程序时使用 WiFi ADB 连真机调试,手机端需要连接  WiFi, Root 权限开启 ADB 端口,电脑上执行 adb connect 命令来让 Mac 连接 Android 真机进行调试,其实用不着那么麻烦。

即使是现在新版的 Andorid SDK Manager 里的 Google USB Drive  Not compatible with Mac OS X,并不是说不支持 USB 连接 Android 手机,而是在 Mac 下根本用不着安装这个驱动,有些知名手机直接 USB 连上 Mac 就能被 DDMS 发现。

而我在用一个小米的手机在连机测试,不被 DDMS 识别,解决办法是把小米手机的 Vendor ID 加到文件 ~/.android/adb_usb.ini 中去就行。

Using Hardware Devices 里有很多手机品牌商的 Vendor ID,没有小米的,不急,手机连上 Mac 从设备信息里查相应的 USB 连接端口上能找到。 阅读全文 >>