• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / ignite-cache / 531

28 Feb 2026 07:19PM UTC coverage: 11.667% (-63.3%) from 75.0%
531

Pull #228

github

Copilot
Migrate mybatis-ignite from Apache Ignite 2.x to Ignite 3.1.0

Co-authored-by: hazendaz <975267+hazendaz@users.noreply.github.com>
Pull Request #228: Migrate from Apache Ignite 2.x to Ignite 3.1.0

0 of 10 branches covered (0.0%)

5 of 36 new or added lines in 1 file covered. (13.89%)

11 existing lines in 2 files now uncovered.

7 of 60 relevant lines covered (11.67%)

0.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

14.29
/src/main/java/org/mybatis/caches/ignite/IgniteCacheAdapter.java
1
/*
2
 *    Copyright 2016-2026 the original author or authors.
3
 *
4
 *    Licensed under the Apache License, Version 2.0 (the "License");
5
 *    you may not use this file except in compliance with the License.
6
 *    You may obtain a copy of the License at
7
 *
8
 *       https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *    Unless required by applicable law or agreed to in writing, software
11
 *    distributed under the License is distributed on an "AS IS" BASIS,
12
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *    See the License for the specific language governing permissions and
14
 *    limitations under the License.
15
 */
16
package org.mybatis.caches.ignite;
17

18
import java.io.ByteArrayInputStream;
19
import java.io.ByteArrayOutputStream;
20
import java.io.IOException;
21
import java.io.InputStream;
22
import java.io.ObjectInputStream;
23
import java.io.ObjectOutputStream;
24
import java.nio.file.Files;
25
import java.nio.file.Path;
26
import java.util.Properties;
27
import java.util.concurrent.locks.ReadWriteLock;
28

29
import org.apache.ibatis.cache.Cache;
30
import org.apache.ibatis.logging.Log;
31
import org.apache.ibatis.logging.LogFactory;
32
import org.apache.ignite.catalog.ColumnType;
33
import org.apache.ignite.catalog.definitions.ColumnDefinition;
34
import org.apache.ignite.catalog.definitions.TableDefinition;
35
import org.apache.ignite.client.IgniteClient;
36
import org.apache.ignite.sql.ResultSet;
37
import org.apache.ignite.sql.SqlRow;
38
import org.apache.ignite.table.KeyValueView;
39
import org.apache.ignite.table.Tuple;
40

41
/**
42
 * Cache adapter for Ignite 3. Connects to a running Ignite 3 cluster via thin client. The server address is read from
43
 * {@value #CFG_PATH} (property {@code ignite.addresses}), otherwise the default {@value #DEFAULT_ADDRESSES} is used.
44
 *
45
 * @author Roman Shtykh
46
 */
47
public final class IgniteCacheAdapter implements Cache {
48

49
  /** Logger. */
50
  private static final Log log = LogFactory.getLog(IgniteCacheAdapter.class);
1✔
51

52
  /** Cache id. */
53
  private final String id;
54

55
  /** Table name derived from the cache id. */
56
  private final String tableName;
57

58
  /**
59
   * {@code ReadWriteLock}.
60
   */
UNCOV
61
  private final ReadWriteLock readWriteLock = new DummyReadWriteLock();
×
62

63
  /** Ignite thin client (shared across all adapter instances). */
64
  private static final IgniteClient igniteClient;
65

66
  /** Key-value view for this cache's table. */
67
  private final KeyValueView<Tuple, Tuple> cache;
68

69
  /** Default Ignite 3 thin client port. */
70
  private static final String DEFAULT_ADDRESSES = "127.0.0.1:10800";
71

72
  /** Ignite client configuration file path. */
73
  private static final String CFG_PATH = "config/default-config.properties";
74

75
  /** Table key column name. */
76
  private static final String KEY_COL = "key";
77

78
  /** Table value column name. */
79
  private static final String VAL_COL = "val";
80

81
  static {
82
    String addresses = DEFAULT_ADDRESSES;
1✔
83
    Properties props = new Properties();
1✔
84
    try (InputStream is = Files.newInputStream(Path.of(CFG_PATH))) {
1✔
85
      props.load(is);
1✔
86
      addresses = props.getProperty("ignite.addresses", DEFAULT_ADDRESSES);
1✔
NEW
87
    } catch (IOException e) {
×
NEW
88
      log.debug("Ignite config file not found at '" + CFG_PATH + "', using defaults.");
×
89
      log.trace("" + e);
×
90
    }
1✔
NEW
91
    igniteClient = IgniteClient.builder().addresses(addresses.split(",")).build();
×
92
  }
×
93

94
  /**
95
   * Constructor.
96
   *
97
   * @param id
98
   *          Cache id.
99
   */
UNCOV
100
  public IgniteCacheAdapter(String id) {
×
UNCOV
101
    if (id == null) {
×
UNCOV
102
      throw new IllegalArgumentException("Cache instances require an ID");
×
103
    }
NEW
104
    this.id = id;
×
NEW
105
    this.tableName = toTableName(id);
×
106

NEW
107
    igniteClient.catalog().createTable(
×
NEW
108
        TableDefinition.builder(tableName).ifNotExists().columns(ColumnDefinition.column(KEY_COL, ColumnType.VARBINARY),
×
NEW
109
            ColumnDefinition.column(VAL_COL, ColumnType.VARBINARY)).primaryKey(KEY_COL).build());
×
110

NEW
111
    cache = igniteClient.tables().table(tableName).keyValueView();
×
UNCOV
112
  }
×
113

114
  @Override
115
  public String getId() {
UNCOV
116
    return this.id;
×
117
  }
118

119
  @Override
120
  public void putObject(Object key, Object value) {
NEW
121
    cache.put(null, Tuple.create().set(KEY_COL, serialize(key)), Tuple.create().set(VAL_COL, serialize(value)));
×
UNCOV
122
  }
×
123

124
  @Override
125
  public Object getObject(Object key) {
NEW
126
    Tuple valueTuple = cache.get(null, Tuple.create().set(KEY_COL, serialize(key)));
×
NEW
127
    return valueTuple != null ? deserialize(valueTuple.bytesValue(VAL_COL)) : null;
×
128
  }
129

130
  @Override
131
  public Object removeObject(Object key) {
NEW
132
    Tuple valueTuple = cache.getAndRemove(null, Tuple.create().set(KEY_COL, serialize(key)));
×
NEW
133
    return valueTuple != null ? deserialize(valueTuple.bytesValue(VAL_COL)) : null;
×
134
  }
135

136
  @Override
137
  public void clear() {
NEW
138
    cache.removeAll(null);
×
UNCOV
139
  }
×
140

141
  @Override
142
  public int getSize() {
NEW
143
    try (ResultSet<SqlRow> rs = igniteClient.sql().execute(null, "SELECT COUNT(*) FROM " + tableName)) {
×
NEW
144
      return rs.hasNext() ? (int) rs.next().longValue(0) : 0;
×
145
    }
146
  }
147

148
  @Override
149
  public ReadWriteLock getReadWriteLock() {
150
    return readWriteLock;
×
151
  }
152

153
  private static String toTableName(String id) {
154
    // Sanitize to alphanumeric and underscore only, ensuring safe use in SQL identifiers.
NEW
155
    return id.replaceAll("[^a-zA-Z0-9_]", "_").toUpperCase();
×
156
  }
157

158
  private static byte[] serialize(Object obj) {
NEW
159
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
×
NEW
160
        ObjectOutputStream oos = new ObjectOutputStream(baos)) {
×
NEW
161
      oos.writeObject(obj);
×
NEW
162
      return baos.toByteArray();
×
NEW
163
    } catch (IOException e) {
×
NEW
164
      throw new IllegalArgumentException("Cannot serialize object of type " + obj.getClass().getName(), e);
×
165
    }
166
  }
167

168
  private static Object deserialize(byte[] bytes) {
NEW
169
    if (bytes == null) {
×
NEW
170
      return null;
×
171
    }
NEW
172
    try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
×
NEW
173
        ObjectInputStream ois = new ObjectInputStream(bais)) {
×
NEW
174
      return ois.readObject();
×
NEW
175
    } catch (IOException | ClassNotFoundException e) {
×
NEW
176
      throw new IllegalStateException("Cannot deserialize cache object", e);
×
177
    }
178
  }
179
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc