一、创建库表
1、创建两个数据库
CREATE SCHEMA `shard_db_0` DEFAULT CHARACTER SET utf8 ;
CREATE SCHEMA `shard_db_1` DEFAULT CHARACTER SET utf8 ;
2、在每个数据库各创建三个分表
CREATE TABLE `tb_order_0` (`order_id` bigint(20) NOT NULL,`buyer_id` bigint(20) not null comment '买家ID',`seller_id` bigint(20) not null comment '卖家ID',`order_name` varchar(64) not NULL COMMENT '商品名称',`price` decimal(10,2) DEFAULT NULL COMMENT '商品价格',PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tb_order_1` (`order_id` bigint(20) NOT NULL,`buyer_id` bigint(20) not null comment '买家ID',`seller_id` bigint(20) not null comment '卖家ID',`order_name` varchar(64) not NULL COMMENT '商品名称',`price` decimal(10,2) DEFAULT NULL COMMENT '商品价格',PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `tb_order_2` (`order_id` bigint(20) NOT NULL,`buyer_id` bigint(20) not null comment '买家ID',`seller_id` bigint(20) not null comment '卖家ID',`order_name` varchar(64) not NULL COMMENT '商品名称',`price` decimal(10,2) DEFAULT NULL COMMENT '商品价格',PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2、创建工程
1、引入maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.1</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>sharding-sphere-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>sharding-sphere-demo</name><description>sharding-sphere-demo</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version></dependency><!-- MyBatis-Plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.7</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/shardingsphere-jdbc-core-spring-boot-starter --><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId><version>5.2.1</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>
2、创建po
@Builder
@Data
@TableName("tb_buyer")
public class TbBuyer {@TableIdprivate Long buyerId;private String buyerName;private Boolean sex;private Integer age;}
@Builder
@Data
@TableName("tb_order")
public class TbOrder {@TableIdprivate Long orderId;private Long buyerId;private Long sellerId;private String orderName;private BigDecimal price;}
@Builder
@Data
@TableName("tb_seller")
public class TbSeller {@TableIdprivate Long sellerId;private String sellerName;private Boolean sex;private Integer age;}
3、创建mapper
package com.example.shardingsphere.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.shardingsphere.po.TbBuyer;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface TbBuyerMapper extends BaseMapper<TbBuyer> {// 可以在这里定义自定义方法
}
package com.example.shardingsphere.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.shardingsphere.po.TbOrder;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface TbOrderMapper extends BaseMapper<TbOrder> {// 可以在这里定义自定义方法
}
package com.example.shardingsphere.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.shardingsphere.po.TbSeller;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface TbSellerMapper extends BaseMapper<TbSeller> {// 可以在这里定义自定义方法
}
4、创建controller控制器
package com.example.shardingsphere.web;import com.example.shardingsphere.mapper.TbBuyerMapper;
import com.example.shardingsphere.mapper.TbOrderMapper;
import com.example.shardingsphere.mapper.TbSellerMapper;
import com.example.shardingsphere.po.TbOrder;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@RestController
public class OrderController {@Resourceprivate TbBuyerMapper tbBuyerMapper ;@Resourceprivate TbSellerMapper tbSellerMapper ;@Resourceprivate TbOrderMapper tbOrderMapper ;/*** 查询订单详情*/@GetMapping("/order/info/{orderId}")public Map<String,Object> orderInfo (@PathVariable Long orderId){Map<String,Object> orderMap = new HashMap<>() ;TbOrder order = tbOrderMapper.selectById(orderId) ;if (order != null){orderMap.put("order",order) ;orderMap.put("buyer",tbBuyerMapper.selectById(order.getBuyerId())) ;orderMap.put("seller",tbSellerMapper.selectById(order.getSellerId())) ;}return orderMap ;}
}
5、用到的工具类(雪花算法生成关联表主键ID,测试用,无特殊意义)
package com.example.shardingsphere.provider;import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;/*** 雪花算法**/
@Slf4j
@Component
public class SnowFlakeProvider implements ApplicationRunner {private long workerId;private Snowflake snowFlake;private long datacenterId;/*** 初始化方法,用于在类实例化后进行必要的设置。* 本方法主要用于确定WorkerId,这是一个在分布式系统中唯一标识当前节点的ID。* 它通过获取本地主机名或IP并转换为long值来实现。* 如果无法获取本地主机名或IP,或者转换过程中发生异常,将不设置workerId,可能导致后续ID生成失败。*/@Overridepublic void run(ApplicationArguments args) throws Exception {//初始化workIdinitWorkId();initDataCenterId();//初始化SnowflakeID生成器createSnowFlake(workerId, datacenterId);}/*** 根据IP Address 生成workId** @return*/private void initWorkId() {try {String hostAddress = Inet4Address.getLocalHost().getHostAddress();log.info("hostAddress========={}", hostAddress);int[] ints = StringUtils.toCodePoints(hostAddress);int sums = 0;for (int b : ints) {sums += b;}workerId= (long) (sums % 32);} catch (UnknownHostException e) {log.error("根据IP获取workId失败。", e);// 如果获取失败,则使用随机数备用workerId = RandomUtil.randomLong(0, 31);}}/*** 根据HostName 生成dataCenterId* @return*/private void initDataCenterId() {String hostName = getHostName();log.info("hostName========={}", hostName);int[] ints = StringUtils.toCodePoints(hostName);int sums = 0;for (int i : ints) {sums += i;}datacenterId = (long) (sums % 32);}/*** 获取 hostName* SystemUtils.getHostName() 在mac系统为空处理* @return*/public static String getHostName() {//获取当前操作系统名称,例如:windows xp,linux 等String osName = System.getProperty("os.name");String hostName = null;if(!StringUtils.startsWithIgnoreCase(osName,"mac")){hostName = SystemUtils.getHostName();}else{try {hostName = InetAddress.getLocalHost().getHostName().toUpperCase();} catch (UnknownHostException e) {hostName = "N/A";log.error("获取 hostName错误:", e);}}return hostName;}/*** 初始化SnowflakeID生成器。* 使用指定的workerId和datacenterId创建SnowflakeID生成器实例。如果创建失败,将抛出异常。** @param workerId 工作节点ID,用于标识当前节点。* @param datacenterId 数据中心ID,用于标识数据中心。* @throws IllegalArgumentException 如果Snowflake实例创建失败,则抛出此异常。* @throws RuntimeException 如果Snowflake实例创建过程中发生其他异常,则抛出此异常。*/private Snowflake createSnowFlake(long workerId, long datacenterId) {try {this.snowFlake = IdUtil.createSnowflake(workerId, datacenterId);// 参数合法性检查if (null == snowFlake) {throw new IllegalArgumentException("Failed to create Snowflake instance. Check workerId and datacenterId.");}return snowFlake;} catch (Exception e) {log.error("创建Snowflake实例失败,异常:{}", e.getMessage());throw new RuntimeException("Initialization failed for Snowflake ID generator.", e);}}/*** 获取一个唯一的雪花ID。使用Snowflake算法生成ID,该算法由Twitter开源。* 具体来说,这个方法调用了Snowflake实例的nextId方法来获取一个唯一的长整型ID。* 使用synchronized关键字确保了这个方法在多线程环境下的线程安全,* 保证了ID的生成不会因为并发而产生重复或错乱。** @return 生成的唯一长整型ID。*/public synchronized long snowflakeId() {// 调用Snowflake实例的nextId方法获取唯一IDreturn this.snowFlake.nextId();}/*** 生成基于Snowflake算法的唯一ID。* <p>* 使用Snowflake算法生成唯一的分布式ID。该算法由Twitter提出,通过组合时间戳、工作机器ID和序列号来生成全局唯一的ID。* 具体结构如下:* - 1位符号位,用于区分正负,由于ID只能是正数,所以这个位始终为0。* - 41位时间戳,精确到毫秒,可以使用约69年。* - 10位工作机器ID,可以部署在1024个节点,包括5位数据中心ID和5位工作机器ID。* - 12位序列号,用于同一毫秒内生成的ID去重,每个节点每毫秒可以生成4096个ID。* <p>* 参数:* workerId - 工作机器ID,用于标识不同的工作机器或进程。* datacenterId - 数据中心ID,用于标识不同的数据中心。* <p>* 返回:* 一个长整型的唯一ID,根据Snowflake算法生成。*/public synchronized long snowflakeId(long workerId, long datacenterId) {return createSnowFlake(workerId, datacenterId).nextId();}}
6、测试用例
package com.example.shardingsphere;import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.shardingsphere.mapper.TbOrderMapper;
import com.example.shardingsphere.po.TbOrder;
import com.example.shardingsphere.provider.SnowFlakeProvider;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;@Slf4j
public class ShardTest extends ShardingSphereDemoApplicationTests{@Autowiredprivate SnowFlakeProvider snowFlakeProvider;@Autowiredprivate TbOrderMapper tbOrderMapper ;/*** 写入100条数据*/@Testpublic void testOrderInsert (){List<TbOrder> list = new ArrayList<>();for (int i=1 ; i<= 10 ; i++){TbOrder order = TbOrder.builder()
// .orderId(snowFlakeProvider.snowflakeId()).buyerId(snowFlakeProvider.snowflakeId()).sellerId(snowFlakeProvider.snowflakeId()).orderName("订单"+ RandomUtil.randomInt(6)).price(RandomUtil.randomBigDecimal().setScale(2, BigDecimal.ROUND_HALF_UP)).build();list.add(order);}tbOrderMapper.insert(list);}@Testpublic void testOrderQuery (){TbOrder order = tbOrderMapper.selectById(5) ;Assert.assertNotNull(order);log.info("查询结果:"+ JSONUtil.toJsonStr(order));}@Testpublic void testOrderUpdate (){TbOrder order = tbOrderMapper.selectById(3) ;Assert.assertNotNull(order);order.setBuyerId(1l);order.setSellerId(3l);int count = tbOrderMapper.updateById(order) ;log.info("更新记录数:"+count);}@Testpublic void testOrderPage (){//分页参数Page<TbOrder> rowPage = new Page<>(1, 2);//queryWrapper组装查询where条件LambdaQueryWrapper<TbOrder> queryWrapper = new LambdaQueryWrapper<>();Page<TbOrder> page = tbOrderMapper.selectPage(rowPage, queryWrapper);log.info("分页查询结果:"+ JSONUtil.toJsonStr(page));}}
7、yml配置
server:port: 8095spring:application:name: dynamic-datasource-spring-boot-startershardingsphere:mode:type: Standalonerepository:type: JDBCdatabase:name: db0# 数据源配置datasource:# 数据源名称,多数据源以逗号分隔names: db0,db1db0:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://xx:3306/shard_db_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: xxpassword: xxdb1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://xx:3306/shard_db_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: xxpassword: xx# 分片规则配置rules:sharding:# 分片算法配置sharding-algorithms:database-inline:# 分片算法类型type: INLINEprops:# 分片算法的行表达式(算法自行定义,此处为方便演示效果)algorithm-expression: db${order_id % 2}table-inline:# 分片算法类型type: INLINEprops:# 分片算法的行表达式algorithm-expression: tb_order_${order_id % 3}tables:# 逻辑表名称tb_order:# 行表达式标识符可以使用 ${...} 或 $->{...},但前者与 Spring 本身的属性文件占位符冲突,因此在 Spring 环境中使用行表达式标识符建议使用 $->{...}actual-data-nodes: db${0..1}.tb_order_${0..2}# 分库策略database-strategy:standard:# 分片列名称sharding-column: order_id# 分片算法名称sharding-algorithm-name: database-inline# 分表策略table-strategy:standard:# 分片列名称sharding-column: order_id# 分片算法名称sharding-algorithm-name: table-inline# 属性配置props:# 展示修改以后的sql语句sql-show: truemybatis-plus:type-aliases-package: com.example.dynamic.poconfiguration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations:- classpath:/mapper/*.xml
至此,一个支持分库分表的工程搭建完成。
########################################################
关于搭建过程中遇到的问题(shardingsphere-jdbc-core-spring-boot-starter 5.2.1)
1、Caused by: java.lang.NoSuchMethodError: org.yaml.snakeyaml.representer.Representer: method 'void <init>()' not found
解答:该问题是由于版本问题导致的,是个兼容性问题。
shardingsphere-jdbc-core-spring-boot-starter 5.2.1中使用snakeyaml版本1.33 spring-boot-starter-web使用snakeyaml版本2.2 2.2中删除了Representer和SafeRepresenter的无参构造器,因此导致了该异常。
可通过降低boot版本号从而降低其中snakeyaml版本号解决,但由于snakeyaml 1.x版本有安全问题,而shardingsphere-jdbc-core-spring-boot-starter已是当前最高版本,因此可通过重新jar中bean新增无参构造器去覆盖jar bean去解决。
com.main.java下新增目录org.yaml.snakeyaml.representer
目录下新建bean
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.yaml.snakeyaml.representer;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.introspector.Property;
import org.yaml.snakeyaml.introspector.PropertyUtils;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeId;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.ScalarNode;
import org.yaml.snakeyaml.nodes.SequenceNode;
import org.yaml.snakeyaml.nodes.Tag;public class Representer extends SafeRepresenter {protected Map<Class<? extends Object>, TypeDescription> typeDefinitions = Collections.emptyMap();public Representer() {this.representers.put(null, new RepresentJavaBean());}public Representer(DumperOptions options) {super(options);this.representers.put(null, new RepresentJavaBean());}public TypeDescription addTypeDescription(TypeDescription td) {if (Collections.EMPTY_MAP == this.typeDefinitions) {this.typeDefinitions = new HashMap();}if (td.getTag() != null) {this.addClassTag(td.getType(), td.getTag());}td.setPropertyUtils(this.getPropertyUtils());return (TypeDescription)this.typeDefinitions.put(td.getType(), td);}public void setPropertyUtils(PropertyUtils propertyUtils) {super.setPropertyUtils(propertyUtils);Collection<TypeDescription> tds = this.typeDefinitions.values();Iterator var3 = tds.iterator();while(var3.hasNext()) {TypeDescription typeDescription = (TypeDescription)var3.next();typeDescription.setPropertyUtils(propertyUtils);}}protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) {List<NodeTuple> value = new ArrayList(properties.size());Tag customTag = (Tag)this.classTags.get(javaBean.getClass());Tag tag = customTag != null ? customTag : new Tag(javaBean.getClass());MappingNode node = new MappingNode(tag, value, FlowStyle.AUTO);this.representedObjects.put(javaBean, node);DumperOptions.FlowStyle bestStyle = FlowStyle.FLOW;Iterator var8 = properties.iterator();while(true) {NodeTuple tuple;do {if (!var8.hasNext()) {if (this.defaultFlowStyle != FlowStyle.AUTO) {node.setFlowStyle(this.defaultFlowStyle);} else {node.setFlowStyle(bestStyle);}return node;}Property property = (Property)var8.next();Object memberValue = property.get(javaBean);Tag customPropertyTag = memberValue == null ? null : (Tag)this.classTags.get(memberValue.getClass());tuple = this.representJavaBeanProperty(javaBean, property, memberValue, customPropertyTag);} while(tuple == null);if (!((ScalarNode)tuple.getKeyNode()).isPlain()) {bestStyle = FlowStyle.BLOCK;}Node nodeValue = tuple.getValueNode();if (!(nodeValue instanceof ScalarNode) || !((ScalarNode)nodeValue).isPlain()) {bestStyle = FlowStyle.BLOCK;}value.add(tuple);}}protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) {ScalarNode nodeKey = (ScalarNode)this.representData(property.getName());boolean hasAlias = this.representedObjects.containsKey(propertyValue);Node nodeValue = this.representData(propertyValue);if (propertyValue != null && !hasAlias) {NodeId nodeId = nodeValue.getNodeId();if (customTag == null) {if (nodeId == NodeId.scalar) {if (property.getType() != Enum.class && propertyValue instanceof Enum) {nodeValue.setTag(Tag.STR);}} else {if (nodeId == NodeId.mapping && property.getType() == propertyValue.getClass() && !(propertyValue instanceof Map) && !nodeValue.getTag().equals(Tag.SET)) {nodeValue.setTag(Tag.MAP);}this.checkGlobalTag(property, nodeValue, propertyValue);}}}return new NodeTuple(nodeKey, nodeValue);}protected void checkGlobalTag(Property property, Node node, Object object) {if (!object.getClass().isArray() || !object.getClass().getComponentType().isPrimitive()) {Class<?>[] arguments = property.getActualTypeArguments();if (arguments != null) {Class t;Iterator iter;Iterator var9;if (node.getNodeId() == NodeId.sequence) {t = arguments[0];SequenceNode snode = (SequenceNode)node;Iterable<Object> memberList = Collections.emptyList();if (object.getClass().isArray()) {memberList = Arrays.asList((Object[])object);} else if (object instanceof Iterable) {memberList = (Iterable)object;}iter = ((Iterable)memberList).iterator();if (iter.hasNext()) {var9 = snode.getValue().iterator();while(var9.hasNext()) {Node childNode = (Node)var9.next();Object member = iter.next();if (member != null && t.equals(member.getClass()) && childNode.getNodeId() == NodeId.mapping) {childNode.setTag(Tag.MAP);}}}} else if (object instanceof Set) {t = arguments[0];MappingNode mnode = (MappingNode)node;Iterator<NodeTuple> ite = mnode.getValue().iterator();Set<?> set = (Set)object;var9 = set.iterator();while(var9.hasNext()) {Object member = var9.next();NodeTuple tuple = (NodeTuple)ite.next();Node keyNode = tuple.getKeyNode();if (t.equals(member.getClass()) && keyNode.getNodeId() == NodeId.mapping) {keyNode.setTag(Tag.MAP);}}} else if (object instanceof Map) {t = arguments[0];Class<?> valueType = arguments[1];MappingNode mnode = (MappingNode)node;iter = mnode.getValue().iterator();while(iter.hasNext()) {NodeTuple tuple = (NodeTuple)iter.next();this.resetTag(t, tuple.getKeyNode());this.resetTag(valueType, tuple.getValueNode());}}}}}private void resetTag(Class<? extends Object> type, Node node) {Tag tag = node.getTag();if (tag.matches(type)) {if (Enum.class.isAssignableFrom(type)) {node.setTag(Tag.STR);} else {node.setTag(Tag.MAP);}}}protected Set<Property> getProperties(Class<? extends Object> type) {return this.typeDefinitions.containsKey(type) ? ((TypeDescription)this.typeDefinitions.get(type)).getProperties() : this.getPropertyUtils().getProperties(type);}protected class RepresentJavaBean implements Represent {protected RepresentJavaBean() {}public Node representData(Object data) {return Representer.this.representJavaBean(Representer.this.getProperties(data.getClass()), data);}}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.yaml.snakeyaml.representer;import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.regex.Pattern;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.DumperOptions.NonPrintableStyle;
import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.reader.StreamReader;class SafeRepresenter extends BaseRepresenter {protected Map<Class<? extends Object>, Tag> classTags;protected TimeZone timeZone = null;protected DumperOptions.NonPrintableStyle nonPrintableStyle;private static final Pattern MULTILINE_PATTERN = Pattern.compile("\n|\u0085|\u2028|\u2029");public SafeRepresenter() {this(new DumperOptions());}public SafeRepresenter(DumperOptions options) {if (options == null) {throw new NullPointerException("DumperOptions must be provided.");} else {this.nullRepresenter = new RepresentNull();this.representers.put(String.class, new RepresentString());this.representers.put(Boolean.class, new RepresentBoolean());this.representers.put(Character.class, new RepresentString());this.representers.put(UUID.class, new RepresentUuid());this.representers.put(byte[].class, new RepresentByteArray());Represent primitiveArray = new RepresentPrimitiveArray();this.representers.put(short[].class, primitiveArray);this.representers.put(int[].class, primitiveArray);this.representers.put(long[].class, primitiveArray);this.representers.put(float[].class, primitiveArray);this.representers.put(double[].class, primitiveArray);this.representers.put(char[].class, primitiveArray);this.representers.put(boolean[].class, primitiveArray);this.multiRepresenters.put(Number.class, new RepresentNumber());this.multiRepresenters.put(List.class, new RepresentList());this.multiRepresenters.put(Map.class, new RepresentMap());this.multiRepresenters.put(Set.class, new RepresentSet());this.multiRepresenters.put(Iterator.class, new RepresentIterator());this.multiRepresenters.put((new Object[0]).getClass(), new RepresentArray());this.multiRepresenters.put(Date.class, new RepresentDate());this.multiRepresenters.put(Enum.class, new RepresentEnum());this.multiRepresenters.put(Calendar.class, new RepresentDate());this.classTags = new HashMap();this.nonPrintableStyle = options.getNonPrintableStyle();this.setDefaultScalarStyle(options.getDefaultScalarStyle());this.setDefaultFlowStyle(options.getDefaultFlowStyle());}}protected Tag getTag(Class<?> clazz, Tag defaultTag) {return this.classTags.containsKey(clazz) ? (Tag)this.classTags.get(clazz) : defaultTag;}public Tag addClassTag(Class<? extends Object> clazz, Tag tag) {if (tag == null) {throw new NullPointerException("Tag must be provided.");} else {return (Tag)this.classTags.put(clazz, tag);}}public TimeZone getTimeZone() {return this.timeZone;}public void setTimeZone(TimeZone timeZone) {this.timeZone = timeZone;}protected class RepresentUuid implements Represent {protected RepresentUuid() {}public Node representData(Object data) {return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), new Tag(UUID.class)), data.toString());}}protected class RepresentByteArray implements Represent {protected RepresentByteArray() {}public Node representData(Object data) {char[] binary = Base64Coder.encode((byte[])data);return SafeRepresenter.this.representScalar(Tag.BINARY, String.valueOf(binary), ScalarStyle.LITERAL);}}protected class RepresentEnum implements Represent {protected RepresentEnum() {}public Node representData(Object data) {Tag tag = new Tag(data.getClass());return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), tag), ((Enum)data).name());}}protected class RepresentDate implements Represent {protected RepresentDate() {}public Node representData(Object data) {Calendar calendar;if (data instanceof Calendar) {calendar = (Calendar)data;} else {calendar = Calendar.getInstance(SafeRepresenter.this.getTimeZone() == null ? TimeZone.getTimeZone("UTC") : SafeRepresenter.this.timeZone);calendar.setTime((Date)data);}int years = calendar.get(1);int months = calendar.get(2) + 1;int days = calendar.get(5);int hour24 = calendar.get(11);int minutes = calendar.get(12);int seconds = calendar.get(13);int millis = calendar.get(14);StringBuilder buffer = new StringBuilder(String.valueOf(years));while(buffer.length() < 4) {buffer.insert(0, "0");}buffer.append("-");if (months < 10) {buffer.append("0");}buffer.append(months);buffer.append("-");if (days < 10) {buffer.append("0");}buffer.append(days);buffer.append("T");if (hour24 < 10) {buffer.append("0");}buffer.append(hour24);buffer.append(":");if (minutes < 10) {buffer.append("0");}buffer.append(minutes);buffer.append(":");if (seconds < 10) {buffer.append("0");}buffer.append(seconds);if (millis > 0) {if (millis < 10) {buffer.append(".00");} else if (millis < 100) {buffer.append(".0");} else {buffer.append(".");}buffer.append(millis);}int gmtOffset = calendar.getTimeZone().getOffset(calendar.getTime().getTime());if (gmtOffset == 0) {buffer.append('Z');} else {if (gmtOffset < 0) {buffer.append('-');gmtOffset *= -1;} else {buffer.append('+');}int minutesOffset = gmtOffset / '\uea60';int hoursOffset = minutesOffset / 60;int partOfHour = minutesOffset % 60;if (hoursOffset < 10) {buffer.append('0');}buffer.append(hoursOffset);buffer.append(':');if (partOfHour < 10) {buffer.append('0');}buffer.append(partOfHour);}return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), Tag.TIMESTAMP), buffer.toString(), ScalarStyle.PLAIN);}}protected class RepresentSet implements Represent {protected RepresentSet() {}public Node representData(Object data) {Map<Object, Object> value = new LinkedHashMap();Set<Object> set = (Set)data;Iterator var4 = set.iterator();while(var4.hasNext()) {Object key = var4.next();value.put(key, (Object)null);}return SafeRepresenter.this.representMapping(SafeRepresenter.this.getTag(data.getClass(), Tag.SET), value, FlowStyle.AUTO);}}protected class RepresentMap implements Represent {protected RepresentMap() {}public Node representData(Object data) {return SafeRepresenter.this.representMapping(SafeRepresenter.this.getTag(data.getClass(), Tag.MAP), (Map)data, FlowStyle.AUTO);}}protected class RepresentPrimitiveArray implements Represent {protected RepresentPrimitiveArray() {}public Node representData(Object data) {Class<?> type = data.getClass().getComponentType();if (Byte.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asByteList(data), FlowStyle.AUTO);} else if (Short.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asShortList(data), FlowStyle.AUTO);} else if (Integer.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asIntList(data), FlowStyle.AUTO);} else if (Long.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asLongList(data), FlowStyle.AUTO);} else if (Float.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asFloatList(data), FlowStyle.AUTO);} else if (Double.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asDoubleList(data), FlowStyle.AUTO);} else if (Character.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asCharList(data), FlowStyle.AUTO);} else if (Boolean.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asBooleanList(data), FlowStyle.AUTO);} else {throw new YAMLException("Unexpected primitive '" + type.getCanonicalName() + "'");}}private List<Byte> asByteList(Object in) {byte[] array = (byte[])in;List<Byte> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Short> asShortList(Object in) {short[] array = (short[])in;List<Short> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Integer> asIntList(Object in) {int[] array = (int[])in;List<Integer> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Long> asLongList(Object in) {long[] array = (long[])in;List<Long> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Float> asFloatList(Object in) {float[] array = (float[])in;List<Float> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Double> asDoubleList(Object in) {double[] array = (double[])in;List<Double> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Character> asCharList(Object in) {char[] array = (char[])in;List<Character> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Boolean> asBooleanList(Object in) {boolean[] array = (boolean[])in;List<Boolean> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}}protected class RepresentArray implements Represent {protected RepresentArray() {}public Node representData(Object data) {Object[] array = (Object[])data;List<Object> list = Arrays.asList(array);return SafeRepresenter.this.representSequence(Tag.SEQ, list, FlowStyle.AUTO);}}private static class IteratorWrapper implements Iterable<Object> {private final Iterator<Object> iter;public IteratorWrapper(Iterator<Object> iter) {this.iter = iter;}public Iterator<Object> iterator() {return this.iter;}}protected class RepresentIterator implements Represent {protected RepresentIterator() {}public Node representData(Object data) {Iterator<Object> iter = (Iterator)data;return SafeRepresenter.this.representSequence(SafeRepresenter.this.getTag(data.getClass(), Tag.SEQ), new IteratorWrapper(iter), FlowStyle.AUTO);}}protected class RepresentList implements Represent {protected RepresentList() {}public Node representData(Object data) {return SafeRepresenter.this.representSequence(SafeRepresenter.this.getTag(data.getClass(), Tag.SEQ), (List)data, FlowStyle.AUTO);}}protected class RepresentNumber implements Represent {protected RepresentNumber() {}public Node representData(Object data) {Tag tag;String value;if (!(data instanceof Byte) && !(data instanceof Short) && !(data instanceof Integer) && !(data instanceof Long) && !(data instanceof BigInteger)) {Number number = (Number)data;tag = Tag.FLOAT;if (number.equals(Double.NaN)) {value = ".NaN";} else if (number.equals(Double.POSITIVE_INFINITY)) {value = ".inf";} else if (number.equals(Double.NEGATIVE_INFINITY)) {value = "-.inf";} else {value = number.toString();}} else {tag = Tag.INT;value = data.toString();}return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), tag), value);}}protected class RepresentBoolean implements Represent {protected RepresentBoolean() {}public Node representData(Object data) {String value;if (Boolean.TRUE.equals(data)) {value = "true";} else {value = "false";}return SafeRepresenter.this.representScalar(Tag.BOOL, value);}}protected class RepresentString implements Represent {protected RepresentString() {}public Node representData(Object data) {Tag tag = Tag.STR;DumperOptions.ScalarStyle style = SafeRepresenter.this.defaultScalarStyle;String value = data.toString();if (SafeRepresenter.this.nonPrintableStyle == NonPrintableStyle.BINARY && !StreamReader.isPrintable(value)) {tag = Tag.BINARY;byte[] bytes = value.getBytes(StandardCharsets.UTF_8);String checkValue = new String(bytes, StandardCharsets.UTF_8);if (!checkValue.equals(value)) {throw new YAMLException("invalid string value has occurred");}char[] binary = Base64Coder.encode(bytes);value = String.valueOf(binary);style = ScalarStyle.LITERAL;}if (SafeRepresenter.this.defaultScalarStyle == ScalarStyle.PLAIN && SafeRepresenter.MULTILINE_PATTERN.matcher(value).find()) {style = ScalarStyle.LITERAL;}return SafeRepresenter.this.representScalar(tag, value, style);}}protected class RepresentNull implements Represent {protected RepresentNull() {}public Node representData(Object data) {return SafeRepresenter.this.representScalar(Tag.NULL, "null");}}
}