Skip to content

TreeNode改为Builder模式; #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<optional>true</optional>
</dependency>
<!-- reactor -->
<dependency>
<groupId>io.projectreactor</groupId>
Expand Down
120 changes: 66 additions & 54 deletions src/main/java/top/leafage/common/AbstractTreeNodeService.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
import java.util.stream.Collectors;

/**
* Abstract service for constructing tree nodes from objects.
* Abstract base service for constructing tree structures from objects.
* Provides functionality for creating tree nodes and organizing them
* based on superior-subordinate relationships.
*
* @param <T> the type of object representing a node
* @author wq li
* @param <T> the type of object representing a node in the tree
* @since 0.1.3
*/
public abstract class AbstractTreeNodeService<T> {
Expand All @@ -42,76 +43,60 @@ public abstract class AbstractTreeNodeService<T> {
private static final Logger log = StatusLogger.getLogger();

/**
* Constructs a tree node from an object, optionally expanding additional properties.
* Creates a tree node from the given object, using the provided property names to expand additional data.
* This method extracts ID, name, and superior ID from the object and attaches any expanded properties.
*
* @param t the object representing the node
* @param expand a set of property names to expand on the node
* @return a constructed TreeNode
* @since 0.2.0
* @param t the object representing a node
* @param expand a set of property names to be expanded into the node's additional properties
* @return a fully constructed TreeNode instance
* @throws IllegalArgumentException if the ID property is null
* @since 0.3.0
*/
protected TreeNode node(T t, Set<String> expand) {
protected TreeNode createNode(T t, Set<String> expand) {
Class<?> aClass = t.getClass();
Object id = this.getId(t, aClass.getSuperclass());
if (Objects.isNull(id)) {
throw new IllegalArgumentException("ID cannot be null");
}
Object name = this.getName(t, aClass);
Object superiorId = this.getSuperiorId(t, aClass);

TreeNode treeNode = new TreeNode(Objects.nonNull(id) ? (Long) id : null,
Objects.nonNull(name) ? String.valueOf(name) : null);
treeNode.setSuperior(Objects.nonNull(superiorId) ? (Long) superiorId : null);

this.expand(treeNode, aClass, t, expand);
return treeNode;
return TreeNode.withId((Long) id)
.name(Objects.nonNull(name) ? String.valueOf(name) : null)
.superiorId(Objects.nonNull(superiorId) ? (Long) superiorId : null)
.meta(meta(aClass, t, expand)).build();
}

/**
* Sets the children for tree nodes based on their superior IDs.
* Organizes the tree nodes by assigning children to their respective parents based on the superior ID.
* Returns a list of root nodes (nodes that do not have a superior).
*
* @param treeNodes the list of tree nodes
* @return a list of root nodes (nodes without a superior)
* @param treeNodes the list of all nodes to organize
* @return a list of root nodes, each containing its child nodes
* @since 0.2.0
*/
protected List<TreeNode> children(List<TreeNode> treeNodes) {
Map<Long, List<TreeNode>> nodesMap = treeNodes.stream()
.filter(node -> Objects.nonNull(node.getSuperior()) && node.getSuperior() != 0)
.collect(Collectors.groupingBy(TreeNode::getSuperior));

treeNodes.forEach(node -> node.setChildren(nodesMap.get(node.getId())));
.filter(node -> Objects.nonNull(node.getSuperiorId()) && node.getSuperiorId() != 0)
.collect(Collectors.groupingBy(TreeNode::getSuperiorId));

return treeNodes.stream()
.filter(node -> Objects.isNull(node.getSuperior()) || node.getSuperior() == 0)
.map(treeNode -> TreeNode.withId(treeNode.getId())
.name(treeNode.getName())
.superiorId(treeNode.getSuperiorId())
.children(nodesMap.get(treeNode.getId()))
.meta(treeNode.getMeta())
.build())
.filter(node -> Objects.isNull(node.getSuperiorId()))
.collect(Collectors.toList());
}

/**
* Expands additional properties for a TreeNode.
*
* @param treeNode the TreeNode to expand
* @param clazz the class of the object
* @param t the object representing the node
* @param expand a set of property names to expand
*/
private void expand(TreeNode treeNode, Class<?> clazz, T t, Set<String> expand) {
if (expand != null && !expand.isEmpty()) {
Map<String, Object> expandedData = new HashMap<>(expand.size());
try {
for (String field : expand) {
PropertyDescriptor descriptor = new PropertyDescriptor(field, clazz);
Object value = descriptor.getReadMethod().invoke(t);
expandedData.put(field, value);
}
} catch (IllegalAccessException | InvocationTargetException | IntrospectionException e) {
log.error("Error expanding data for TreeNode.", e);
}
treeNode.setExpand(expandedData);
}
}

/**
* Retrieves the ID from the object.
* Retrieves the ID value from the given object using reflection.
*
* @param obj the object instance
* @param clazz the class of the object
* @return the ID value, or null if an error occurs
* @param clazz the class of the object or its superclass
* @return the ID value, or null if an error occurs during reflection
*/
private Object getId(Object obj, Class<?> clazz) {
try {
Expand All @@ -124,11 +109,11 @@ private Object getId(Object obj, Class<?> clazz) {
}

/**
* Retrieves the name from the object.
* Retrieves the name value from the given object using reflection.
*
* @param t the object instance
* @param clazz the class of the object
* @return the name value, or null if an error occurs
* @return the name value, or null if an error occurs during reflection
*/
private Object getName(T t, Class<?> clazz) {
try {
Expand All @@ -141,11 +126,11 @@ private Object getName(T t, Class<?> clazz) {
}

/**
* Retrieves the superior ID from the object.
* Retrieves the superior ID value from the given object using reflection.
*
* @param t the object instance
* @param clazz the class of the object
* @return the superior ID value, or null if an error occurs
* @return the superior ID value, or null if an error occurs during reflection
*/
private Object getSuperiorId(T t, Class<?> clazz) {
try {
Expand All @@ -156,5 +141,32 @@ private Object getSuperiorId(T t, Class<?> clazz) {
return null;
}
}

/**
* Expands additional properties for the TreeNode by reflecting on the object's class and property names.
*
* @param clazz the class of the object
* @param t the object representing the node
* @param expand a set of property names to expand as additional data
* @return a map containing the expanded properties
* @since 0.3.0
*/
private Map<String, Object> meta(Class<?> clazz, T t, Set<String> expand) {
Map<String, Object> expandedData = Collections.emptyMap();
if (expand != null && !expand.isEmpty()) {
expandedData = new HashMap<>(expand.size());
try {
for (String field : expand) {
PropertyDescriptor descriptor = new PropertyDescriptor(field, clazz);
Object value = descriptor.getReadMethod().invoke(t);
expandedData.put(field, value);
}
} catch (IllegalAccessException | InvocationTargetException | IntrospectionException e) {
log.error("Error expanding data for TreeNode.", e);
}
}
return expandedData;
}
}


Loading
Loading