Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
65b60e3
Backend: read-only columns, @Lob, CrudRepository bulk methods, produc…
shai-almog Nov 1, 2026
5ea06a9
JavaAPI: Semaphore, ConcurrentLinkedQueue, Flow, YearMonth, TemporalA…
shai-almog Nov 1, 2026
be764f6
backend-package: relocate java.util.regex and String regex calls onto…
shai-almog Nov 1, 2026
4ea2875
Backend: a logger facade with per-logger levels from configuration
shai-almog Nov 1, 2026
b8ce394
Backend: typed Json.read/readList/convert and Json.write through the …
shai-almog Nov 1, 2026
c0cecba
Backend: XML pull parser, element tree, property lists and image head…
shai-almog Nov 1, 2026
8fc7c9e
Backend: HTTP/2 on the JVM WebClient through java.net.http
shai-almog Nov 1, 2026
32e908e
Backend security: legacy recovery-code hashes, remember-me devices, c…
shai-almog Nov 1, 2026
400f32d
Backend: clear the static analysis findings and follow the security s…
shai-almog Nov 1, 2026
1418c70
Backend: refuse a typed long past the range and a wildcard Content-Type
shai-almog Nov 2, 2026
aa496a6
Backend: red-team fixes - per-table index names, body read deadline, …
shai-almog Nov 2, 2026
3007605
JavaAPI: refuse a dotted IPv4 part before :: and non-ASCII hex digits
shai-almog Nov 2, 2026
1c8e998
Docs: include the security table-name snippet from docs/demos
shai-almog Nov 2, 2026
5866191
Backend security: read the table names lazily so a server without sto…
shai-almog Nov 2, 2026
895e752
Docs: Vale wording in the security table-name section
shai-almog Nov 2, 2026
4024e09
ORM: @Column(collation), and accept a declared coarser @Temporal column
shai-almog Nov 3, 2026
56a6985
ORM: ElementCollection joinColumn and type; unwrap Hibernate-quoted n…
shai-almog Nov 3, 2026
7395012
Backend: the {sha256} encoder uses the shared Hash.toHex
shai-almog Nov 3, 2026
97391aa
Backend: share core com.codename1.xml, delete the backend's XML parser
shai-almog Nov 3, 2026
45d6c30
ORM: a PostgreSQL default collation is not a declared one; exact Post…
shai-almog Nov 3, 2026
7a9931e
Backend: one CivilTime helper for the UTC civil-date math
shai-almog Nov 3, 2026
6f8ecf8
Backend: JsonCodec and CronSchedule use CivilTime
shai-almog Nov 3, 2026
6b38fb7
XMLParser: restore setStrict semantics, put hardening behind setRejec…
shai-almog Nov 3, 2026
bc35111
Backend: call CivilTime directly; test Asn1 rejects a day past month end
shai-almog Nov 3, 2026
93eb63c
XMLParser: position tracking only when rejecting, I/O callback cannot…
shai-almog Nov 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/parparvm-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ on:
- 'CodenameOne/src/com/codename1/realtime/**'
- 'CodenameOne/src/com/codename1/qrcode/QrCode.java'
- 'CodenameOne/src/com/codename1/impl/MdnsEngine.java'
- 'CodenameOne/src/com/codename1/util/regex/**'
- 'CodenameOne/src/com/codename1/xml/**'
- 'CodenameOne/src/com/codename1/orm/session/**'
- 'CodenameOne/src/com/codename1/orm/repository/**'
- 'CodenameOne/src/com/codename1/annotations/db/**'
Expand Down Expand Up @@ -134,6 +136,8 @@ on:
- 'CodenameOne/src/com/codename1/realtime/**'
- 'CodenameOne/src/com/codename1/qrcode/QrCode.java'
- 'CodenameOne/src/com/codename1/impl/MdnsEngine.java'
- 'CodenameOne/src/com/codename1/util/regex/**'
- 'CodenameOne/src/com/codename1/xml/**'
- 'CodenameOne/src/com/codename1/orm/session/**'
- 'CodenameOne/src/com/codename1/orm/repository/**'
- 'CodenameOne/src/com/codename1/annotations/db/**'
Expand Down
24 changes: 24 additions & 0 deletions CodenameOne/src/com/codename1/annotations/Column.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,28 @@
/// engine spells differently (`TEXT`/`VARCHAR`, `REAL`/`DOUBLE PRECISION`,
/// `BLOB`/`BYTEA`).
String type() default "";
/// When false the column is left out of every `INSERT` the ORM writes, so the
/// row starts with the column's database default. The field's value at
/// insert time is ignored, not written.
boolean insertable() default true;
/// When false the column is left out of every `UPDATE` the ORM writes for a
/// changed entity, so a save never overwrites it. The column can still be
/// written by a query of the application's own -- a `@Modifying @Query` that
/// claims a row with a compare-and-swap, for example -- which is what makes
/// `insertable = false, updatable = false` a column only that statement owns.
/// A change made to the field alone is ignored: it neither writes the column
/// nor marks the entity dirty.
boolean updatable() default true;
/// The collation of the column, appended to its DDL as `COLLATE <name>`
/// (quoted on PostgreSQL), and the one the schema report then holds an
/// existing column to instead of requiring a case-sensitive key collation.
/// Letters, digits and underscores only, as `utf8mb4_0900_ai_ci` on MySQL,
/// `NOCASE` on SQLite or a collation created on PostgreSQL.
///
/// A case-insensitive collation on a key makes the database treat `"A"` and
/// `"a"` as one key. The session's identity cache still compares ids with
/// `String.equals`, so look an entity up by the spelling it is stored with:
/// another one finds the row but loads a second instance of it. Hibernate
/// has the same caveat.
String collation() default "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@
/// Names the scalar value column in the collection table.
/// @return column name; element_value by default
String column() default "element_value";
/// Names the column that holds the owner's id in the collection table.
/// Empty keeps `JoinTable.joinColumn` when that is set and `owner_id`
/// otherwise; naming the column in both places is a build error.
/// @return owner column name; empty for the default
String joinColumn() default "";
/// The SQL type of the value column, written into `CREATE TABLE` as it
/// is, like `Column.type` -- for example `LONGTEXT` -- and validated against
/// the existing column the same way.
/// @return SQL type; empty for the dialect's type for the element class
String type() default "";
/// Names the column that stores each element's position, which keys the
/// table together with the owner and keeps a List's order and duplicates.
///
Expand Down
41 changes: 41 additions & 0 deletions CodenameOne/src/com/codename1/annotations/db/Lob.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.annotations.db;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/// Marks a `String`, `char[]` or `byte[]` field as a large object, as JPA's
/// `@Lob` does.
///
/// It changes nothing about the column, because every string and byte column
/// is already one: MySQL gets `LONGTEXT` and `LONGBLOB`, and SQLite and
/// PostgreSQL leave `TEXT` and `BLOB`/`BYTEA` unbounded. It exists so an entity
/// ported from JPA keeps the annotation, and the build rejects it on a field of
/// any other type, as JPA would.
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
@com.codename1.impl.SharedWithBackend
public @interface Lob {
}
8 changes: 6 additions & 2 deletions CodenameOne/src/com/codename1/annotations/db/Temporal.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@
/// not change what is stored. A `TIMESTAMP WITH TIME ZONE` column is read with
/// the offset the server sends.
/// - Precision is the **millisecond**, which is all a Date holds. A column with
/// finer precision has the extra digits dropped on read; one with coarser
/// precision rounds or truncates on write, as that engine does.
/// finer precision has the extra digits dropped on read. A coarser column,
/// such as a plain MySQL `DATETIME`, is accepted only when the field declares
/// it, `@Column(type = "DATETIME")`: the declaration is the opt-in to losing
/// the milliseconds. The engine then rounds or truncates on write, as it does
/// for Hibernate, so on MySQL a value may read back one second later. MySQL's
/// `TIMESTAMP` is still refused, since it ends in 2038.
/// - On SQLite, which has no native date type, the value is text in the form
/// `2026-10-16 09:30:00.000`, which sorts in time order. Rows written in a
/// different textual form are read when they are ISO 8601, but compare as text
Expand Down
21 changes: 21 additions & 0 deletions CodenameOne/src/com/codename1/impl/orm/Attribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ public final class Attribute {
/// itself is TEXT storage through TemporalConverter; this picks the DDL type
/// and what an existing column may be.
public final int temporal;
/// False for `@Column(insertable = false)`: no INSERT names the column.
public final boolean insertable;
/// False for `@Column(updatable = false)`: no dirty-checking UPDATE names it.
public final boolean updatable;
/// Null, or the `@Column(collation)` name: the DDL appends it, and the
/// schema report holds the column to it instead of to a case-sensitive key
/// collation.
public final String collation;
/// The kind that decides SQL semantics -- collation, LIKE, the text
/// functions -- as opposed to [#kind], which decides how a value is bound and
/// read. A `@Temporal` column exchanges text through its converter but is a
Expand All @@ -68,6 +76,19 @@ public Attribute(String field, String column, int kind, boolean id, boolean gene
}
public Attribute(String field, String column, int kind, boolean id, boolean generated, boolean nullable,
boolean version, String declaredType, int temporal) {
this(field, column, kind, id, generated, nullable, version, declaredType, temporal, true, true);
}
public Attribute(String field, String column, int kind, boolean id, boolean generated, boolean nullable,
boolean version, String declaredType, int temporal, boolean insertable, boolean updatable) {
this(field, column, kind, id, generated, nullable, version, declaredType, temporal, insertable, updatable,
null);
}
public Attribute(String field, String column, int kind, boolean id, boolean generated, boolean nullable,
boolean version, String declaredType, int temporal, boolean insertable, boolean updatable,
String collation) {
this.collation = collation == null || collation.length() == 0 ? null : collation;
this.insertable = insertable;
this.updatable = updatable;
this.temporal = temporal;
this.declaredType = declaredType;
this.field = field;
Expand Down
9 changes: 9 additions & 0 deletions CodenameOne/src/com/codename1/impl/orm/Relationship.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public final class Relationship {
public final boolean orphanRemoval;
public final boolean unique;
public final boolean element;
/// The SQL type an element collection declares for its value column, empty for the default.
public final String elementType;
public final int column;
public final int cascade;
public static final int PERSIST = 1;
Expand Down Expand Up @@ -69,7 +71,14 @@ public Relationship(String field, Class target, boolean many, boolean lazy, int
public Relationship(String field, Class target, boolean many, boolean lazy, int column, String mappedBy,
String joinTable, String joinColumn, String inverseJoinColumn, int cascade, boolean orphanRemoval,
boolean unique, String mapKey, String orderColumn, String orderBy, boolean element) {
this(field, target, many, lazy, column, mappedBy, joinTable, joinColumn, inverseJoinColumn, cascade,
orphanRemoval, unique, mapKey, orderColumn, orderBy, element, "");
}
public Relationship(String field, Class target, boolean many, boolean lazy, int column, String mappedBy,
String joinTable, String joinColumn, String inverseJoinColumn, int cascade, boolean orphanRemoval,
boolean unique, String mapKey, String orderColumn, String orderBy, boolean element, String elementType) {
this.element = element;
this.elementType = elementType == null ? "" : elementType;
this.mapKey = mapKey;
this.orderColumn = orderColumn;
this.orderBy = orderBy;
Expand Down
Loading
Loading