一、创建库表
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 {
-
- @TableId
- private Long buyerId;
- private String buyerName;
- private Boolean sex;
- private Integer age;
-
- }
- @Builder
- @Data
- @TableName("tb_order")
- public class TbOrder {
-
- @TableId
- private Long orderId;
- private Long buyerId;
- private Long sellerId;
- private String orderName;
- private BigDecimal price;
-
- }
- @Builder
- @Data
- @TableName("tb_seller")
- public class TbSeller {
-
- @TableId
- private 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 {
-
- @Resource
- private TbBuyerMapper tbBuyerMapper ;
- @Resource
- private TbSellerMapper tbSellerMapper ;
- @Resource
- private TbOrderMapper tbOrderMapper ;
-
- /**
- * 查询订单详情
- */
- @GetMapping("/order/info/{orderId}")
- public Map
orderInfo (@PathVariable Long orderId){ - Map
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生成失败。
- */
- @Override
- public void run(ApplicationArguments args) throws Exception {
- //初始化workId
- initWorkId();
-
- 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方法获取唯一ID
- return this.snowFlake.nextId();
- }
-
- /**
- * 生成基于Snowflake算法的唯一ID。
- *
- * 使用Snowflake算法生成唯一的分布式ID。该算法由Twitter提出,通过组合时间戳、工作机器ID和序列号来生成全局唯一的ID。
- * 具体结构如下:
- * - 1位符号位,用于区分正负,由于ID只能是正数,所以这个位始终为0。
- * - 41位时间戳,精确到毫秒,可以使用约69年。
- * - 10位工作机器ID,可以部署在1024个节点,包括5位数据中心ID和5位工作机器ID。
- * - 12位序列号,用于同一毫秒内生成的ID去重,每个节点每毫秒可以生成4096个ID。
- *
- * 参数:
- * workerId - 工作机器ID,用于标识不同的工作机器或进程。
- * datacenterId - 数据中心ID,用于标识不同的数据中心。
- *
- * 返回:
- * 一个长整型的唯一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{
-
- @Autowired
- private SnowFlakeProvider snowFlakeProvider;
-
- @Autowired
- private TbOrderMapper tbOrderMapper ;
-
- /**
- * 写入100条数据
- */
- @Test
- public 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);
- }
-
- @Test
- public void testOrderQuery (){
- TbOrder order = tbOrderMapper.selectById(5) ;
- Assert.assertNotNull(order);
- log.info("查询结果:"+ JSONUtil.toJsonStr(order));
- }
-
- @Test
- public void testOrderUpdate (){
- TbOrder order = tbOrderMapper.selectById(3) ;
- Assert.assertNotNull(order);
- order.setBuyerId(1l);
- order.setSellerId(3l);
- int count = tbOrderMapper.updateById(order) ;
- log.info("更新记录数:"+count);
- }
-
- @Test
- public 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: 8095
-
- spring:
- application:
- name: dynamic-datasource-spring-boot-starter
- shardingsphere:
- mode:
- type: Standalone
- repository:
- type: JDBC
- database:
- name: db0
- # 数据源配置
- datasource:
- # 数据源名称,多数据源以逗号分隔
- names: db0,db1
- db0:
- type: com.zaxxer.hikari.HikariDataSource
- driver-class-name: com.mysql.cj.jdbc.Driver
- jdbc-url: jdbc:mysql://xx:3306/shard_db_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
- username: xx
- password: xx
- db1:
- type: com.zaxxer.hikari.HikariDataSource
- driver-class-name: com.mysql.cj.jdbc.Driver
- jdbc-url: jdbc:mysql://xx:3306/shard_db_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
- username: xx
- password: xx
- # 分片规则配置
- rules:
- sharding:
- # 分片算法配置
- sharding-algorithms:
- database-inline:
- # 分片算法类型
- type: INLINE
- props:
- # 分片算法的行表达式(算法自行定义,此处为方便演示效果)
- algorithm-expression: db${order_id % 2}
- table-inline:
- # 分片算法类型
- type: INLINE
- props:
- # 分片算法的行表达式
- 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: true
-
- mybatis-plus:
- type-aliases-package: com.example.dynamic.po
- configuration:
- map-underscore-to-camel-case: true
- log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
- mapper-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
解答:该问题是由于版本问题导致的,是个兼容性问题。
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");
- }
- }
- }