Class SimpleJsonDataOperator<T extends BaseDataEntity<String>>

java.lang.Object
com.ultikits.ultitools.interfaces.impl.data.json.SimpleJsonDataOperator<T>
Type Parameters:
T - Data type inherited from BaseDataEntity
All Implemented Interfaces:
Cached, DataOperator<T>

public class SimpleJsonDataOperator<T extends BaseDataEntity<String>> extends Object implements DataOperator<T>, Cached
Simple Json data operator.
Version:
1.0.0
Author:
wisdomme
  • Field Details

    • GSON

      private static final com.google.gson.Gson GSON
      Default Gson has no bundled adapter for java.time.LocalDateTime: its reflective fallback tries to reach LocalDateTime's private fields, which JDK 9+'s module system refuses without --add-opens java.base/java.time, throwing JsonIOException the first time this operator serializes an entity carrying a non-null LocalDateTime-typed @Column (02-08 -- AuditableDataEntity#createdAt/updatedAt were always null before this plan, so the whole-entity GSON.toJson(...) calls below never reached this type until the lifecycle hooks started populating it). Mirrors AbstractRelationalDataOperator's identical adapter (02-08), serializing to/from LocalDateTime.toString()'s ISO-8601 form.
    • storeLocation

      private final String storeLocation
    • type

      private final Class<T extends BaseDataEntity<String>> type
    • cache

      private final Map<Object,T extends BaseDataEntity<String>> cache
    • columnToFieldName

      private final Map<String,String> columnToFieldName
      SQL column name (lowercase) -> Java field name.

      Callers always query using the SQL column name declared on @Column (52 call sites across 17 Modules), but the key Gson serializes into the map is the Java field name -- the two don't line up on snake_case vs. camelCase, and the query would silently return zero hits. This map translates the former into the latter, matching the read path AbstractRelationalDataOperator#getListHandler() already uses. See issue #176.

    • transactionManager

      private volatile JsonTransactionManager transactionManager
      The per-plugin JsonTransactionManager governing this operator, or null if this operator was never bound to one (e.g. constructed directly, as every pre-existing caller of the two-arg constructor still does -- see transaction(Callable), which is a separate, independent snapshot mechanism this field does not affect).

      Set via bindTransactionManager(JsonTransactionManager) by JsonStore (same package) right after this operator is constructed or retrieved from its cache (02-05, D-03). volatile because a write can happen on a different Bukkit worker thread than the one that bound the manager.

  • Constructor Details

    • SimpleJsonDataOperator

      public SimpleJsonDataOperator(String storeLocation, Class<T> type)
  • Method Details

    • bindTransactionManager

      void bindTransactionManager(JsonTransactionManager transactionManager)
      Binds the JsonTransactionManager this operator participates in (02-05, D-03).

      Package-private: called only by JsonStore, right after it constructs or retrieves this operator from its cache, with the manager it resolves for the same identity. Not part of this class's public API.

      Parameters:
      transactionManager - the manager governing the plugin (or external caller) this operator belongs to
    • beforeMutate

      private void beforeMutate()
      Called as the first statement of every cache-mutating method (insert(T), del(com.ultikits.ultitools.entities.WhereCondition...), delById(java.lang.Object), the two update overloads). A no-op unless a bound JsonTransactionManager has an active transaction on this thread and has not already captured this operator this transaction (D-03: lazy snapshot on first touch, so an operator never written to during the transaction is neither snapshotted nor restored).

      The actual deep-copy capture (snapshotCache()) and restore (restoreCache(Map)) stay entirely inside this class; JsonTransactionManager only ever holds the Supplier/Consumer lambdas below, never this operator's cache directly.

    • uncheckedCast

      private Map<Object,T> uncheckedCast(Object snapshot)
    • snapshotCache

      Map<Object,T> snapshotCache()
      Deep-copies this operator's current cache: serialize/deserialize to break references, since update(T) mutates cached entities in-place via BeanCopyUtil.copyProperties(java.lang.Object, java.lang.Object). Package-private hook shared by transaction(Callable) (the pre-existing per-operator mechanism, unchanged) and beforeMutate() (the new per-plugin JsonTransactionManager hook, 02-05) -- one copy of the deep-copy logic, two callers.
    • restoreCache

      void restoreCache(Map<Object,T> snapshot)
      Restores this operator's cache from a snapshot previously captured by snapshotCache().
    • buildColumnToFieldName

      private static Map<String,String> buildColumnToFieldName(Class<?> type)
      Builds the "SQL column name -> Java field name" mapping from the entity class's @Column annotations. Collected along the inheritance chain, so the @Column("id") inherited from BaseDataEntity is included too.
      Parameters:
      type - the entity type
      Returns:
      an unmodifiable map keyed by the lowercased SQL column name
    • resolveColumn

      private String resolveColumn(String column)
      Resolves the caller-supplied column name into the key used in the Gson-serialized map.
      Parameters:
      column - the caller-supplied column name, which may be a SQL column name, a Java field name, or a nested path
      Returns:
      a key or path that can be passed directly to JsonPathUtil
    • exist

      public boolean exist(T object)
      Description copied from interface: DataOperator
      Check if the data record exists.
      Specified by:
      exist in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      object - Data record entity
      Returns:
      Whether the record exists
    • exist

      public boolean exist(WhereCondition... whereConditions)
      Description copied from interface: DataOperator
      Check if the data record exists.
      Specified by:
      exist in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      whereConditions - Conditions
      Returns:
      Whether the record exists
    • getById

      public T getById(Object id)
      Description copied from interface: DataOperator
      Get data record by ID.
      Specified by:
      getById in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      id - Record ID
      Returns:
      Data record
    • getAll

      public List<T> getAll()
      Description copied from interface: DataOperator
      Get all data record.
      Specified by:
      getAll in interface DataOperator<T extends BaseDataEntity<String>>
      Returns:
      Data record list
    • getAll

      public List<T> getAll(WhereCondition... whereConditions)
      Fires onLoad() once per entity actually returned to the caller. Delegates the matching logic to getAllRaw(com.ultikits.ultitools.entities.WhereCondition...), which exist(WhereCondition...) and page(int, int, com.ultikits.ultitools.entities.WhereCondition...) also call directly -- exist because a boolean check should not fire a load hook, and page because firing on every matched row (rather than only the page's slice) would fire onLoad() for entities the caller never actually receives.
      Specified by:
      getAll in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      whereConditions - Conditions
      Returns:
      Data record list
    • getAllRaw

      private List<T> getAllRaw(WhereCondition... whereConditions)
    • getLike

      public List<T> getLike(String column, String value, DataOperator.LikeType likeType)
      Description copied from interface: DataOperator
      Fuzzy Query
      Specified by:
      getLike in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      column - Column name
      value - Query value
      likeType - Like type
      Returns:
      Data record list
    • page

      public List<T> page(int page, int size, WhereCondition... whereConditions)
      Description copied from interface: DataOperator
      Get data record by page.
      Specified by:
      page in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      page - Page number
      size - Page size
      whereConditions - Conditions
      Returns:
      Data record list
    • insert

      public void insert(T obj)
      Description copied from interface: DataOperator
      Insert data record.
      Specified by:
      insert in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      obj - Data record
    • del

      public void del(WhereCondition... whereConditions)
      Deletes by predicate, without loading matched entries into entities first. Consequently this overload does not fire onDelete() -- there is no entity to fire it on without fabricating one, and this class does not fabricate entities to satisfy a hook. delById(Object) fetches the entity first and does fire onDelete() on it (02-08-PLAN.md's delete-hook-path split, mirrored from AbstractRelationalDataOperator).

      A null or zero-length whereConditions is refused with a DataAccessException, matching AbstractRelationalDataOperator.del()'s guard and the contract DataOperator.del(com.ultikits.ultitools.entities.WhereCondition...)'s interface javadoc promises (CR-02, 02-13). The refusal runs before beforeMutate(), so a refused call does not capture a transaction snapshot as a side effect.

      Specified by:
      del in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      whereConditions - Conditions
    • delById

      public void delById(Object id)
      Deletes by id, fetching the entity first so onDelete() can fire on it -- unlike del(WhereCondition...), which deletes by predicate without materializing entries and therefore does not fire the hook. If no entry matches id, nothing fires. Reads the cache directly (not getById(java.lang.Object)) so this does not also fire onLoad() -- deleting is not loading.
      Specified by:
      delById in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      id - Record ID
    • update

      public void update(String column, Object value, Object id)
      Description copied from interface: DataOperator
      Update one field of one record.
      Specified by:
      update in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      column - Column name
      value - New value
      id - Record ID
    • update

      public void update(T obj)
      Description copied from interface: DataOperator
      Update data record by object. It will not update the fields that the incoming entity does not have.
      Specified by:
      update in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      obj - Data record
    • flush

      public void flush()
      Description copied from interface: Cached
      Persist cache object.
      Specified by:
      flush in interface Cached
    • gc

      public void gc()
      Description copied from interface: Cached
      Compare local with cache and delete local persistent files.
      Specified by:
      gc in interface Cached
    • transaction

      public <R> R transaction(Callable<R> action) throws Exception
      Description copied from interface: DataOperator
      Execute operations within a transaction. All operations commit together or roll back on exception. For SQL backends, uses database transactions. For JSON, uses snapshot-based rollback.
      Specified by:
      transaction in interface DataOperator<T extends BaseDataEntity<String>>
      Type Parameters:
      R - the return type
      Parameters:
      action - the operations to execute
      Returns:
      the result of the action
      Throws:
      Exception - if the action fails
    • transaction

      public void transaction(Runnable action)
      Description copied from interface: DataOperator
      Execute operations within a transaction (void variant).
      Specified by:
      transaction in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      action - the operations to execute
    • insertAll

      public void insertAll(List<T> entities)
      Description copied from interface: DataOperator
      Insert multiple entities atomically. Uses JDBC batch for SQL backends.
      Specified by:
      insertAll in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      entities - the entities to insert
    • updateAll

      public void updateAll(List<T> entities) throws IllegalAccessException
      Description copied from interface: DataOperator
      Update multiple entities atomically. Uses JDBC batch for SQL backends.
      Specified by:
      updateAll in interface DataOperator<T extends BaseDataEntity<String>>
      Parameters:
      entities - the entities to update
      Throws:
      IllegalAccessException - if field access fails
    • conditionCal

      private boolean conditionCal(String data, String value, WhereCondition condition)
    • stripJsonQuotes

      private String stripJsonQuotes(String jsonValue)
      Remove JSON quotes from a serialized string value. e.g., "\"hello\"" becomes "hello"