在gs-uploaded-files Spring Boot示例中将Java 1.8 lambdas转换为Java 1.7

bul*_*ous 3 java lambda spring spring-boot

我正在https://spring.io/ Spring Boot 上进行一些练习.

做示例https://spring.io/guides/gs/uploading-files/,当我使用Java 8时它工作正常,但遗憾的是我在Web服务中包装的代码需要Java 7.我列出了所有的错误代码,有人可以帮助我将lambda转换为1.7兼容代码并替换新库(java.util.stream.Stream和java.util.stream.Collectors).

Application.java

@SpringBootApplication
@EnableConfigurationProperties(StorageProperties.class)
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    CommandLineRunner init(StorageService storageService) {
        return (args) -> {
            storageService.deleteAll();
            storageService.init();
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

return(args) - >错误说"使用source -8或更高版本来启用lambda表达式"

FileUploadController.java

import java.util.stream.Collectors

//..

@GetMapping("/")
public String listUploadedFiles(Model model) throws IOException {

    model.addAttribute("files", storageService
            .loadAll()
            .map(path ->
                    MvcUriComponentsBuilder
                            .fromMethodName(FileUploadController.class, "serveFile", path.getFileName().toString())
                            .build().toString())
            .collect(Collectors.toList()));

    return "uploadForm";
}
Run Code Online (Sandbox Code Playgroud)

包java.util.stream不存在

type loadAll()是错误的

错误说"使用source -8或更高版本来启用lambda表达式"

FileSystemStorageService.java

@Override
public Stream<Path> loadAll() {
    try {
        return Files.walk(this.rootLocation, 1)
                .filter(path -> !path.equals(this.rootLocation))
                .map(path -> this.rootLocation.relativize(path));
    } catch (IOException e) {
        throw new StorageException("Failed to read stored files", e);
    }

}
Run Code Online (Sandbox Code Playgroud)

找不到符号走路

错误说"使用source -8或更高版本来启用lambda表达式"

StorageService.java

import java.util.stream.Stream;

public interface StorageService {

    void init();

    void store(MultipartFile file);

    Stream<Path> loadAll();

    Path load(String filename);

    Resource loadAsResource(String filename);

    void deleteAll();

}
Run Code Online (Sandbox Code Playgroud)

包java.util.stream不存在

Ser*_*gGr 6

斗牛,我很抱歉你的赏金,但你真的只有很少的选择.Stream API仅在Java 8中添加,因此在Java 7中不存在.您可以通过手动编写匿名类甚至几乎自动来解决与lambda相关的问题(请参阅Retrolambda).但是使用Stream API,您只有两个选择:

  1. 手动将Backport Stream API转换为Java 7.或者使用其他人尝试在SourceForge上反向移植诸如streamsupport项目(或在GitHub上复制)
  2. 摆脱Stream API并使用较旧的Java 7类.

更新(替换Files.walk)

如果您Files.walk是唯一使用Java-8特定API的地方,则可以相对轻松地将其替换为Java 7 API:

interface PathNameMapper
{
    String mapPath(Path path);
}


List<String> loadAll(PathNameMapper mapper)
{
    try
    {
        List<String> result = new ArrayList<>();

        Files.walkFileTree(rootLocation, EnumSet.noneOf(FileVisitOption.class), 1, new SimpleFileVisitor<Path>()
        {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
            {
                if (!rootLocation.equals(file))
                {
                    result.add(mapper.mapPath(rootLocation.relativize(file)));
                }
                return FileVisitResult.CONTINUE;
            }
        });


        return result;
    }
    catch (IOException e)
    {
        throw new StorageException("Failed to read stored files", e);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你listUploadedFiles会变得像

@GetMapping ("/")
public String listUploadedFiles(Model model) throws IOException
{

    model.addAttribute("files", storageService
            .loadAll(new PathNameMapper()
            {
                @Override
                public String mapPath(Path path)
                {
                    return MvcUriComponentsBuilder
                            .fromMethodName(FileUploadController.class, "serveFile", path.getFileName().toString())
                            .build().toString();
                }
            }));

    return "uploadForm";
}
Run Code Online (Sandbox Code Playgroud)

更新2(labmda - >匿名类转换)

仅仅为了完整性,一个如何手动将lambda转换为匿名类的示例:

@Bean
CommandLineRunner init(StorageService storageService)
{
    return new CommandLineRunner()
    {
        @Override
        public void run(String... args) throws Exception
        {
            storageService.deleteAll();
            storageService.init();              
        }
    };
}
Run Code Online (Sandbox Code Playgroud)


use*_*814 6

您可以将以下方法更新为Java 7变体.所有的测试用例都在通过.

Application.java

@SpringBootApplication
@EnableConfigurationProperties(StorageProperties.class)
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    CommandLineRunner init(StorageService storageService) {
        return new CommandLineRunner() {
          @Override
           public void run(String... args) throws Exception {
            storageService.deleteAll();
            storageService.init();
           }
       };
    }
}
Run Code Online (Sandbox Code Playgroud)

FileUploadController.java

@GetMapping("/")
    public String listUploadedFiles(Model model) throws IOException {
        List<Path> paths = storageService.loadAll();
        List<String> sPaths = new ArrayList<>(paths.size());
        for (Path path : paths) {
            sPaths.add(MvcUriComponentsBuilder
                        .fromMethodName(FileUploadController.class, "serveFile", path.getFileName().toString())
                        .build().toString());
        }
        model.addAttribute("files", sPaths);
        return "uploadForm";
    }
Run Code Online (Sandbox Code Playgroud)

更新了DirectoryStream用于简单列出所有文件的方法实现.

FileSystemStorageService.java

@Override
public List<Path> loadAll() {
   List<Path> rPaths = new ArrayList<>();
   try (DirectoryStream<Path> stream = Files.newDirectoryStream(this.rootLocation)) {
       for (Path entry: stream) {
             rPaths.add(rootLocation.relativize(entry));
        }
    } catch (IOException e) {
       throw new StorageException("Failed to read stored files", e);
    }
    return rPaths;
}
Run Code Online (Sandbox Code Playgroud)

StorageService.java

public interface StorageService {

    void init();

    void store(MultipartFile file);

    List<Path> loadAll();

    Path load(String filename);

    Resource loadAsResource(String filename);

    void deleteAll();

}
Run Code Online (Sandbox Code Playgroud)

FileUploadTests

 @Test
    public void shouldListAllFiles() throws Exception {
        given(this.storageService.loadAll())
                .willReturn(Arrays.asList(Paths.get("first.txt"), Paths.get("second.txt")));

        this.mvc.perform(get("/"))
                .andExpect(status().isOk())
                .andExpect(model().attribute("files",
                        Matchers.contains("http://localhost/files/first.txt", "http://localhost/files/second.txt")));
    }
Run Code Online (Sandbox Code Playgroud)

FileSystemStorageServiceTest

@RunWith(SpringRunner.class)
@SpringBootTest
public class FileSystemStorageServiceTest {

    @Autowired
    private StorageService storageService;

    @Test
    public void loadAll() throws Exception {
        MockMultipartFile multipartFile =
                new MockMultipartFile("file", "test.txt", "text/plain", "Spring Framework".getBytes());
        storageService.store(multipartFile);
        List<Path> paths = storageService.loadAll();
        assertThat(paths.size()).isEqualTo(1);
    }

}
Run Code Online (Sandbox Code Playgroud)

更新TestComparerootLocation设置为FileSystems.getDefault().getPath(".")

@RunWith(SpringRunner.class)
public class TestCompare {

    @Configuration
    @ComponentScan(basePackages = {"hello.storage"})
    @EnableConfigurationProperties(StorageProperties.class)
    static class ContextConfiguration{}

    @Autowired
    private StorageService storageService;

    @Test
    public void loadAllDirectoryStreamVsloadAllWalkFileWithDepth1() throws Exception {
        List<Path> paths1 = storageService.loadAllDirectoryStream();
        List<Path> paths2 = storageService.loadAllWalkFileWithDepth1();
        assertThat(paths1.size()).isEqualTo(paths2.size());

    }

}
Run Code Online (Sandbox Code Playgroud)

我添加了两种方法仅用于测试目的.一个使用DirectoryStream和使用其他 WalkFileTree具有maxDepth为1组他们两人的工作原理相同.

   @Override
    public List<Path> loadAllDirectoryStream() {
        List<Path> rPaths = new ArrayList<>();
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(this.rootLocation)) {
            for (Path entry: stream) {
                //if(!Files.isDirectory(entry))
                    rPaths.add(rootLocation.relativize(entry));
            }
        } catch (IOException e) {
            throw new StorageException("Failed to read stored files", e);
        }
        return rPaths;
    }

    @Override
    public List<Path> loadAllWalkFileWithDepth1() {
        List<Path> rPaths = new ArrayList<>();
        try {
            Files.walkFileTree(rootLocation, EnumSet.noneOf(FileVisitOption.class), 1, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    if (!rootLocation.equals(file)) {
                        rPaths.add(rootLocation.relativize(file));
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
            return rPaths;
        } catch (IOException e) {
            throw new StorageException("Failed to read stored files", e);
        }
    }
Run Code Online (Sandbox Code Playgroud)