feat(Java_ConstractUtil):创建项目、单测,进行第一轮简单的测试
This commit is contained in:
@@ -0,0 +1,141 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>SpringBean</groupId>
|
||||||
|
<artifactId>SpringBean</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>7</source>
|
||||||
|
<target>7</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<name>SpringBean Maven Webapp</name>
|
||||||
|
<url>http://maven.apache.org</url>
|
||||||
|
|
||||||
|
|
||||||
|
<!--配置依赖的属性-->
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.build.jdk.version>1.7</project.build.jdk.version>
|
||||||
|
<javax.version>7.0</javax.version>
|
||||||
|
<junit.version>4.11</junit.version>
|
||||||
|
<javax.servlet.version>3.0</javax.servlet.version>
|
||||||
|
<log4j.version>2.3</log4j.version>
|
||||||
|
<slf4j.version>1.7.12</slf4j.version>
|
||||||
|
<org.aspectj.version>1.6.2</org.aspectj.version>
|
||||||
|
<net.sf.ehcache.version>2.3.2</net.sf.ehcache.version>
|
||||||
|
<org.springframework.version>4.3.1.RELEASE</org.springframework.version>
|
||||||
|
<oracle.jdbc.version>10.2.0.1.0</oracle.jdbc.version>
|
||||||
|
<!--<hibernateVersion>4.wwwwwww.0</hibernateVersion>-->
|
||||||
|
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
|
||||||
|
<powermock.version>1.4.9</powermock.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.9</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
<version>4.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>28.2-jre</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
<version>1.2.17</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<!--引入reflectASM包-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.esotericsoftware</groupId>
|
||||||
|
<artifactId>reflectasm</artifactId>
|
||||||
|
<version>1.11.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.powermock</groupId>
|
||||||
|
<artifactId>powermock-module-junit4</artifactId>
|
||||||
|
<version>${powermock.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.powermock</groupId>
|
||||||
|
<artifactId>powermock-api-mockito</artifactId>
|
||||||
|
<version>${powermock.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>1.8.5</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.8.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-collections</groupId>
|
||||||
|
<artifactId>commons-collections</artifactId>
|
||||||
|
<version>3.2.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>RELEASE</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.powermock</groupId>
|
||||||
|
<artifactId>powermock-module-junit4</artifactId>
|
||||||
|
<version>1.4.9</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
import bean.ContrastObject;
|
||||||
|
import com.esotericsoftware.reflectasm.MethodAccess;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import exception.NoSetMethodException;
|
||||||
|
import exception.TypeMisMatchException;
|
||||||
|
import handler.CollectionHandler;
|
||||||
|
import handler.MapHandler;
|
||||||
|
import handler.OriginHandler;
|
||||||
|
import handler.SelfHandler;
|
||||||
|
import util.CheckUtil;
|
||||||
|
import util.ClassUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import static constant.Constant.GET;
|
||||||
|
import static constant.Constant.SET;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 志军
|
||||||
|
* @date 2020-1-5 16:00:00
|
||||||
|
*/
|
||||||
|
public class ContrastUtil {
|
||||||
|
|
||||||
|
|
||||||
|
//get方法的缓存Map
|
||||||
|
private static ConcurrentHashMap<String, List<String>> getMethodCache = new ConcurrentHashMap<String, List<String>>();
|
||||||
|
|
||||||
|
//set方法的缓存map
|
||||||
|
private static ConcurrentHashMap<String, List<String>> setMethodCache = new ConcurrentHashMap<String, List<String>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单对象对比
|
||||||
|
*
|
||||||
|
* @param origin 原始对象
|
||||||
|
* @param target 修改后的对象
|
||||||
|
* @param <T> 对象类型
|
||||||
|
* @return 对比结果
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> ContrastObject<T> contrast(T origin, T target) throws IllegalAccessException, InstantiationException {
|
||||||
|
//空的情况的判断
|
||||||
|
if (origin == null || target == null) {
|
||||||
|
return nullProcessor(origin, target);
|
||||||
|
}
|
||||||
|
//提前检查 - 接口或者抽象类
|
||||||
|
if (!CheckUtil.commonCheck(origin.getClass())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//检查类型是否一致
|
||||||
|
if (!CheckUtil.CheckType(origin, target)) {
|
||||||
|
throw new TypeMisMatchException("类型不匹配");
|
||||||
|
}
|
||||||
|
//先检查get、set方法是否存在.
|
||||||
|
CheckUtil.checkGetAndSetMethod(origin.getClass());
|
||||||
|
|
||||||
|
//初始所有参数
|
||||||
|
Class<T> tClass = (Class<T>) origin.getClass();
|
||||||
|
T originChange = tClass.newInstance();
|
||||||
|
T targetChange = tClass.newInstance();
|
||||||
|
MethodAccess methodAccess = MethodAccess.get(tClass);
|
||||||
|
//获取get方法的值进行比较、正常情况下Field都会声明为private,reflectASM对static和private自动跳过,所以用MethodAccess进行处理
|
||||||
|
List<String> getList = getGetMethod(methodAccess, tClass);
|
||||||
|
List<String> setList = getSetMethod(methodAccess, tClass);
|
||||||
|
|
||||||
|
//循环所有的MethodAccess判断是否发生变化
|
||||||
|
boolean changed = forContrast(getList, methodAccess, origin, target, setList, originChange, targetChange);
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return setContrastObject(origin, target, originChange, targetChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> ContrastObject<T> nullProcessor(T origin, T target) {
|
||||||
|
if (origin == null && target == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (origin == null) {
|
||||||
|
return setContrastObject(null, target, null, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
return setContrastObject(origin, null, origin, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> boolean forContrast(List<String> getList, MethodAccess methodAccess, T origin, T target, List<String> setList,
|
||||||
|
T originChange, T targetChange) throws InstantiationException,
|
||||||
|
IllegalAccessException {
|
||||||
|
|
||||||
|
boolean changed = false;
|
||||||
|
for (String methodName : getList) {
|
||||||
|
//reflectASM会对基本类型进行装箱(比如说int返回Integer),所以这里要考虑的就是自定义类型怎么比较的问题
|
||||||
|
Object originValue = methodAccess.invoke(origin, methodName);
|
||||||
|
Object targetValue = methodAccess.invoke(target, methodName);
|
||||||
|
String setName = null;
|
||||||
|
for (String setMethodName : setList) {
|
||||||
|
if (setMethodName.substring(3).equals(methodName.substring(3))) {
|
||||||
|
setName = setMethodName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (setName == null) {
|
||||||
|
throw new NoSetMethodException();
|
||||||
|
}
|
||||||
|
if (originValue == null && targetValue == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//对比 + 设值
|
||||||
|
changed = changed || contrastValue(originValue, targetValue, originChange, targetChange, methodAccess, setName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> ContrastObject<T> setContrastObject(T origin, T target, T originChange, T targetChange) {
|
||||||
|
ContrastObject<T> contrastObject = new ContrastObject<>();
|
||||||
|
contrastObject.setOrigin(origin);
|
||||||
|
contrastObject.setTarget(target);
|
||||||
|
contrastObject.setOriginChange(originChange);
|
||||||
|
contrastObject.setTargetChange(targetChange);
|
||||||
|
return contrastObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param originValue get方法拿到的原始的值
|
||||||
|
* @param targetValue get方法拿到的变化的值
|
||||||
|
* @param originChange 新创建的原始变化对象
|
||||||
|
* @param targetChange 新创建的改变变化对象
|
||||||
|
* @param methodAccess reflectASM类
|
||||||
|
* @param setName set方法名
|
||||||
|
* @throws IllegalAccessException 异常
|
||||||
|
* @throws InstantiationException 异常
|
||||||
|
*/
|
||||||
|
private static boolean contrastValue(Object originValue, Object targetValue, Object originChange, Object targetChange,
|
||||||
|
MethodAccess methodAccess, String setName) throws IllegalAccessException, InstantiationException {
|
||||||
|
//处理Collection
|
||||||
|
if (originValue instanceof Collection || targetValue instanceof Collection) {
|
||||||
|
return CollectionHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Map的处理
|
||||||
|
if (originValue instanceof Map || targetValue instanceof Map) {
|
||||||
|
return MapHandler.putValue(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//非自定义类的处理
|
||||||
|
Boolean result = OriginHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
|
if (null != result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//自定义类型的处理
|
||||||
|
return SelfHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Get方法集合
|
||||||
|
*
|
||||||
|
* @param methodAccess MethodAccess
|
||||||
|
* @param tClass 类.class
|
||||||
|
* @param <T> T
|
||||||
|
* @return 方法名
|
||||||
|
*/
|
||||||
|
private static <T> List<String> getSetMethod(MethodAccess methodAccess, Class<T> tClass) {
|
||||||
|
if (setMethodCache.get(tClass.getName()) != null) {
|
||||||
|
return setMethodCache.get(tClass.getName());
|
||||||
|
}
|
||||||
|
List<String> methodNameList = Lists.newArrayList();
|
||||||
|
List<Method> methods = ClassUtil.getAllMethodWithSuper(tClass);
|
||||||
|
String[] methodNames = methodAccess.getMethodNames();
|
||||||
|
|
||||||
|
return buildMethodList(SET, methodNames, methods, methodNameList, setMethodCache, tClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> List<String> buildMethodList(String type, String[] methodNames, List<Method> methods, List<String> methodNameList,
|
||||||
|
ConcurrentHashMap<String, List<String>> methodCache, Class<T> tClass) {
|
||||||
|
for (String methodName : methodNames) {
|
||||||
|
if (methodName.startsWith(type)) {
|
||||||
|
for (Method method : methods) {
|
||||||
|
if (method.getName().equals(methodName)) {
|
||||||
|
methodNameList.add(methodName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
methodCache.put(tClass.getName(), methodNameList);
|
||||||
|
return methodNameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Set方法集合
|
||||||
|
*
|
||||||
|
* @param methodAccess MethodAccess
|
||||||
|
* @param tClass 类.class
|
||||||
|
* @param <T> T
|
||||||
|
* @return 方法名
|
||||||
|
*/
|
||||||
|
private static <T> List<String> getGetMethod(MethodAccess methodAccess, Class<T> tClass) {
|
||||||
|
if (getMethodCache.get(tClass.getName()) != null) {
|
||||||
|
return getMethodCache.get(tClass.getName());
|
||||||
|
}
|
||||||
|
List<String> methodNameList = Lists.newArrayList();
|
||||||
|
String[] methodNames = methodAccess.getMethodNames();
|
||||||
|
List<Method> methods = ClassUtil.getAllMethodWithSuper(tClass);
|
||||||
|
|
||||||
|
return buildMethodList(GET, methodNames, methods, methodNameList, getMethodCache, tClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package bean;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回的对比对象的包装
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ContrastObject<T> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原始的java对象
|
||||||
|
*/
|
||||||
|
private T origin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改后的java对象
|
||||||
|
*/
|
||||||
|
private T target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原始的java对象修改的部分
|
||||||
|
*/
|
||||||
|
private T originChange;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改后的java对象修改的部分
|
||||||
|
*/
|
||||||
|
private T targetChange;
|
||||||
|
|
||||||
|
|
||||||
|
public T getOrigin() {
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrigin(T origin) {
|
||||||
|
this.origin = origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(T target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getOriginChange() {
|
||||||
|
return originChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOriginChange(T originChange) {
|
||||||
|
this.originChange = originChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getTargetChange() {
|
||||||
|
return targetChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetChange(T targetChange) {
|
||||||
|
this.targetChange = targetChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
ContrastObject<?> that = (ContrastObject<?>) o;
|
||||||
|
return getOrigin().equals(that.getOrigin()) &&
|
||||||
|
getTarget().equals(that.getTarget()) &&
|
||||||
|
getOriginChange().equals(that.getOriginChange()) &&
|
||||||
|
getTargetChange().equals(that.getTargetChange());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(getOrigin(), getTarget(), getOriginChange(), getTargetChange());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package constant;
|
||||||
|
|
||||||
|
public class Constant {
|
||||||
|
|
||||||
|
|
||||||
|
public static final String GET = "get";
|
||||||
|
public static final String SET = "set";
|
||||||
|
public static final String WELL_NUMBER = "#";
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package exception;
|
||||||
|
|
||||||
|
public class NoGetMethodException extends RuntimeException{
|
||||||
|
|
||||||
|
public NoGetMethodException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NoGetMethodException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NoGetMethodException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NoGetMethodException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected NoGetMethodException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package exception;
|
||||||
|
|
||||||
|
public class NoSetMethodException extends RuntimeException {
|
||||||
|
|
||||||
|
public NoSetMethodException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NoSetMethodException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NoSetMethodException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NoSetMethodException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected NoSetMethodException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package exception;
|
||||||
|
|
||||||
|
public class TypeMisMatchException extends RuntimeException {
|
||||||
|
|
||||||
|
public TypeMisMatchException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeMisMatchException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeMisMatchException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeMisMatchException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TypeMisMatchException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020.
|
||||||
|
* made by 志军
|
||||||
|
*/
|
||||||
|
|
||||||
|
package handler;
|
||||||
|
|
||||||
|
import com.esotericsoftware.reflectasm.MethodAccess;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import util.CollectionUtil;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理Collection类型的对比,必须重写equals和hashCode方法
|
||||||
|
*
|
||||||
|
* @author 志军
|
||||||
|
*/
|
||||||
|
public class CollectionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对比组合Collection差异的部分
|
||||||
|
*
|
||||||
|
* @param originChange 原始的变化部分的对象
|
||||||
|
* @param targetChange 修改后变化部分的对象
|
||||||
|
* @param originValue 原始的对象
|
||||||
|
* @param targetValue 修改后的对象
|
||||||
|
* @param methodAccess MethodAccess
|
||||||
|
* @param setName set方法名
|
||||||
|
* @return 是否变化
|
||||||
|
* @throws IllegalAccessException 异常
|
||||||
|
* @throws InstantiationException 异常
|
||||||
|
*/
|
||||||
|
public static Boolean contract(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
||||||
|
MethodAccess methodAccess, String setName) throws IllegalAccessException, InstantiationException {
|
||||||
|
|
||||||
|
boolean changed;
|
||||||
|
Class returnValue = originValue.getClass();
|
||||||
|
|
||||||
|
//判断Collection是否相等
|
||||||
|
if (CollectionUtils.isEqualCollection((Collection) originValue, (Collection) targetValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object originCollection = CollectionUtil.buildDiffCollection(originValue, targetValue, returnValue);
|
||||||
|
Object changeCollection = CollectionUtil.buildDiffCollection(targetValue, originValue, returnValue);
|
||||||
|
|
||||||
|
changed = CollectionUtils.isNotEmpty((Collection) originCollection) || CollectionUtils.isNotEmpty((Collection) changeCollection);
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
methodAccess.invoke(originChange, setName, originCollection);
|
||||||
|
methodAccess.invoke(targetChange, setName, changeCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020.
|
||||||
|
* made by 志军
|
||||||
|
*/
|
||||||
|
|
||||||
|
package handler;
|
||||||
|
|
||||||
|
import com.esotericsoftware.reflectasm.MethodAccess;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import util.MapUtil;
|
||||||
|
import util.SetUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理Map对应的对比
|
||||||
|
*
|
||||||
|
* @author 志军
|
||||||
|
*/
|
||||||
|
public class MapHandler {
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean putValue(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
||||||
|
MethodAccess methodAccess, String setName) throws IllegalAccessException, InstantiationException {
|
||||||
|
//参数前置
|
||||||
|
boolean changed = false;
|
||||||
|
Set<Map.Entry> originEntry = ((Map) originValue).entrySet();
|
||||||
|
Set<Map.Entry> targetEntry = ((Map) targetValue).entrySet();
|
||||||
|
Map originMap = (Map) originValue.getClass().newInstance();
|
||||||
|
Map targetMap = (Map) targetValue.getClass().newInstance();
|
||||||
|
|
||||||
|
//处理key一样的value比较.
|
||||||
|
for (Map.Entry entry : originEntry) {
|
||||||
|
Object key = entry.getKey();
|
||||||
|
for (Map.Entry tEntry : targetEntry) {
|
||||||
|
if (tEntry.getKey().equals(key)) {
|
||||||
|
//每一个key都进行比较,如果key相等则比较对应的value,这个value需要重写hashcode和equals方法
|
||||||
|
changed = changed || MapHandler.putValue(originChange, targetChange, originMap, targetMap, key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//得到不一致的key的集合.
|
||||||
|
List<Map.Entry> originList = SetUtil.findUnLikeValue(originEntry, targetEntry);
|
||||||
|
List<Map.Entry> changeList = SetUtil.findUnLikeValue(originEntry, targetEntry);
|
||||||
|
//计算changed的值
|
||||||
|
changed = changed || !CollectionUtils.isEmpty(originList) || CollectionUtils.isEmpty(changeList);
|
||||||
|
//把不一致的值设置会新的Map中
|
||||||
|
MapUtil.putIfNotEmpty(originMap, originList);
|
||||||
|
MapUtil.putIfNotEmpty(targetMap, changeList);
|
||||||
|
//对对象进行设值
|
||||||
|
methodAccess.invoke(originChange, setName, originValue);
|
||||||
|
methodAccess.invoke(targetChange, setName, targetValue);
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean putValue(Object originChange, Object targetChange, Map<Object, Object> originMap,
|
||||||
|
Map<Object, Object> targetMap, Object key) {
|
||||||
|
if (originChange.equals(targetChange)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
originMap.put(key, originChange);
|
||||||
|
targetMap.put(key, targetChange);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020.
|
||||||
|
* made by 志军
|
||||||
|
*/
|
||||||
|
|
||||||
|
package handler;
|
||||||
|
|
||||||
|
import com.esotericsoftware.reflectasm.MethodAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理除Iterable和Map之外的原始类型
|
||||||
|
*
|
||||||
|
* @author 志军
|
||||||
|
*/
|
||||||
|
public class OriginHandler {
|
||||||
|
|
||||||
|
|
||||||
|
public static Boolean contract(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
||||||
|
MethodAccess methodAccess, String setName) {
|
||||||
|
Class returnValue = originValue == null ? targetValue.getClass() : originValue.getClass();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (returnValue.getClassLoader() == null) {
|
||||||
|
return contractValue(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
|
} else {
|
||||||
|
//用来判断是否进行了比较
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (NullPointerException ex) {
|
||||||
|
//这边是处理Object类型
|
||||||
|
return contractValue(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static boolean contractValue(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
||||||
|
MethodAccess methodAccess, String setName) {
|
||||||
|
boolean result = (originValue == null ? targetValue.equals(originChange) : originValue.equals(targetValue));
|
||||||
|
if (originValue == targetValue || result) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
methodAccess.invoke(originChange, setName, originValue);
|
||||||
|
methodAccess.invoke(targetChange, setName, targetValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020.
|
||||||
|
* made by 志军
|
||||||
|
*/
|
||||||
|
|
||||||
|
package handler;
|
||||||
|
|
||||||
|
import com.esotericsoftware.reflectasm.MethodAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理自定义的类,必须重写hashCode和equals方法,不然会出现对比偏差.<p>
|
||||||
|
* @author 志军
|
||||||
|
*/
|
||||||
|
public class SelfHandler {
|
||||||
|
public static Boolean contract(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
||||||
|
MethodAccess methodAccess, String setName) {
|
||||||
|
if (!originChange.equals(targetChange)) {
|
||||||
|
methodAccess.invoke(originChange, setName, originValue);
|
||||||
|
methodAccess.invoke(targetChange, setName, targetValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package util;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import exception.NoGetMethodException;
|
||||||
|
import exception.NoSetMethodException;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
import static constant.Constant.GET;
|
||||||
|
import static constant.Constant.SET;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 志军
|
||||||
|
* @date 2020-1-5 16:00:00
|
||||||
|
*/
|
||||||
|
public class CheckUtil {
|
||||||
|
|
||||||
|
private static Vector<String> vector = new Vector<>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提前检查是否包含了get、set方法
|
||||||
|
* TODO 没有考虑is方法
|
||||||
|
*
|
||||||
|
* @param zClass Class类
|
||||||
|
*/
|
||||||
|
public static void checkGetAndSetMethod(Class zClass) {
|
||||||
|
if (vector.contains(zClass.getName())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Field> fieldList = ClassUtil.getAllFieldWithSuper(zClass);
|
||||||
|
List<Method> methodList = ClassUtil.getAllMethodWithSuper(zClass);
|
||||||
|
List<String> methodNameList = getMethodNameList(methodList);
|
||||||
|
for (Field field : fieldList) {
|
||||||
|
String fieldName = field.getName();
|
||||||
|
final String s = String.valueOf(fieldName.charAt(0)).toUpperCase();
|
||||||
|
String setMethodName = SET + s + fieldName.substring(1);
|
||||||
|
String getMethodName = GET + s + fieldName.substring(1);
|
||||||
|
if (!methodNameList.contains(getMethodName)) {
|
||||||
|
throw new NoGetMethodException();
|
||||||
|
}
|
||||||
|
//这边加上了set的参数校验
|
||||||
|
if (!methodNameList.contains(setMethodName) || !setMethodParamCheck(field, setMethodName, methodList)) {
|
||||||
|
throw new NoSetMethodException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vector.add(zClass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean setMethodParamCheck(Field field, String setMethodName, List<Method> methodList) {
|
||||||
|
for (Method method : methodList) {
|
||||||
|
if (method.getName().equals(setMethodName) && method.getParameterTypes()[0] == field.getType()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> getMethodNameList(List<Method> methodList) {
|
||||||
|
List<String> methodNameList = Lists.newArrayList();
|
||||||
|
for (Method method : methodList) {
|
||||||
|
methodNameList.add(method.getName());
|
||||||
|
}
|
||||||
|
return methodNameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否为抽象类或者接口
|
||||||
|
*/
|
||||||
|
public static boolean commonCheck(Class<?> aClass) {
|
||||||
|
return !Modifier.isAbstract(aClass.getModifiers()) && !Modifier.isInterface(aClass.getModifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> boolean CheckType(T origin, T target) {
|
||||||
|
return origin.getClass() == target.getClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package util;
|
||||||
|
|
||||||
|
import com.esotericsoftware.reflectasm.MethodAccess;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import static constant.Constant.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 志军
|
||||||
|
* @date 2020-1-5 16:00:00
|
||||||
|
* 其实你不用担心类似 ##<code>fieldCache.get(zClass.getName())</code>这样的代码在一个方法里面写了很多遍会处理多次
|
||||||
|
* <p>可以了解一下##方法内联
|
||||||
|
*/
|
||||||
|
public class ClassUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类名#方法 - 方法索引 缓存
|
||||||
|
*/
|
||||||
|
private static ConcurrentHashMap<String, Integer> cache = new ConcurrentHashMap<String, Integer>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类 - Field数组 缓存
|
||||||
|
*/
|
||||||
|
private static ConcurrentHashMap<String, List<Field>> fieldCache = new ConcurrentHashMap<String, List<Field>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类 - method数组 缓存
|
||||||
|
*/
|
||||||
|
private static ConcurrentHashMap<String, List<Method>> methodCache = new ConcurrentHashMap<String, List<Method>>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取get方法
|
||||||
|
*
|
||||||
|
* @param fieldName 类属性名称
|
||||||
|
* @param zClass 类.class
|
||||||
|
* @return GetMethod
|
||||||
|
*/
|
||||||
|
public static Integer getGetMethod(String fieldName, Class zClass) {
|
||||||
|
//获取下标的方式非常方便,本质上,如果使用getDeclareMethod方法,还需要考虑继承的问题
|
||||||
|
MethodAccess access = MethodAccess.get(zClass);
|
||||||
|
String getMethodName = GET + String.valueOf(fieldName.charAt(0)).toUpperCase() + fieldName.substring(1);
|
||||||
|
String keyName = zClass.getName() + WELL_NUMBER + getMethodName;
|
||||||
|
if (cache.get(keyName) == null) {
|
||||||
|
cache.put(keyName, access.getIndex(getMethodName));
|
||||||
|
return access.getIndex(getMethodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache.get(keyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取set方法
|
||||||
|
*
|
||||||
|
* @param fieldName 类属性名称
|
||||||
|
* @param zClass 类.class
|
||||||
|
* @return SetMethod
|
||||||
|
*/
|
||||||
|
public static Integer getSetMethod(String fieldName, Class zClass) {
|
||||||
|
String setMethodName = SET + String.valueOf(fieldName.charAt(0)).toUpperCase() + fieldName.substring(1);
|
||||||
|
String keyName = zClass.getName() + WELL_NUMBER + setMethodName;
|
||||||
|
MethodAccess access = MethodAccess.get(zClass);
|
||||||
|
if (cache.get(keyName) != null) {
|
||||||
|
return cache.get(keyName);
|
||||||
|
}
|
||||||
|
cache.put(keyName, access.getIndex(setMethodName));
|
||||||
|
return access.getIndex(setMethodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static List<Field> getAllFieldWithSuper(Class zClass) {
|
||||||
|
if (fieldCache.get(zClass.getName()) != null) {
|
||||||
|
return fieldCache.get(zClass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
List<Field> fieldList = Lists.newArrayList();
|
||||||
|
Class tempClass = zClass;
|
||||||
|
while (tempClass != null) {
|
||||||
|
fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
|
||||||
|
tempClass = tempClass.getSuperclass();
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldCache.put(zClass.getName(), fieldList);
|
||||||
|
return fieldList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static List<Method> getAllMethodWithSuper(Class zClass) {
|
||||||
|
if (methodCache.get(zClass.getName()) != null) {
|
||||||
|
return methodCache.get(zClass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Class tempClass = zClass;
|
||||||
|
List<Method> methodList = Lists.newArrayList();
|
||||||
|
while (tempClass != null) {
|
||||||
|
methodList.addAll(Arrays.asList(tempClass.getDeclaredMethods()));
|
||||||
|
tempClass = tempClass.getSuperclass();
|
||||||
|
}
|
||||||
|
|
||||||
|
methodCache.put(zClass.getName(), methodList);
|
||||||
|
return methodList;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020.
|
||||||
|
* made by 志军
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection类型的处理工具
|
||||||
|
* @author 志军
|
||||||
|
*/
|
||||||
|
public class CollectionUtil {
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Collection buildDiffCollection(Object originValue, Object targetValue, Class returnValue) throws IllegalAccessException,
|
||||||
|
InstantiationException {
|
||||||
|
|
||||||
|
Object collection = returnValue.newInstance();
|
||||||
|
|
||||||
|
for (Object value : (Collection) originValue) {
|
||||||
|
if (((Collection) targetValue).contains(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
((Collection) collection).add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Collection) collection;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020.
|
||||||
|
* made by 志军
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map工具类
|
||||||
|
* @author 志军
|
||||||
|
*/
|
||||||
|
public class MapUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把List中Entry对应的key、value设置到新的Map中
|
||||||
|
* @param map 新的Map
|
||||||
|
* @param changeList 变化的List
|
||||||
|
*/
|
||||||
|
public static void putIfNotEmpty(Map<Object, Object> map, List<Map.Entry> changeList) {
|
||||||
|
if (CollectionUtils.isEmpty(changeList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (Map.Entry entry : changeList) {
|
||||||
|
map.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020.
|
||||||
|
* made by 志军
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set工具类
|
||||||
|
* @author 志军
|
||||||
|
*/
|
||||||
|
public class SetUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param origin 原始Set
|
||||||
|
* @param target 目标Set
|
||||||
|
* @param <T> Set类型
|
||||||
|
* @return 返回origin中不被包含在target的元素集合
|
||||||
|
*/
|
||||||
|
public static <T> List<T> findUnLikeValue(Set<T> origin, Set<T> target) {
|
||||||
|
List<T> unLikeList = Lists.newArrayList();
|
||||||
|
for (T t : origin) {
|
||||||
|
if (target.contains(t)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
unLikeList.add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return unLikeList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# 工具说明
|
||||||
|
|
||||||
|
# 更新日志
|
||||||
|
2020/4/30: 创建项目、单测,进行第一轮简单的测试
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import bean.ContrastObject;
|
||||||
|
|
||||||
|
public class ContractTest {
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
|
||||||
|
SimpleObj s1 = new SimpleObj();
|
||||||
|
s1.setM((float) 2.2);
|
||||||
|
s1.setY("55555");
|
||||||
|
ContrastObject<SimpleObj> sim = ContrastUtil.contrast(new SimpleObj(), s1);
|
||||||
|
|
||||||
|
|
||||||
|
System.out.print(sim.getTargetChange().m + " " + sim.getTargetChange().x + " " + sim.getTargetChange().y);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class SimpleObj {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
String y;
|
||||||
|
|
||||||
|
float m;
|
||||||
|
|
||||||
|
Date date;
|
||||||
|
|
||||||
|
public Date getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDate(Date date) {
|
||||||
|
this.date = date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(int x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY(String y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getM() {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setM(float m) {
|
||||||
|
this.m = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user