Skip to content

Commit

Permalink
Merge fd7693d into 779555d
Browse files Browse the repository at this point in the history
  • Loading branch information
ozlerhakan committed May 25, 2020
2 parents 779555d + fd7693d commit 5896671
Show file tree
Hide file tree
Showing 33 changed files with 732 additions and 130 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
114 changes: 106 additions & 8 deletions src/main/java/com/poiji/bind/Poiji.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.poiji.bind;

import com.poiji.bind.mapping.HSSFPropertyFile;
import com.poiji.bind.mapping.HSSFPropertyStream;
import com.poiji.bind.mapping.PoijiPropertyHelper;
import com.poiji.bind.mapping.UnmarshallerHelper;
import com.poiji.exception.IllegalCastException;
import com.poiji.exception.InvalidExcelFileExtension;
Expand Down Expand Up @@ -40,13 +43,108 @@ 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) {
HSSFPropertyFile hssfPropertyFile = deserializerPropertyFile(file, options);
return hssfPropertyFile.unmarshal(type);
}

private static HSSFPropertyFile deserializerPropertyFile(final File file, PoijiOptions options) {
String extension = files.getExtension(file.getName());
if (XLSX_EXTENSION.equals(extension)) {
return PoijiPropertyHelper.createPoijiPropertyFile(file, options);
} 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");
}
}

private static HSSFPropertyStream deserializerPropertyStream(PoijiExcelType excelType, InputStream inputStream, PoijiOptions options) {
if (excelType == PoijiExcelType.XLSX) {
return PoijiPropertyHelper.createPoijiPropertyStream(inputStream, options);
} else {
throw new InvalidExcelFileExtension("Reading metadata from (" + excelType + "), is not supported");
}
}

/**
* 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);
HSSFPropertyStream hssfPropertyStream = deserializerPropertyStream(excelType, inputStream, options);
return hssfPropertyStream.unmarshal(type);
}

/**
* 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 +182,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 +226,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 +264,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 +316,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 +328,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
13 changes: 13 additions & 0 deletions src/main/java/com/poiji/bind/PropertyUnmarshaller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.poiji.bind;

/**
* Created by hakan on 25.05.2020
*/
public interface PropertyUnmarshaller {

<T> T unmarshal(Class<T> type);

<T> T returnFromExcelFile(Class<T> type);

<T> T returnFromEncryptedFile(Class<T> type);
}
15 changes: 15 additions & 0 deletions src/main/java/com/poiji/bind/Unmarshaller.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.poiji.bind;

import com.poiji.annotation.ExcelSheet;
import com.poiji.option.PoijiOptions;

import java.util.Optional;
import java.util.function.Consumer;

/**
Expand All @@ -8,4 +12,15 @@
public interface Unmarshaller {

<T> void unmarshal(Class<T> type, Consumer<? super T> consumer);

default <T> Optional<String> getSheetName(Class<T> type, PoijiOptions options) {
if (type.isAnnotationPresent(ExcelSheet.class)) {
ExcelSheet excelSheet = type.getAnnotation(ExcelSheet.class);
String annotatedSheetName = excelSheet.value();
return Optional.of(annotatedSheetName);
}

String configuredSheetName = options.getSheetName();
return Optional.ofNullable(configuredSheetName);
}
}
66 changes: 66 additions & 0 deletions src/main/java/com/poiji/bind/mapping/HSSFPropertyFile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.poiji.bind.mapping;

import com.poiji.bind.PropertyUnmarshaller;
import com.poiji.exception.PoijiException;
import com.poiji.option.PoijiOptions;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
* Created by hakan on 24.05.2020
*/
public final class HSSFPropertyFile implements PropertyUnmarshaller {

private File file;
private PoijiOptions options;

HSSFPropertyFile(File file, PoijiOptions options) {
this.file = file;
this.options = options;
}

@Override
public <T> T unmarshal(Class<T> type) {
if (options.getPassword() != null) {
return returnFromEncryptedFile(type);
}
return returnFromExcelFile(type);
}

@Override
public <T> T returnFromExcelFile(Class<T> type) {
try (OPCPackage open = OPCPackage.open(file, PackageAccess.READ)) {
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(open);
PropertyHandler propertyHandler = new PropertyHandler();
return propertyHandler.unmarshal(type, xssfWorkbook.getProperties());
} catch (IOException | OpenXML4JException e) {
throw new PoijiException("Problem occurred while reading data", e);
}
}

@Override
public <T> T returnFromEncryptedFile(Class<T> type) {
try (POIFSFileSystem fs = new POIFSFileSystem(file, true)) {
InputStream stream = DocumentFactoryHelper.getDecryptedStream(fs, options.getPassword());
try (OPCPackage open = OPCPackage.open(stream)) {
XSSFWorkbook xssfWorkbook = new XSSFWorkbook(open);
PropertyHandler propertyHandler = new PropertyHandler();
return propertyHandler.unmarshal(type, xssfWorkbook.getProperties());
} catch (IOException | OpenXML4JException e) {
IOUtils.closeQuietly(fs);
throw new PoijiException("Problem occurred while reading data", e);
}
} catch (IOException e) {
throw new PoijiException("Problem occurred while reading data", e);
}
}
}
Loading

0 comments on commit 5896671

Please sign in to comment.