Skip to content

Commit

Permalink
Merge b6684e9 into 81f0ab2
Browse files Browse the repository at this point in the history
  • Loading branch information
breucode committed May 6, 2020
2 parents 81f0ab2 + b6684e9 commit 5d8eb5d
Show file tree
Hide file tree
Showing 18 changed files with 567 additions and 84 deletions.
26 changes: 26 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,32 @@ model.getDate();

We know that the index 47 uses the format `mm:ss.0` by default in the given excel file, thus we're able to override its format with `mm/dd/yyyy hh.mm aa` using the `putNumberFormat` method.

=== Feature 12

Since Poiji 2.8.0, it is possible to read excel properties from xlsx files.
To achieve that, create a class with fields annotated with `@ExcelProperty`.

Example:

[source,java]
----
public class ExcelProperties {
@ExcelProperty
private String title;
@ExcelProperty
private String customProperty;
}
----

The field name corresponds to the name of the property inside the Excel file.
To use a different one than the field name, you can specify a `propertyName` (e.g. `@ExcelProperty(propertyName = "customPropertyName")`)

The list of built-in (e.g. non-custom) properties in an Excel file, which can be read by Poiji can be found in the class `DefaultExcelProperties`.

Poiji can only read Text properties from an Excel file, so you have to use a `String` to read them.
This does not apply to "modified", "lastPrinted" and "created", which are deserialized into a `Date`.

== Try with JShell

Since we have a new pedagogic tool, Java 9 REPL, you can try Poiji in JShell. Clone the repo and follow the steps below. JShell should open up a new jshell session once loading the startup scripts and the specified jars that must be in the classpath. You must first import and create related packages and classes before using Poiji. We are able to use directly Poiji and Employee classes because they are already imported from `jshell/snippets` with `try-with-jshell.sh`.
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
<configuration>
<argLine>${add.opens}</argLine>
<argLine>-Djava.awt.headless=true</argLine>
<argLine>-Duser.language=en -Duser.region=US</argLine>
</configuration>
</plugin>

Expand Down
24 changes: 24 additions & 0 deletions src/main/java/com/poiji/annotation/ExcelProperty.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.poiji.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Indicates, that a field contains an excel property (e.g. author, title, custom properties, ...)
*
* @author breucode
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface ExcelProperty {
/**
* If this value is set, the property will be read from property field with this name instead of your field name.
*
* @return the name of the property field to read from
*/
String propertyName() default "";
}
2 changes: 1 addition & 1 deletion src/main/java/com/poiji/annotation/ExcelUnknownCells.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* This annotations allows you to put every unknown cell (neither mapped by name, nor by index) into a {@code Map<String,String>}
*
* @author Pascal Breuer
* @author breucode
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
Expand Down
123 changes: 115 additions & 8 deletions src/main/java/com/poiji/bind/Poiji.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package com.poiji.bind;

import com.poiji.bind.mapping.PropertyHandler;
import com.poiji.bind.mapping.UnmarshallerHelper;
import com.poiji.exception.IllegalCastException;
import com.poiji.exception.InvalidExcelFileExtension;
import com.poiji.exception.PoijiExcelType;
import com.poiji.exception.PoijiException;
import com.poiji.option.PoijiOptions;
import com.poiji.option.PoijiOptions.PoijiOptionsBuilder;
import com.poiji.util.ExcelFileOpenUtil;
import com.poiji.util.Files;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -40,13 +45,115 @@ public final class Poiji {
private Poiji() {
}

/**
* converts excel properties into an object
*
* @param file excel file ending with .xlsx.
* @param type type of the root object.
* @param <T> type of the root object.
* @return the newly created objects
* @throws PoijiException if an internal exception occurs during the mapping process.
* @throws InvalidExcelFileExtension if the specified excel file extension is invalid.
* @throws IllegalCastException if this Field object is enforcing Java language access control and the underlying field is either inaccessible or final.
* @see Poiji#fromExcelProperties(File, Class, PoijiOptions)
*/
public static <T> T fromExcelProperties(final File file, final Class<T> type) {
return fromExcelProperties(file, type, PoijiOptionsBuilder.settings().build());
}

/**
* converts excel properties into an object
*
* @param inputStream excel file stream
* @param excelType type of the excel file, xlsx only!
* @param type type of the root object.
* @param <T> type of the root object.
* @return the newly created object
* @throws PoijiException if an internal exception occurs during the mapping process.
* @throws InvalidExcelFileExtension if the specified excel file extension is invalid.
* @throws IllegalCastException if this Field object is enforcing Java language access control and the underlying field is either inaccessible or final.
* @see Poiji#fromExcelProperties(InputStream, PoijiExcelType, Class, PoijiOptions)
*/
public static <T> T fromExcelProperties(final InputStream inputStream,
PoijiExcelType excelType,
final Class<T> type) {
return fromExcelProperties(inputStream, excelType, type, PoijiOptionsBuilder.settings().build());
}

/**
* converts excel properties into an object
*
* @param file excel file ending with .xlsx.
* @param type type of the root object.
* @param <T> type of the root object.
* @param options specifies to change the default behaviour of the poiji. In this case, only the password has an effect
* @return the newly created object
* @throws PoijiException if an internal exception occurs during the mapping process.
* @throws InvalidExcelFileExtension if the specified excel file extension is invalid.
* @throws IllegalCastException if this Field object is enforcing Java language access control and the underlying field is either inaccessible or final.
* @see Poiji#fromExcelProperties(File, Class)
*/
public static <T> T fromExcelProperties(final File file, final Class<T> type, final PoijiOptions options) {
String extension = files.getExtension(file.getName());

if (XLSX_EXTENSION.equals(extension)) {
try (OPCPackage open = ExcelFileOpenUtil.openXlsxFile(file, options);
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(open)) {

return PropertyHandler.unmarshal(type, xssfWorkbook.getProperties());

} catch (IOException e) {
throw new PoijiException("Problem occurred while reading data", e);
}
} else if (XLS_EXTENSION.equals(extension)) {
throw new InvalidExcelFileExtension("Reading metadata from (" + extension + "), is not supported");
} else {
throw new InvalidExcelFileExtension("Invalid file extension (" + extension + "), expected .xlsx");
}
}

/**
* converts excel properties into an object
*
* @param inputStream excel file stream
* @param excelType type of the excel file, xlsx only!
* @param type type of the root object.
* @param <T> type of the root object.
* @param options specifies to change the default behaviour of the poiji. In this case, only the password has an effect
* @return the newly created object
* @throws PoijiException if an internal exception occurs during the mapping process.
* @throws InvalidExcelFileExtension if the specified excel file extension is invalid.
* @throws IllegalCastException if this Field object is enforcing Java language access control and the underlying field is either inaccessible or final.
* @see Poiji#fromExcelProperties(InputStream, PoijiExcelType, Class)
*/
public static <T> T fromExcelProperties(final InputStream inputStream,
PoijiExcelType excelType,
final Class<T> type,
PoijiOptions options) {
Objects.requireNonNull(excelType);

if (excelType == PoijiExcelType.XLSX) {
try (OPCPackage open = ExcelFileOpenUtil.openXlsxFile(inputStream, options);
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(open)) {

return PropertyHandler.unmarshal(type, xssfWorkbook.getProperties());

} catch (IOException e) {
throw new PoijiException("Problem occurred while reading data", e);
}
} else {
//Must be PoijiExcelType.XLS in this case
throw new InvalidExcelFileExtension("Reading metadata from (" + excelType + "), is not supported");
}
}

/**
* converts excel rows into a list of objects
*
* @param file excel file ending with .xls or .xlsx.
* @param type type of the root object.
* @param <T> type of the root object.
* @return the newly created a list of objects
* @return the newly created list of objects
* @throws PoijiException if an internal exception occurs during the mapping process.
* @throws InvalidExcelFileExtension if the specified excel file extension is invalid.
* @throws IllegalCastException if this Field object is enforcing Java language access control and the underlying field is either inaccessible or final.
Expand Down Expand Up @@ -84,11 +191,11 @@ public static <T> void fromExcel(final File file, final Class<T> type, final Con
* @param excelType type of the excel file, xls or xlsx
* @param type type of the root object.
* @param <T> type of the root object.
* @return the newly created a list of objects
* @return the newly created list of objects
* @throws PoijiException if an internal exception occurs during the mapping process.
* @throws InvalidExcelFileExtension if the specified excel file extension is invalid.
* @throws IllegalCastException if this Field object is enforcing Java language access control and the underlying field is either inaccessible or final.
* @see Poiji#fromExcel(File, Class, PoijiOptions)
* @see Poiji#fromExcel(InputStream, PoijiExcelType, Class, PoijiOptions)
*/
public static <T> List<T> fromExcel(final InputStream inputStream,
PoijiExcelType excelType,
Expand Down Expand Up @@ -128,7 +235,7 @@ public static <T> void fromExcel(final InputStream inputStream,
* @param type type of the root object.
* @param <T> type of the root object.
* @param options specifies to change the default behaviour of the poiji.
* @return the newly created a list of objects
* @return the newly created list of objects
* @throws PoijiException if an internal exception occurs during the mapping process.
* @throws InvalidExcelFileExtension if the specified excel file extension is invalid.
* @throws IllegalCastException if this Field object is enforcing Java language access control and the underlying field is either inaccessible or final.
Expand Down Expand Up @@ -166,11 +273,11 @@ public static <T> void fromExcel(final File file, final Class<T> type, final Poi
* @param type type of the root object.
* @param <T> type of the root object.
* @param options specifies to change the default behaviour of the poiji.
* @return the newly created a list of objects
* @return the newly created list of objects
* @throws PoijiException if an internal exception occurs during the mapping process.
* @throws InvalidExcelFileExtension if the specified excel file extension is invalid.
* @throws IllegalCastException if this Field object is enforcing Java language access control and the underlying field is either inaccessible or final.
* @see Poiji#fromExcel(File, Class)
* @see Poiji#fromExcel(InputStream, PoijiExcelType, Class)
*/
public static <T> List<T> fromExcel(final InputStream inputStream,
final PoijiExcelType excelType,
Expand Down Expand Up @@ -218,7 +325,7 @@ private static Unmarshaller deserializer(final File file, final PoijiOptions opt
} else if (XLSX_EXTENSION.equals(extension)) {
return UnmarshallerHelper.XSSFInstance(poijiFile, options);
} else {
throw new InvalidExcelFileExtension("Invalid file extension (" + extension + "), excepted .xls or .xlsx");
throw new InvalidExcelFileExtension("Invalid file extension (" + extension + "), expected .xls or .xlsx");
}
}

Expand All @@ -230,7 +337,7 @@ private static Unmarshaller deserializer(final InputStream inputStream, PoijiExc
} else if (excelType == PoijiExcelType.XLSX) {
return UnmarshallerHelper.XSSFInstance(poijiInputStream, options);
} else {
throw new InvalidExcelFileExtension("Invalid file extension (" + excelType + "), excepted .xls or .xlsx");
throw new InvalidExcelFileExtension("Invalid file extension (" + excelType + "), expected .xls or .xlsx");
}
}

Expand Down
23 changes: 7 additions & 16 deletions src/main/java/com/poiji/bind/mapping/PoijiHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ private boolean setValue(String content, Class<? super T> type, int column) {
ExcelRow excelRow = field.getAnnotation(ExcelRow.class);
if (excelRow != null) {
Object o = casting.castValue(field.getType(), valueOf(internalRow), internalRow, column, options);
setFieldData(field, o, instance);
ReflectUtil.setFieldData(field, o, instance);
columnToField.put(-1, field);
}
ExcelCellRange range = field.getAnnotation(ExcelCellRange.class);
Expand All @@ -99,7 +99,7 @@ private boolean setValue(String content, Class<? super T> type, int column) {
ins = getInstance(field);
for (Field f : field.getType().getDeclaredFields()) {
if (setValue(f, column, content, ins)) {
setFieldData(field, ins, instance);
ReflectUtil.setFieldData(field, ins, instance);
columnToField.put(column, f);
columnToSuperClassField.put(column, field);
}
Expand All @@ -119,7 +119,7 @@ private boolean setValue(String content, Class<? super T> type, int column) {
field.setAccessible(true);
if (field.get(instance) == null) {
excelUnknownCellsMap = new HashMap<>();
setFieldData(field, excelUnknownCellsMap, instance);
ReflectUtil.setFieldData(field, excelUnknownCellsMap, instance);
} else {
excelUnknownCellsMap = (Map) field.get(instance);
}
Expand All @@ -133,14 +133,14 @@ private boolean setValue(String content, Class<? super T> type, int column) {
if (columnToField.containsKey(-1)) {
Field field = columnToField.get(-1);
Object o = casting.castValue(field.getType(), valueOf(internalRow), internalRow, column, options);
setFieldData(field, o, instance);
ReflectUtil.setFieldData(field, o, instance);
}
if (columnToField.containsKey(column) && columnToSuperClassField.containsKey(column)) {
Field field = columnToField.get(column);
Object ins;
ins = getInstance(columnToSuperClassField.get(column));
if (setValue(field, column, content, ins)) {
setFieldData(columnToSuperClassField.get(column), ins, instance);
ReflectUtil.setFieldData(columnToSuperClassField.get(column), ins, instance);
return true;
}
return setValue(field, column, content, instance);
Expand All @@ -154,7 +154,7 @@ private boolean setValue(Field field, int column, String content, Object ins) {
Class<?> fieldType = field.getType();
if (column == index.value()) {
Object o = casting.castValue(fieldType, content, internalRow, column, options);
setFieldData(field, o, ins);
ReflectUtil.setFieldData(field, o, ins);
return true;
}
} else {
Expand All @@ -169,23 +169,14 @@ private boolean setValue(Field field, int column, String content, Object ins) {
//Fix both columns mapped to name passing this condition below
if (titleColumn != null && titleColumn == column) {
Object o = casting.castValue(fieldType, content, internalRow, column, options);
setFieldData(field, o, ins);
ReflectUtil.setFieldData(field, o, ins);
return true;
}
}
}
return false;
}

private void setFieldData(Field field, Object o, Object instance) {
try {
field.setAccessible(true);
field.set(instance, o);
} catch (IllegalAccessException e) {
throw new IllegalCastException("Unexpected cast type {" + o + "} of field" + field.getName());
}
}

@Override
public void startRow(int rowNum) {
if (rowNum + 1 > options.skip()) {
Expand Down
Loading

0 comments on commit 5d8eb5d

Please sign in to comment.