最近在写一个gradle插件过程中,为Task定义文件复制方法时,发现文件并没有被复制,本来是一个很简单的操作,却出现了如此不解的现象。因编写gradle插件调试不易,所以花了比较多的时间才发现问题,所以谨此记录。
下面一个精简版的Task类:
import java.io.File; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.apache.commons.io.FileUtils; import org.gradle.api.tasks.TaskAction; public class MyTask { private List<Action> actions = new CopyOnWriteArrayList<>(); public void copy(final String source, final String dest) throws Exception { this.actions.add(new Action() { @Override public void execute() throws Exception { FileUtils.copyFile(new File(source), new File(dest)); } }); } public void copyDependencies() { this.actions.add(new Action() { @Override public void execute() throws Exception { File dir = new File("H:\\sourceDir");//测试代码源目录 for(File file : dir.listFiles()) { copy(file.getAbsolutePath(), "H:\\destDir\\"+file.getName()); } } }); } @TaskAction public void execute() throws Exception { for(Action action : this.actions) { action.execute(); } } public static interface Action { void execute() throws Exception; } }
如上代码中,为了统一各个方法调用,调用方法时只是在actions列表中添加一个Action,在真正执行Task时迭代actions,依次执行各个Action。在MyTask的构建脚本中会调用copy与copyDependencies方法。如果List使用的是ArrayList而不是CopyOnWriteArrayList的话,执行过程中将会抛出ConcurrentModificationException异常,因为ArrayList在迭代的过程不允许对其进行修改(增加或移除元素)。但是即使使用了ConcurrentModificationException后也并没有达到预期目的,即进行文件复制。细看代码后发现,虽然CopyOnWriteArrayList支持迭代过程对列表进行修改,但是copyDependencies方法中调用copy方法其本意是为了复用copy方法,而这其实只是向actions列表中添加了一个新的Action而已,并不是在执行Action,所以copyDependencies方法中的“文件复制”功能无效。
明白问题原因为后改进MyTask类为:
import java.io.File; import java.util.List; import java.util.ArrayList; import org.apache.commons.io.FileUtils; import org.gradle.api.tasks.TaskAction; public class MyTask { private List<Action> actions = new ArrayList<>(); public void copy(final String source, final String dest) throws Exception { this.actions.add(new Action() { @Override public void execute() throws Exception { FileUtils.copyFile(new File(source), new File(dest)); } }); } public void copyDependencies() { this.actions.add(new Action() { @Override public void execute() throws Exception { File dir = new File("H:\\sourceDir"); for(File file : dir.listFiles()) { //不再调用copy方法,而是直接进行文件复制,这样就避免了仅向actions列表中添加元素 //列表类型也可以使用ArrayList了 FileUtils.copyFile(file, new File("H:\\destDir\\"+file.getName())); } } }); } @TaskAction public void execute() throws Exception { for(Action action : this.actions) { action.execute(); } } public static interface Action { void execute() throws Exception; } }
时间: 2024-12-18 11:44:40