Skip to content
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fesod.sheet.annotation.write;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
Comment on lines +22 to +25

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

import org.apache.fesod.sheet.write.builder.AbstractExcelWriterParameterBuilder;

/**
* Annotation used for indicating view(s) that the property
* that is defined by field annotated is part of.
* <p>
* An example annotation would be:
* <pre>
* &#064;ExcelView(asTypes = BasicView.class)
* // Or
* &#064;ExcelView(asNames = "BasicView")
* </pre>
* which would specify that field annotated would be included
* when processing (writing) Sheet identified by <code>BasicView.class</code> (or its subclass) or
* <code>"BasicView"</code>.
* If multiple View class or string identifiers are included, the field will be part of all of them.
* </p>
*
* @see AbstractExcelWriterParameterBuilder#groups(Class[])
* @see AbstractExcelWriterParameterBuilder#groups(String[])
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelView {
Comment on lines +47 to +49

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


/**
* View or views that annotated element is part of. Views are identified
* by classes, when a view type is selected, fields annotated with that type
* or any of subtypes are included.
*/
Comment on lines +51 to +55

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Class<?>[] asTypes() default {};

/**
* View or views that annotated element is part of. Views are identified
* by strings.
*/
String[] asNames() default {};
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import org.apache.fesod.sheet.metadata.property.NumberFormatProperty;
import org.apache.fesod.sheet.metadata.property.StyleProperty;
import org.apache.fesod.sheet.write.metadata.holder.WriteHolder;
import org.apache.fesod.sheet.write.view.WriteViewMatcher;

public class ClassUtils {

Expand Down Expand Up @@ -346,23 +347,30 @@ private static FieldCache doDeclaredFields(Class<?> clazz, ConfigurationHolder c

WriteHolder writeHolder = (WriteHolder) configurationHolder;

// ignore field by grouping
WriteViewMatcher writeViewMatcher = writeHolder.writeViewMatcher();
boolean hasViews = (WriteViewMatcher.NOOP != writeViewMatcher);
// ignore field by include*/exclude*
boolean needIgnore = !CollectionUtils.isEmpty(writeHolder.excludeColumnFieldNames())
|| !CollectionUtils.isEmpty(writeHolder.excludeColumnIndexes())
|| !CollectionUtils.isEmpty(writeHolder.includeColumnFieldNames())
|| !CollectionUtils.isEmpty(writeHolder.includeColumnIndexes());
|| !CollectionUtils.isEmpty(writeHolder.includeColumnIndexes())
|| hasViews;

if (!needIgnore) {
return fieldCache;
}
// ignore filed
// ignore field
Map<Integer, FieldWrapper> tempSortedFieldMap = MapUtils.newHashMap();
int index = 0;
for (Map.Entry<Integer, FieldWrapper> entry : sortedFieldMap.entrySet()) {
Integer key = entry.getKey();
FieldWrapper field = entry.getValue();

boolean isGroupsMismatch = hasViews && !writeViewMatcher.matches(field.getField());

// The current field needs to be ignored
if (writeHolder.ignore(field.getFieldName(), entry.getKey())) {
if (isGroupsMismatch || writeHolder.ignore(field.getFieldName(), entry.getKey())) {
ignoreSet.add(field.getFieldName());
indexFieldMap.remove(index);
} else {
Expand Down Expand Up @@ -575,6 +583,7 @@ public static class FieldCacheKey {
private Collection<Integer> excludeColumnIndexes;
private Collection<String> includeColumnFieldNames;
private Collection<Integer> includeColumnIndexes;
private WriteViewMatcher writeViewMatcher;

FieldCacheKey(Class<?> clazz, ConfigurationHolder configurationHolder) {
this.clazz = clazz;
Expand All @@ -584,6 +593,7 @@ public static class FieldCacheKey {
this.excludeColumnIndexes = writeHolder.excludeColumnIndexes();
this.includeColumnFieldNames = writeHolder.includeColumnFieldNames();
this.includeColumnIndexes = writeHolder.includeColumnIndexes();
this.writeViewMatcher = writeHolder.writeViewMatcher();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@

import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.fesod.sheet.enums.HeaderMergeStrategy;
import org.apache.fesod.sheet.metadata.AbstractParameterBuilder;
import org.apache.fesod.sheet.write.handler.WriteHandler;
import org.apache.fesod.sheet.write.metadata.WriteBasicParameter;
import org.apache.fesod.sheet.write.view.ClassBasedViewMatcher;
import org.apache.fesod.sheet.write.view.NameBasedViewMatcher;

/**
* Build ExcelBuilder
Expand Down Expand Up @@ -170,4 +173,34 @@ public T orderByIncludeColumn(Boolean orderByIncludeColumn) {
parameter().setOrderByIncludeColumn(orderByIncludeColumn);
return self();
}

/**
* Only write the fields marked by the following View class identifiers.
*
* @param types Target View class identifiers
* @throws IllegalArgumentException if the types is empty
* @return this
*/
public T groups(Class<?>... types) {
if (ArrayUtils.isEmpty(types)) {
throw new IllegalArgumentException("Types must not be empty");
}
parameter().setWriteViewMatcher(new ClassBasedViewMatcher(types));
return self();
}
Comment on lines +184 to +190

/**
* Only write to the fields marked by the following View string identifiers.
*
* @param names Target View string identifiers
* @throws IllegalArgumentException if the names is empty
* @return this
*/
public T groups(String... names) {
if (ArrayUtils.isEmpty(names)) {
throw new IllegalArgumentException("Names must not be empty");
}
parameter().setWriteViewMatcher(new NameBasedViewMatcher(names));
return self();
}
Comment on lines +199 to +205
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.apache.fesod.sheet.enums.HeaderMergeStrategy;
import org.apache.fesod.sheet.metadata.BasicParameter;
import org.apache.fesod.sheet.write.handler.WriteHandler;
import org.apache.fesod.sheet.write.view.WriteViewMatcher;

/**
* Write basic parameter
Expand Down Expand Up @@ -92,4 +93,9 @@ public class WriteBasicParameter extends BasicParameter {
* Default is {@code false}.
*/
private Boolean orderByIncludeColumn;

/**
* view-based matcher for sheet writing.
*/
private WriteViewMatcher writeViewMatcher;
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import org.apache.fesod.sheet.write.style.SheetFreezePaneStrategy;
import org.apache.fesod.sheet.write.style.column.AbstractHeadColumnWidthStyleStrategy;
import org.apache.fesod.sheet.write.style.row.SimpleRowHeightStyleStrategy;
import org.apache.fesod.sheet.write.view.WriteViewMatcher;

/**
* Write holder configuration
Expand Down Expand Up @@ -136,6 +137,11 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
*/
private List<Converter<?>> customConverterList;

/**
* view-based matcher for sheet writing.
*/
private WriteViewMatcher writeViewMatcher;

/**
* Write handler
*/
Expand Down Expand Up @@ -263,6 +269,16 @@ public AbstractWriteHolder(WriteBasicParameter writeBasicParameter, AbstractWrit
this.includeColumnIndexes = writeBasicParameter.getIncludeColumnIndexes();
}

if (writeBasicParameter.getWriteViewMatcher() == null) {
if (parentAbstractWriteHolder == null) {
this.writeViewMatcher = WriteViewMatcher.NOOP;
} else {
this.writeViewMatcher = parentAbstractWriteHolder.getWriteViewMatcher();
}
} else {
this.writeViewMatcher = writeBasicParameter.getWriteViewMatcher();
}

// Initialization property
this.excelWriteHeadProperty = new ExcelWriteHeadProperty(this, getClazz(), getHead());

Expand Down Expand Up @@ -599,4 +615,9 @@ public Collection<Integer> excludeColumnIndexes() {
public Collection<String> excludeColumnFieldNames() {
return getExcludeColumnFieldNames();
}

@Override
public WriteViewMatcher writeViewMatcher() {
return getWriteViewMatcher();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.apache.fesod.sheet.enums.HeaderMergeStrategy;
import org.apache.fesod.sheet.metadata.ConfigurationHolder;
import org.apache.fesod.sheet.write.property.ExcelWriteHeadProperty;
import org.apache.fesod.sheet.write.view.WriteViewMatcher;

/**
* Get the corresponding Holder
Expand Down Expand Up @@ -115,4 +116,9 @@ public interface WriteHolder extends ConfigurationHolder {
* @return
*/
Collection<String> excludeColumnFieldNames();

/**
* view-based matcher for sheet writing.
*/
WriteViewMatcher writeViewMatcher();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fesod.sheet.write.view;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.fesod.sheet.annotation.write.ExcelView;

/**
* View matcher that resolves view-based on class
* identifiers declared in {@code @ExcelView#asTypes()}.
*/
@EqualsAndHashCode
public class ClassBasedViewMatcher implements WriteViewMatcher {

private final Collection<Class<?>> expectedGroups;

public ClassBasedViewMatcher(Class<?>... expectedGroups) {
this(ArrayUtils.isEmpty(expectedGroups) ? Collections.emptyList() : Arrays.asList(expectedGroups));
}

public ClassBasedViewMatcher(Collection<Class<?>> expectedGroups) {
if (CollectionUtils.isEmpty(expectedGroups)) {
throw new IllegalArgumentException("Type-based view groups must not be empty");
}
this.expectedGroups = Collections.unmodifiableCollection(expectedGroups);
}

@Override
public boolean matches(Field field) {
Class<?>[] fieldGroups = Optional.ofNullable(field.getAnnotation(ExcelView.class))
.map(ExcelView::asTypes)
.orElse(new Class<?>[0]);

if (ArrayUtils.isEmpty(fieldGroups)) {
return false;
}

return Arrays.stream(fieldGroups).anyMatch(fieldGroup -> expectedGroups.stream()
.anyMatch(expectedGroup -> expectedGroup.isAssignableFrom(fieldGroup)));
}
Comment on lines +62 to +64
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fesod.sheet.write.view;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.fesod.sheet.annotation.write.ExcelView;

/**
* View matcher that resolves view-based on string
* identifiers declared in {@code @ExcelView#asNames()}.
*/
@EqualsAndHashCode
public class NameBasedViewMatcher implements WriteViewMatcher {

private final Collection<String> expectedGroups;

public NameBasedViewMatcher(String... expectedGroups) {
this(ArrayUtils.isEmpty(expectedGroups) ? Collections.emptyList() : Arrays.asList(expectedGroups));
}

public NameBasedViewMatcher(Collection<String> expectedGroups) {
if (CollectionUtils.isEmpty(expectedGroups)) {
throw new IllegalArgumentException("Name-based view groups must not be empty");
}
this.expectedGroups = Collections.unmodifiableCollection(expectedGroups);
}

@Override
public boolean matches(Field field) {
String[] fieldGroups = Optional.ofNullable(field.getAnnotation(ExcelView.class))
.map(ExcelView::asNames)
.orElse(new String[0]);

if (ArrayUtils.isEmpty(fieldGroups)) {
return false;
}

return Arrays.stream(fieldGroups).anyMatch(fieldGroup -> expectedGroups.stream()
.anyMatch(expectedGroup -> expectedGroup.equals(fieldGroup)));
}
Comment on lines +62 to +64
}
Loading
Loading