package com.alan344.utils; import com.github.javaparser.JavaParser; import com.github.javaparser.ParseResult; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.ImportDeclaration; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.PackageDeclaration; import com.github.javaparser.ast.body.FieldDeclaration; import com.github.javaparser.ast.body.TypeDeclaration; import com.github.javaparser.ast.body.VariableDeclarator; import lombok.extern.slf4j.Slf4j; import org.mybatis.generator.api.GeneratedXmlFile; import org.mybatis.generator.exception.ShellException; import org.mybatis.generator.internal.DefaultShellCallback; import org.mybatis.generator.internal.DomWriter; import org.w3c.dom.*; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.*; import static org.mybatis.generator.internal.util.messages.Messages.getString; /** * @author AlanSun * @date 2019/8/17 19:43 * merge 现在不用,有点问题 */ @Slf4j public class MyShellCallback extends DefaultShellCallback { private boolean supportMerge; public MyShellCallback(boolean overwrite, boolean supportMerge) { super(overwrite); this.supportMerge = supportMerge; } @Override public boolean isMergeSupported() { return supportMerge; } @Override public String mergeJavaFile(String newFileSource, File existingFile, String[] javadocTags, String fileEncoding) { try { return this.getNewJavaFile(newFileSource, existingFile.getAbsolutePath()); } catch (FileNotFoundException e) { log.error("merge fail", e); } return newFileSource; } private String getNewJavaFile(String newFileSource, String existingFileFullPath) throws FileNotFoundException { JavaParser javaParser = new JavaParser(); ParseResult<CompilationUnit> newCompilationUnitParse = javaParser.parse(newFileSource); CompilationUnit newCompilationUnit; if (newCompilationUnitParse.isSuccessful() && newCompilationUnitParse.getResult().isPresent()) { newCompilationUnit = newCompilationUnitParse.getResult().get(); } else { log.error("解析 newFileSource 失败, {}", newCompilationUnitParse.getProblem(0).toString()); return newFileSource; } ParseResult<CompilationUnit> existingCompilationUnitParse = javaParser.parse(new File(existingFileFullPath)); CompilationUnit existingCompilationUnit; if (existingCompilationUnitParse.isSuccessful() && existingCompilationUnitParse.getResult().isPresent()) { existingCompilationUnit = existingCompilationUnitParse.getResult().get(); } else { log.error("解析 existingFileFullPath 失败, {}", existingCompilationUnitParse.getProblem(0).toString()); return newFileSource; } return mergerFile(newCompilationUnit, existingCompilationUnit); } /** * merge java bean * * @param newCompilationUnit 新的 * @param existingCompilationUnit 旧的 * @return merge 后的 */ private String mergerFile(CompilationUnit newCompilationUnit, CompilationUnit existingCompilationUnit) { Optional<PackageDeclaration> newPackageDeclaration = newCompilationUnit.getPackageDeclaration(); newPackageDeclaration.ifPresent(existingCompilationUnit::setPackageDeclaration); //合并imports NodeList<ImportDeclaration> oldImports = existingCompilationUnit.getImports(); NodeList<ImportDeclaration> newImports = newCompilationUnit.getImports(); oldImports.addAll(newImports); Set<ImportDeclaration> importSet = new HashSet<>(oldImports); existingCompilationUnit.setImports(new NodeList<>(importSet)); //处理类 comment TypeDeclaration<?> newType = newCompilationUnit.getTypes().get(0); TypeDeclaration<?> existType = existingCompilationUnit.getTypes().get(0); newType.getComment().ifPresent(existType::setComment); List<FieldDeclaration> existFields = existType.getFields(); List<FieldDeclaration> newFields = newType.getFields(); //合并fields int size = newFields.size(); for (int i = 0; i < size; i++) { FieldDeclaration existField = newFields.get(0); VariableDeclarator existVar = existField.getVariables().get(0); for (FieldDeclaration newField : existFields) { VariableDeclarator newVar = newField.getVariables().get(0); // 名称相同 if (newVar.getName().equals(existVar.getName())) { // 名称相同 且 类型相同 if (newVar.getTypeAsString().equals(existVar.getTypeAsString())) { newType.getComment().ifPresent(existType::setComment); } else { } } } //合并methods } return existingCompilationUnit.toString(); } @Override public String mergeXmlFile(GeneratedXmlFile gxf, File targetFile) throws ShellException { try { return getMergedSource(new InputSource(new StringReader(gxf.getFormattedContent())), new InputSource(new InputStreamReader(new FileInputStream(targetFile), StandardCharsets.UTF_8)), targetFile.getName()); } catch (IOException | SAXException | ParserConfigurationException e) { throw new ShellException(getString("Warning.13", targetFile.getName()), e); } } private static String getMergedSource(InputSource newFile, InputSource existingFile, String existingFileName) throws IOException, SAXException, ParserConfigurationException, ShellException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setExpandEntityReferences(false); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(new NullEntityResolver()); Document existingDocument = builder.parse(existingFile); existingDocument.setStrictErrorChecking(false); Document newDocument = builder.parse(newFile); DocumentType newDocType = newDocument.getDoctype(); DocumentType existingDocType = existingDocument.getDoctype(); if (!newDocType.getName().equals(existingDocType.getName())) { throw new ShellException(getString("Warning.12", existingFileName)); } Element existingRootElement = existingDocument.getDocumentElement(); Element newRootElement = newDocument.getDocumentElement(); // reconcile the root element attributes - // take all attributes from the new element and add to the existing // element // remove all attributes from the existing root element NamedNodeMap attributes = existingRootElement.getAttributes(); int attributeCount = attributes.getLength(); for (int i = attributeCount - 1; i >= 0; i--) { Node node = attributes.item(i); existingRootElement.removeAttribute(node.getNodeName()); } // add attributes from the new root node to the old root node attributes = newRootElement.getAttributes(); attributeCount = attributes.getLength(); for (int i = 0; i < attributeCount; i++) { Node node = attributes.item(i); existingRootElement.setAttribute(node.getNodeName(), node.getNodeValue()); } // remove the old generated elements and any // white space before the old nodes org.w3c.dom.NodeList existChildren = existingRootElement.getChildNodes(); int existLength = existChildren.getLength(); Map<String, Node> existIdChildMap = new HashMap<>(); for (int i = 0; i < existLength; i++) { Node node = existChildren.item(i); if (!isWhiteSpace(node)) { existIdChildMap.put(node.getAttributes().getNamedItem("id").toString(), node); } } org.w3c.dom.NodeList newChildren = newRootElement.getChildNodes(); int newLength = newChildren.getLength(); Map<String, Node> newIdChildMap = new HashMap<>(); for (int i = 0; i < newLength; i++) { Node node = newChildren.item(i); if (!isWhiteSpace(node)) { newIdChildMap.put(node.getAttributes().getNamedItem("id").toString(), node); } } existIdChildMap.forEach((k, v) -> { if (newIdChildMap.containsKey(k)) { existingRootElement.replaceChild(newIdChildMap.get(k), v); newIdChildMap.remove(k); } }); Text whiteNode = existingDocument.createTextNode("\n "); for (Map.Entry<String, Node> entry : newIdChildMap.entrySet()) { Node node = entry.getValue(); Node whiteNodeClone = whiteNode.cloneNode(true); existingRootElement.appendChild(whiteNodeClone); existingRootElement.appendChild(node); } if (!newIdChildMap.isEmpty()) { Text textNode = existingDocument.createTextNode("\n"); existingRootElement.appendChild(textNode); } // pretty print the result return prettyPrint(existingDocument); } private static String prettyPrint(Document document) throws ShellException { DomWriter dw = new DomWriter(); return dw.toString(document); } private static boolean isWhiteSpace(Node node) { boolean rc = false; if (node != null && node.getNodeType() == Node.TEXT_NODE) { Text tn = (Text) node; if (tn.getData().trim().length() == 0) { rc = true; } } return rc; } private static class NullEntityResolver implements EntityResolver { /** * returns an empty reader. This is done so that the parser doesn't * attempt to read a DTD. We don't need that support for the merge and * it can cause problems on systems that aren't Internet connected. */ @Override public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { StringReader sr = new StringReader(""); return new InputSource(sr); } } }