Browse Source

设置 javassist 为默认编译器

hugui 9 years ago
parent
commit
acfd863b0d

+ 7 - 0
lts-admin/src/main/java/com/github/ltsopensource/admin/support/SystemInitListener.java

@@ -3,6 +3,8 @@ package com.github.ltsopensource.admin.support;
 import com.github.ltsopensource.core.commons.file.FileUtils;
 import com.github.ltsopensource.core.commons.utils.PlatformUtils;
 import com.github.ltsopensource.core.commons.utils.StringUtils;
+import com.github.ltsopensource.core.compiler.AbstractCompiler;
+import com.github.ltsopensource.core.constant.Constants;
 import com.github.ltsopensource.core.json.JSONFactory;
 import com.github.ltsopensource.core.logger.LoggerFactory;
 import com.github.ltsopensource.core.spi.SpiExtensionKey;
@@ -26,6 +28,11 @@ public class SystemInitListener implements ServletContextListener {
         }
         AppConfigurer.load(confPath);
 
+        String compiler = AppConfigurer.getProperty("configs." + Constants.COMPILER);
+        if (StringUtils.isNotEmpty(compiler)) {
+            AbstractCompiler.setCompiler(compiler);
+        }
+
         String jsonAdapter = AppConfigurer.getProperty("configs." + SpiExtensionKey.LTS_JSON);
         if (StringUtils.isNotEmpty(jsonAdapter)) {
             JSONFactory.setJSONAdapter(jsonAdapter);

+ 4 - 0
lts-core/pom.xml

@@ -132,5 +132,9 @@
             <artifactId>mysql-connector-java</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+        </dependency>
     </dependencies>
 </project>

+ 8 - 0
lts-core/src/main/java/com/github/ltsopensource/core/cluster/AbstractJobNode.java

@@ -8,6 +8,8 @@ import com.github.ltsopensource.core.commons.utils.CollectionUtils;
 import com.github.ltsopensource.core.commons.utils.GenericsUtils;
 import com.github.ltsopensource.core.commons.utils.NetUtils;
 import com.github.ltsopensource.core.commons.utils.StringUtils;
+import com.github.ltsopensource.core.compiler.AbstractCompiler;
+import com.github.ltsopensource.core.constant.Constants;
 import com.github.ltsopensource.core.constant.EcTopic;
 import com.github.ltsopensource.core.factory.JobNodeConfigFactory;
 import com.github.ltsopensource.core.factory.NodeFactory;
@@ -140,6 +142,12 @@ public abstract class AbstractJobNode<T extends Node, Context extends AppContext
     }
 
     protected void initConfig() {
+
+        String compiler = config.getParameter(Constants.COMPILER);
+        if (StringUtils.isNotEmpty(compiler)) {
+            AbstractCompiler.setCompiler(compiler);
+        }
+
         appContext.setEventCenter(ServiceLoader.load(EventCenter.class, config));
 
         appContext.setCommandBodyWrapper(new CommandBodyWrapper(config));

+ 27 - 2
lts-core/src/main/java/com/github/ltsopensource/core/compiler/AbstractCompiler.java

@@ -8,9 +8,33 @@ import java.util.regex.Pattern;
 
 /**
  * @author william.liangf
+ * @author Robert HG (254963746@qq.com) on 9/12/15.
  */
 public abstract class AbstractCompiler implements Compiler {
 
+    private static Compiler COMPILER = new JavassistCompiler();
+
+    public static void setCompiler(Compiler compiler) {
+        if (compiler == null) {
+            throw new IllegalArgumentException("compiler should not be null");
+        }
+        AbstractCompiler.COMPILER = compiler;
+    }
+
+    public static Compiler getCompiler() {
+        return AbstractCompiler.COMPILER;
+    }
+
+    public static void setCompiler(String compiler) {
+        if ("javassist".equals(compiler)) {
+            setCompiler(new JavassistCompiler());
+        } else if ("jdk".equals(compiler)) {
+            setCompiler(new JdkCompiler());
+        } else {
+            throw new IllegalArgumentException("compiler[" + compiler +"] error ");
+        }
+    }
+
     private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\s+([$_a-zA-Z][$_a-zA-Z0-9\\.]*);");
 
     private static final Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s+");
@@ -36,18 +60,19 @@ public abstract class AbstractCompiler implements Compiler {
             return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass()));
         } catch (ClassNotFoundException e) {
             if (!code.endsWith("}")) {
-                throw new IllegalStateException("The java code not endsWith \"}\", code: \n" + code + "\n");
+                throw new IllegalStateException("The java code not endsWith \"}\", code: " + code + "");
             }
             try {
                 return doCompile(className, code);
             } catch (RuntimeException t) {
                 throw t;
             } catch (Throwable t) {
-                throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: \n" + code + "\n, stack: " + StringUtils.toString(t));
+                throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: " + code + ", stack: " + StringUtils.toString(t));
             }
         }
     }
 
     protected abstract Class<?> doCompile(String name, String source) throws Throwable;
+
 }
 

+ 118 - 0
lts-core/src/main/java/com/github/ltsopensource/core/compiler/JavassistCompiler.java

@@ -0,0 +1,118 @@
+/*
+ * Copyright 1999-2011 Alibaba Group.
+ *  
+ * Licensed 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 com.github.ltsopensource.core.compiler;
+
+import com.github.ltsopensource.core.commons.utils.ClassHelper;
+import javassist.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author william.liangf
+ */
+public class JavassistCompiler extends AbstractCompiler {
+
+    private static final Pattern IMPORT_PATTERN = Pattern.compile("import\\s+([\\w\\.\\*]+);\n");
+
+    private static final Pattern EXTENDS_PATTERN = Pattern.compile("\\s+extends\\s+([\\w\\.]+)[^\\{]*\\{\n");
+
+    private static final Pattern IMPLEMENTS_PATTERN = Pattern.compile("\\s+implements\\s+([\\w\\.]+)\\s*\\{\n");
+
+    private static final Pattern METHODS_PATTERN = Pattern.compile("\n(private|public|protected)\\s+");
+
+    private static final Pattern FIELD_PATTERN = Pattern.compile("[^\n]+=[^\n]+;");
+
+    @Override
+    public Class<?> doCompile(String name, String source) throws Throwable {
+        int i = name.lastIndexOf('.');
+        String className = i < 0 ? name : name.substring(i + 1);
+        ClassPool pool = new ClassPool(true);
+        pool.appendClassPath(new LoaderClassPath(ClassHelper.getCallerClassLoader(getClass())));
+        Matcher matcher = IMPORT_PATTERN.matcher(source);
+        List<String> importPackages = new ArrayList<String>();
+        Map<String, String> fullNames = new HashMap<String, String>();
+        while (matcher.find()) {
+            String pkg = matcher.group(1);
+            if (pkg.endsWith(".*")) {
+                String pkgName = pkg.substring(0, pkg.length() - 2);
+                pool.importPackage(pkgName);
+                importPackages.add(pkgName);
+            } else {
+                int pi = pkg.lastIndexOf('.');
+                if (pi > 0) {
+                    String pkgName = pkg.substring(0, pi);
+                    pool.importPackage(pkgName);
+                    importPackages.add(pkgName);
+                    fullNames.put(pkg.substring(pi + 1), pkg);
+                }
+            }
+        }
+        String[] packages = importPackages.toArray(new String[importPackages.size()]);
+        matcher = EXTENDS_PATTERN.matcher(source);
+        CtClass cls;
+        if (matcher.find()) {
+            String extend = matcher.group(1).trim();
+            String extendClass;
+            if (extend.contains(".")) {
+                extendClass = extend;
+            } else if (fullNames.containsKey(extend)) {
+                extendClass = fullNames.get(extend);
+            } else {
+                extendClass = ClassHelper.forName(packages, extend).getName();
+            }
+            cls = pool.makeClass(name, pool.get(extendClass));
+        } else {
+            cls = pool.makeClass(name);
+        }
+        matcher = IMPLEMENTS_PATTERN.matcher(source);
+        if (matcher.find()) {
+            String[] ifaces = matcher.group(1).trim().split("\\,");
+            for (String iface : ifaces) {
+                iface = iface.trim();
+                String ifaceClass;
+                if (iface.contains(".")) {
+                    ifaceClass = iface;
+                } else if (fullNames.containsKey(iface)) {
+                    ifaceClass = fullNames.get(iface);
+                } else {
+                    ifaceClass = ClassHelper.forName(packages, iface).getName();
+                }
+                cls.addInterface(pool.get(ifaceClass));
+            }
+        }
+        String body = source.substring(source.indexOf("{") + 1, source.length() - 1);
+        String[] methods = METHODS_PATTERN.split(body);
+        for (String method : methods) {
+            method = method.trim();
+            if (method.length() > 0) {
+                if (method.startsWith(className)) {
+                    cls.addConstructor(CtNewConstructor.make("public " + method, cls));
+                } else if (FIELD_PATTERN.matcher(method).matches()) {
+                    cls.addField(CtField.make("private " + method, cls));
+                } else {
+                    cls.addMethod(CtNewMethod.make(method, cls));
+                }
+            }
+        }
+        return cls.toClass(ClassHelper.getCallerClassLoader(getClass()), JavassistCompiler.class.getProtectionDomain());
+    }
+
+}

+ 5 - 9
lts-core/src/main/java/com/github/ltsopensource/core/compiler/JdkCompiler.java

@@ -1,10 +1,10 @@
 package com.github.ltsopensource.core.compiler;
 
 import com.github.ltsopensource.core.commons.utils.ClassHelper;
+import com.github.ltsopensource.core.logger.LoggerFactory;
 
 import javax.tools.*;
 import java.io.*;
-import java.lang.reflect.Method;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
@@ -18,7 +18,7 @@ public class JdkCompiler extends AbstractCompiler {
     public static final String CLASS_EXTENSION = ".class";
     public static final String JAVA_EXTENSION = ".java";
 
-    private JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+    private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
 
     private final DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
 
@@ -30,13 +30,9 @@ public class JdkCompiler extends AbstractCompiler {
 
     public JdkCompiler() {
         if (compiler == null) {
-            try {
-                Class<?> javacTool = Class.forName("com.sun.tools.javac.api.JavacTool");
-                Method create = javacTool.getMethod("create");
-                compiler = (JavaCompiler) create.invoke(null);
-            } catch (Exception e) {
-                throw new AssertionError(e);
-            }
+            throw new IllegalStateException(
+                    "Cannot find the system Java compiler. "
+                            + "Check that your class path includes tools.jar");
         }
         options = new ArrayList<String>();
 //        options.add("-target");

+ 3 - 1
lts-core/src/main/java/com/github/ltsopensource/core/constant/Constants.java

@@ -69,7 +69,7 @@ public interface Constants {
     String PROCESSOR_THREAD = "job.processor.thread";
     int DEFAULT_PROCESSOR_THREAD = 32 + AVAILABLE_PROCESSOR * 5;
 
-    int LATCH_TIMEOUT_MILLIS =  60 * 1000;      // 60s
+    int LATCH_TIMEOUT_MILLIS = 60 * 1000;      // 60s
 
     // 任务最多重试次数
     String JOB_MAX_RETRY_TIMES = "job.max.retry.times";
@@ -114,4 +114,6 @@ public interface Constants {
     String ONCE = "__LTS_ONCE";
 
     String IS_RETRY_JOB = "__LTS_Is_Retry_Job";
+
+    String COMPILER = "java.compiler";
 }

+ 9 - 0
lts-core/src/main/java/com/github/ltsopensource/core/support/bean/BeanCopierAdapter.java

@@ -0,0 +1,9 @@
+package com.github.ltsopensource.core.support.bean;
+
+/**
+ * @author Robert HG (254963746@qq.com) on 4/17/16.
+ */
+public abstract class BeanCopierAdapter implements BeanCopier<Object, Object> {
+
+    public abstract void copyProps(Object sourceObj, Object targetObj);
+}

+ 21 - 20
lts-core/src/main/java/com/github/ltsopensource/core/support/bean/BeanCopierFactory.java

@@ -4,8 +4,8 @@ import com.github.ltsopensource.core.commons.utils.Assert;
 import com.github.ltsopensource.core.commons.utils.BeanUtils;
 import com.github.ltsopensource.core.commons.utils.ClassHelper;
 import com.github.ltsopensource.core.commons.utils.ReflectionUtils;
+import com.github.ltsopensource.core.compiler.AbstractCompiler;
 import com.github.ltsopensource.core.compiler.Compiler;
-import com.github.ltsopensource.core.compiler.JdkCompiler;
 import com.github.ltsopensource.core.exception.LtsRuntimeException;
 import com.github.ltsopensource.core.logger.Logger;
 import com.github.ltsopensource.core.logger.LoggerFactory;
@@ -13,7 +13,6 @@ import com.github.ltsopensource.core.logger.LoggerFactory;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -21,22 +20,16 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * @author Robert HG (254963746@qq.com) on 4/2/16.
+ *         为了兼容javaassist 去掉泛型
  */
 public final class BeanCopierFactory {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(BeanCopierFactory.class);
 
-    private static Compiler COMPILER = new JdkCompiler();
+    private static Compiler COMPILER = AbstractCompiler.getCompiler();
     private static final AtomicInteger SEQ = new AtomicInteger(0);
     private static final ConcurrentMap<Integer, Map<String, PropConverter<?, ?>>> SEQ_PROP_CVT_MAP = new ConcurrentHashMap<Integer, Map<String, PropConverter<?, ?>>>();
 
-    public static void setCompiler(Compiler compiler) {
-        if (compiler == null) {
-            throw new IllegalArgumentException("compiler should not be null");
-        }
-        BeanCopierFactory.COMPILER = compiler;
-    }
-
     public static <Source, Target> BeanCopier<Source, Target> createCopier(
             Class<?> sourceClass, Class<?> targetClass) {
         return createCopier(sourceClass, targetClass, false, null);
@@ -68,7 +61,13 @@ public final class BeanCopierFactory {
 
         try {
             Class<?> beanCopierClazz = COMPILER.compile(getClassCode(sequence, sourceClass, targetClass, deepCopy, propCvtMap));
-            return (BeanCopier<Source, Target>) beanCopierClazz.newInstance();
+            final BeanCopierAdapter beanCopier = (BeanCopierAdapter) beanCopierClazz.newInstance();
+            return new BeanCopier<Source, Target>() {
+                @Override
+                public void copyProps(Source source, Target target) {
+                    beanCopier.copyProps(source, target);
+                }
+            };
         } catch (Exception e) {
             throw new LtsRuntimeException("Generate BeanCopier error, sourceClass=" + sourceClass.getName() + ", targetClass=" + targetClass.getName(), e);
         }
@@ -82,13 +81,14 @@ public final class BeanCopierFactory {
         JavaSourceBean javaSourceBean = new JavaSourceBean();
         javaSourceBean.setPackageName(BeanCopierFactory.class.getPackage().getName());
 
-        javaSourceBean.addImport(BeanCopier.class.getName());
+        javaSourceBean.addImport(BeanCopierAdapter.class.getName());
         javaSourceBean.addImport(sourceClass.getName());
         javaSourceBean.addImport(targetClass.getName());
+        javaSourceBean.addImport(PropConverter.class.getName());
 
         String beanCopierClassName = sourceClass.getSimpleName() + "2" + targetClass.getSimpleName() + BeanCopier.class.getSimpleName() + sequence;
         String classDefinitionCode = "public class " + beanCopierClassName +
-                " implements " + BeanCopier.class.getSimpleName() + "<" + sourceClass.getSimpleName() + "," + targetClass.getSimpleName() + ">";
+                " extends " + BeanCopierAdapter.class.getSimpleName();
 
         javaSourceBean.setClassDefinition(classDefinitionCode);
 
@@ -106,7 +106,9 @@ public final class BeanCopierFactory {
     private static String getMethodImplCode(Integer sequence, Class<?> sourceClass, Class<?> targetClass, boolean deepCopy, final Map<String, PropConverter<?, ?>> propCvtMap) throws Exception {
 
         StringBuilder methodCode = new StringBuilder();
-        methodCode.append("public void copyProps(").append(sourceClass.getSimpleName()).append(" source, ").append(targetClass.getSimpleName()).append(" target){\n");
+        methodCode.append("public void copyProps(").append(Object.class.getName()).append(" sourceObj, ").append(Object.class.getName()).append(" targetObj){\n");
+        methodCode.append(sourceClass.getSimpleName()).append(" source = ").append("(").append(sourceClass.getSimpleName()).append(")sourceObj;\n");
+        methodCode.append(targetClass.getSimpleName()).append(" target = ").append("(").append(targetClass.getSimpleName()).append(")targetObj;\n");
 
         // 这里查找了包括父类的属性
         Field[] targetFields = ReflectionUtils.findFields(targetClass);
@@ -116,7 +118,6 @@ public final class BeanCopierFactory {
                 // 是否含有set方法
                 String methodNameSuffix = capitalize(field.getName());
                 Class<?> targetFieldClass = field.getType();
-                Type targetFieldType = field.getGenericType();
 
                 Method setMethod = ReflectionUtils.findMethod(targetClass, "set" + methodNameSuffix, targetFieldClass);
                 if (setMethod != null) {
@@ -125,12 +126,12 @@ public final class BeanCopierFactory {
                     if (propCvtMap != null && propCvtMap.containsKey(field.getName())) {
 
                         String converterName = field.getName() + "Converter";
-                        String converterType = PropConverter.class.getName() + "<" + sourceClass.getSimpleName() + ", " + targetFieldType.toString() + "> ";
+                        String converterType = PropConverter.class.getSimpleName();
 
-                        methodCode.append(converterType).append(converterName).append(" = (").append(converterType).append(")")
+                        methodCode.append(converterType).append(" ").append(converterName).append(" = (").append(converterType).append(")")
                                 .append(BeanCopierFactory.class.getName()).append(".getConverter(").append(sequence).append(",").append("\"").append(field.getName()).append("\");\n");
                         methodCode.append("target.").append(setMethod.getName()).append("(")
-                                .append("(").append(targetFieldType.toString()).append(")").append(converterName).append(".convert(").append("source").append(")")
+                                .append("(").append(targetFieldClass.getName()).append(")").append(converterName).append(".convert(").append("source").append(")")
                                 .append(");\n");
                         continue;
                     }
@@ -154,7 +155,7 @@ public final class BeanCopierFactory {
                             } else {
                                 // 深度复制,对于非基本类型的采用流的方式拷贝
                                 methodCode.append("target.").append(setMethod.getName()).append("(")
-                                        .append("(").append(targetFieldType.toString()).append(")")
+                                        .append("(").append(targetFieldClass.getName()).append(")")
                                         .append(BeanUtils.class.getName()).append(".deepClone(")
                                         .append("source.").append(getMethod.getName()).append("()")
                                         .append(")")
@@ -184,7 +185,7 @@ public final class BeanCopierFactory {
     /**
      * 会被动态类使用
      */
-    public static PropConverter<?, ?> getConverter(Integer sequence, String propName) {
+    public static PropConverter<?, ?> getConverter(int sequence, String propName) {
         Map<String, PropConverter<?, ?>> map = SEQ_PROP_CVT_MAP.get(sequence);
         return map.get(propName);
     }

+ 13 - 0
lts-core/src/test/java/com/github/ltsopensource/core/support/bean/BeanCopierFactoryTest.java

@@ -1,6 +1,8 @@
 package com.github.ltsopensource.core.support.bean;
 
+import com.github.ltsopensource.core.compiler.AbstractCompiler;
 import com.github.ltsopensource.core.domain.Job;
+import com.github.ltsopensource.core.support.JobUtils;
 import com.github.ltsopensource.queue.domain.JobPo;
 import org.junit.Before;
 import org.junit.Test;
@@ -24,6 +26,17 @@ public class BeanCopierFactoryTest {
         jobPo.setInternalExtParam("xxx", "fadsfsa");
     }
 
+    @Test
+    public void testJdkCopy(){
+        AbstractCompiler.setCompiler("jdk");
+        JobUtils.copy(jobPo);
+    }
+    @Test
+    public void testJavassistCopy(){
+        AbstractCompiler.setCompiler("javassist");
+        JobUtils.copy(jobPo);
+    }
+
     @Test
     public void testGetBeanCopier() throws Exception {
         BeanCopier<JobPo, JobPo> beanCopier = BeanCopierFactory.createCopier(JobPo.class, JobPo.class);

+ 9 - 1
lts-monitor/src/main/java/com/github/ltsopensource/monitor/MonitorAgent.java

@@ -6,6 +6,8 @@ import com.github.ltsopensource.core.cmd.JVMInfoGetHttpCmd;
 import com.github.ltsopensource.core.cmd.StatusCheckHttpCmd;
 import com.github.ltsopensource.core.commons.utils.NetUtils;
 import com.github.ltsopensource.core.commons.utils.StringUtils;
+import com.github.ltsopensource.core.compiler.AbstractCompiler;
+import com.github.ltsopensource.core.constant.Constants;
 import com.github.ltsopensource.core.factory.JobNodeConfigFactory;
 import com.github.ltsopensource.core.factory.NodeFactory;
 import com.github.ltsopensource.core.json.JSONFactory;
@@ -80,7 +82,7 @@ public class MonitorAgent {
             JVMMonitor.start();
             AliveKeeping.start();
 
-            LOGGER.error("========== Start Monitor Success");
+            LOGGER.info("========== Start Monitor Success");
 
         } catch (Throwable t) {
             LOGGER.error("========== Start Monitor Error:", t);
@@ -101,6 +103,12 @@ public class MonitorAgent {
     }
 
     private void intConfig() {
+
+        String compiler = config.getParameter(Constants.COMPILER);
+        if (StringUtils.isNotEmpty(compiler)) {
+            AbstractCompiler.setCompiler(compiler);
+        }
+
         // 初始化一些 db access
         MonitorAccessFactory factory = ServiceLoader.load(MonitorAccessFactory.class, config);
         this.appContext.setJobTrackerMAccess(factory.getJobTrackerMAccess(config));

+ 1 - 1
lts-startup/src/main/resources/bin/lts-admin.cmd

@@ -10,7 +10,7 @@ set LTS_MAIN=com.github.ltsopensource.startup.admin.JettyContainer
 
 echo LTS-Admin started
 
-java -cp "%CLASSPATH%" %JVMFLAGS% %LTS_MAIN% "%BASE_HOME%" %*
+java -cp "%CLASSPATH%" %JVMFLAGS% %LTS_MAIN% %BASE_HOME% %*
 
 pause>null
 

+ 5 - 0
pom.xml

@@ -249,6 +249,11 @@
                 <artifactId>spring-boot-autoconfigure</artifactId>
                 <version>${spring.boot.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.javassist</groupId>
+                <artifactId>javassist</artifactId>
+                <version>${javassist.version}</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
     <profiles>