Apache POI célula vazia

Estou utilizando o Apache POI para pegar dados de uma planilha Excel, porém uma das colunas em algumas linhas não possui valor (célula vazia).

package com.movie.controller;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.collections4.IteratorUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.movie.model.Movie;

import lombok.Cleanup;

public class PlanilhaController {

	public List<Movie> movieList() throws IOException, InvalidFormatException {
		
		List<Movie> movies = new ArrayList<Movie>();

		@Cleanup FileInputStream file = new FileInputStream("src/main/resources/static/movielist.xlsx");
		
		Workbook workbook = new XSSFWorkbook(file);

		Sheet sheet = workbook.getSheetAt(0);
		
		@SuppressWarnings("unchecked")
		List<Row> rows = (List<Row>) toList(sheet.iterator());
		
		rows.remove(0);
		
		rows.forEach(row -> {
			
			@SuppressWarnings("unchecked")
			List<Cell> cells = (List<Cell>) toList(row.cellIterator());
			
//			Movie movie = Movie.builder()
//					.ano((int) cells.get(0).getNumericCellValue())
//					.titulo(cells.get(1).getStringCellValue())
//					.estudio(cells.get(2).getStringCellValue())
//					.produtores(cells.get(3).getStringCellValue())
//					.vencedor(cells.get(4).getStringCellValue())
//					.build();
//			
//			movies.add(movie);
			System.out.println("Testeee! " + cells.size());
			System.out.print("Célula vencedor: ");
			System.out.println(cells.get(4) == null ? "" : cells.get(4).getStringCellValue());
			
		});

		return movies;
	}

	public List<?> toList(Iterator<?> iterator) {
		return IteratorUtils.toList(iterator);
	}
	
	public void imprimir(List<Movie> movies) {
		movies.forEach(System.out::print);
	}	

}

Exception:

Exception in thread “restartedMain” java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.IndexOutOfBoundsException: Index 4 out of bounds for length 4
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266)
at java.base/java.util.Objects.checkIndex(Objects.java:359)
at java.base/java.util.ArrayList.get(ArrayList.java:427)
at com.movie.controller.PlanilhaController.lambda$0(PlanilhaController.java:54)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at com.movie.controller.PlanilhaController.movieList(PlanilhaController.java:38)
at com.movie.MovieApiApplication.main(MovieApiApplication.java:21)
… 5 more

Na expressão lambda da linha 54 do PlanilhaController você está tentando acessar uma posição que não existe.

Sim, até estava ciente disso… na linha em que a célula está vazia a mesma não é considerada na iteração… então utilizei o “if” (cells.get(4) == null ? “” : cells.get(4).getStringCellValue()) para tratar caso da célula 4 for null então utilizar “” String vazia, porém não adiantou…

Achei um caso parecido aqui no GUJ na qual foi indicada a solução cells.get(4).getStringCellValue().isEmpty(), porém ocorre o mesmo erro…

Tem alguma forma de eu testar se a respectiva coluna a ser iterada existe?

Posta o código completo do método.

package com.movie.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import lombok.Builder;
import lombok.Data;

@Data
@Entity
@Builder
public class Movie {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long ID;

	private Integer ano;
	private String titulo;
	private String estudio;
	private String produtores;
	private String vencedor;

}

package com.movie.controller;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.collections4.IteratorUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.movie.model.Movie;

import lombok.Cleanup;

public class PlanilhaController {

	public List<Movie> movieList() throws IOException, InvalidFormatException {
		
		List<Movie> movies = new ArrayList<Movie>();

		@Cleanup FileInputStream file = new FileInputStream("src/main/resources/static/movielist.xlsx");
		
		Workbook workbook = new XSSFWorkbook(file);

		Sheet sheet = workbook.getSheetAt(0);
		
		@SuppressWarnings("unchecked")
		List<Row> rows = (List<Row>) toList(sheet.iterator());
		
		rows.remove(0);
		
		rows.forEach(row -> {
			
			@SuppressWarnings("unchecked")
			List<Cell> cells = (List<Cell>) toList(row.cellIterator());
			
			Movie movie = Movie.builder()
					.ano((int) cells.get(0).getNumericCellValue())
					.titulo(cells.get(1).getStringCellValue())
					.estudio(cells.get(2).getStringCellValue())
					.produtores(cells.get(3).getStringCellValue())
					.vencedor(cells.size() < 5 ? "" : cells.get(4).getStringCellValue())
					.build();
			
			movies.add(movie);
			
		});

		return movies;
	}

	public List<?> toList(Iterator<?> iterator) {
		return IteratorUtils.toList(iterator);
	}
	
	public void imprimir(List<Movie> movies) {
		movies.forEach(System.out::print);
	}	

}

package com.movie.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.movie.model.Movie;
import com.movie.repository.MovieRepository;

@RestController
@RequestMapping("/movies")
public class MovieController {
	
	@Autowired
	private MovieRepository movieRepository;

	@GetMapping
	public List<Movie> listMovies() {
		return movieRepository.findAll();
	}
	
	public void saveAllMovies(List<Movie> movies) {
		movies.forEach(movie ->{
			
			movieRepository.save(movie);
			System.out.println(movie.getTitulo());
		});
	}
}

package com.movie;

import java.io.IOException;
import java.util.List;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.movie.controller.MovieController;
import com.movie.controller.PlanilhaController;
import com.movie.model.Movie;

@SpringBootApplication
public class MovieApiApplication {
	
	public static void main(String[] args) throws IOException, InvalidFormatException {
		SpringApplication.run(MovieApiApplication.class, args);
		
		PlanilhaController planilhaController = new PlanilhaController();
		MovieController movieController = new MovieController();
		
		movieController.saveAllMovies(planilhaController.movieList());
				
		
	}

}

Estou utilizando um arquivo .CSV ao invés de .XLSX, desta forma não irei mais precisar utilizar a API da Apache POI… estou utilizando a CSVReader que no momento estou conseguindo fazer as tratativas de colunas vazias sem nenhum problema.

De qualquer forma agradeço pela força @staroski!