Skip to content

Commit aafb59e

Browse files
authored
Merge pull request #37 from JavaWebStack/dev
Release 1.0.2
2 parents 4126d21 + a0a1548 commit aafb59e

25 files changed

+400
-141
lines changed

pom.xml

+24-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<properties>
88
<maven.compiler.source>8</maven.compiler.source>
99
<maven.compiler.target>8</maven.compiler.target>
10-
<buildVersion>1.0.1-SNAPSHOT</buildVersion>
10+
<buildVersion>1.0.2-SNAPSHOT</buildVersion>
1111
</properties>
1212

1313
<groupId>org.javawebstack</groupId>
@@ -32,6 +32,18 @@
3232
<organization>JavaWebStack</organization>
3333
<organizationUrl>https://javawebstack.org</organizationUrl>
3434
</developer>
35+
<developer>
36+
<name>Timothy Gillespie</name>
37+
<email>timothy@gillespie.eu</email>
38+
<organization>JavaWebStack</organization>
39+
<organizationUrl>https://javawebstack.org</organizationUrl>
40+
</developer>
41+
<developer>
42+
<name>Julian Gojani</name>
43+
<email>julian@gojani.xyz</email>
44+
<organization>JavaWebStack</organization>
45+
<organizationUrl>https://javawebstack.org</organizationUrl>
46+
</developer>
3547
</developers>
3648

3749
<scm>
@@ -44,8 +56,15 @@
4456
<dependency>
4557
<groupId>org.javawebstack</groupId>
4658
<artifactId>abstract-data</artifactId>
47-
<version>1.0.0</version>
59+
<version>1.0.4</version>
60+
</dependency>
61+
<!--- Temporary fix for transitive vulnerabilities -->
62+
<dependency>
63+
<groupId>org.yaml</groupId>
64+
<artifactId>snakeyaml</artifactId>
65+
<version>1.33</version>
4866
</dependency>
67+
<!--- ============================================ -->
4968
<dependency>
5069
<groupId>org.atteo</groupId>
5170
<artifactId>evo-inflector</artifactId>
@@ -59,7 +78,7 @@
5978
<dependency>
6079
<groupId>org.junit.jupiter</groupId>
6180
<artifactId>junit-jupiter-engine</artifactId>
62-
<version>5.8.1</version>
81+
<version>5.9.0</version>
6382
<scope>test</scope>
6483
</dependency>
6584
<dependency>
@@ -71,13 +90,13 @@
7190
<dependency>
7291
<groupId>org.projectlombok</groupId>
7392
<artifactId>lombok</artifactId>
74-
<version>1.18.22</version>
93+
<version>1.18.24</version>
7594
<scope>test</scope>
7695
</dependency>
7796
<dependency>
7897
<groupId>mysql</groupId>
7998
<artifactId>mysql-connector-java</artifactId>
80-
<version>8.0.27</version>
99+
<version>8.0.30</version>
81100
<scope>test</scope>
82101
</dependency>
83102
</dependencies>
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package org.javawebstack.orm;
22

33
import org.javawebstack.orm.query.Query;
4+
import org.javawebstack.orm.query.QueryGroup;
45

56
public interface Accessible {
6-
<T extends Model> Query<T> access(Query<T> query, Object accessor);
7+
<T extends Model> QueryGroup<T> access(Query<T> query, QueryGroup<T> accessChecks, Object accessor);
78
}

src/main/java/org/javawebstack/orm/Repo.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
import java.util.List;
1818
import java.util.Map;
1919
import java.util.UUID;
20-
import java.util.function.Function;
21-
import java.util.stream.Stream;
2220

2321
public class Repo<T extends Model> {
2422

@@ -73,11 +71,11 @@ public Query<T> whereId(Object right) {
7371
}
7472

7573
public Query<T> accessible(Object accessor) {
76-
return accessible(query(), accessor);
74+
return query().accessible(accessor);
7775
}
7876

79-
public Query<T> accessible(Query<T> query, Object accessor) {
80-
return accessible == null ? query : accessible.access(query, accessor);
77+
public Accessible getAccessible() {
78+
return accessible;
8179
}
8280

8381
public void save(T entry) {
@@ -122,6 +120,7 @@ private void executeCreate(T entry) {
122120
map.remove(idCol);
123121
}
124122
SQLQueryString qs = getConnection().builder().buildInsert(info, map);
123+
SQL connection = Session.current() != null ? Session.current().getConnection() : this.connection;
125124
int id = connection.write(qs.getQuery(), qs.getParameters().toArray());
126125
if (info.isAutoIncrement())
127126
info.getField(info.getIdField()).set(entry, id);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.javawebstack.orm;
2+
3+
import org.javawebstack.orm.wrapper.SQL;
4+
5+
import java.util.function.Consumer;
6+
7+
public class Session {
8+
9+
private static ThreadLocal<Session> sessions = new ThreadLocal<>();
10+
11+
public static Session current() {
12+
return sessions.get();
13+
}
14+
15+
private SQL connection;
16+
17+
private Session() {
18+
19+
}
20+
21+
public Session via(SQL connection) {
22+
this.connection = connection;
23+
return this;
24+
}
25+
26+
public SQL getConnection() {
27+
return connection;
28+
}
29+
30+
public static void session(Consumer<Session> consumer) {
31+
Session session = begin();
32+
consumer.accept(session);
33+
end();
34+
}
35+
36+
public static Session begin() {
37+
Session session = new Session();
38+
sessions.set(session);
39+
return session;
40+
}
41+
42+
public static void end() {
43+
sessions.remove();
44+
}
45+
46+
}

src/main/java/org/javawebstack/orm/TableInfo.java

+52-28
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import org.javawebstack.orm.util.Helper;
77
import org.javawebstack.orm.util.KeyType;
88

9-
import java.lang.reflect.Array;
109
import java.lang.reflect.Constructor;
1110
import java.lang.reflect.Field;
1211
import java.lang.reflect.Modifier;
@@ -29,7 +28,7 @@ public class TableInfo {
2928
private final Class<? extends Model> modelClass;
3029
private String primaryKey;
3130
private final List<String> uniqueKeys = new ArrayList<>();
32-
private final Constructor<?> constructor;
31+
private Constructor<?> constructor;
3332
private String relationField;
3433
private final Map<String, String> filterable = new HashMap<>();
3534
private final List<String> searchable = new ArrayList<>();
@@ -42,6 +41,36 @@ public class TableInfo {
4241
public TableInfo(Class<? extends Model> model, ORMConfig config) throws ORMConfigurationException {
4342
this.config = config;
4443
this.modelClass = model;
44+
45+
Stack<Class<?>> superClasses = Helper.getSuperClassesTill(model, Model.class);
46+
while (!superClasses.isEmpty()) {
47+
Class<? extends Model> superClass = (Class<? extends Model>) superClasses.pop();
48+
if (Modifier.isAbstract(superClass.getModifiers())) {
49+
analyzeColumns(superClass);
50+
} else {
51+
throw new ORMConfigurationException("The parent model has to be abstract!");
52+
}
53+
}
54+
55+
constructInfo(model);
56+
}
57+
58+
private void constructInfo (Class<? extends Model> model) throws ORMConfigurationException {
59+
analyzeColumns(model);
60+
analyzeTable(model);
61+
62+
if (!fields.containsKey(idField))
63+
idField = "uuid";
64+
if (!fields.containsKey(idField))
65+
throw new ORMConfigurationException("No id field found!");
66+
67+
if (config.isIdPrimaryKey()) {
68+
if (primaryKey == null)
69+
primaryKey = idField;
70+
}
71+
}
72+
73+
private void analyzeTable(Class<? extends Model> model) throws ORMConfigurationException {
4574
if (model.isAnnotationPresent(Table.class)) {
4675
Table table = model.getDeclaredAnnotationsByType(Table.class)[0];
4776
tableName = table.value();
@@ -59,6 +88,26 @@ public TableInfo(Class<? extends Model> model, ORMConfig config) throws ORMConfi
5988
} catch (NoSuchMethodException e) {
6089
throw new ORMConfigurationException("The model class has no empty constructor!");
6190
}
91+
if (model.isAnnotationPresent(RelationField.class)) {
92+
relationField = model.getDeclaredAnnotationsByType(RelationField.class)[0].value();
93+
} else {
94+
relationField = Helper.pascalToCamelCase(model.getSimpleName()) + ((getIdType().equals(UUID.class) && !idField.equalsIgnoreCase("id")) ? "UUID" : "Id");
95+
}
96+
if (model.isAnnotationPresent(SoftDelete.class)) {
97+
softDelete = model.getDeclaredAnnotationsByType(SoftDelete.class)[0];
98+
if (!fields.containsKey(softDelete.value()))
99+
throw new ORMConfigurationException("Missing soft-delete field '" + softDelete.value() + "'");
100+
}
101+
if (model.isAnnotationPresent(Dates.class)) {
102+
dates = model.getDeclaredAnnotationsByType(Dates.class)[0];
103+
if (!fields.containsKey(dates.create()))
104+
throw new ORMConfigurationException("Missing dates field '" + dates.create() + "'");
105+
if (!fields.containsKey(dates.update()))
106+
throw new ORMConfigurationException("Missing dates field '" + dates.update() + "'");
107+
}
108+
}
109+
110+
private void analyzeColumns(Class<? extends Model> model) throws ORMConfigurationException {
62111
for (Field field : model.getDeclaredFields()) {
63112
if (Modifier.isStatic(field.getModifiers()))
64113
continue;
@@ -82,7 +131,7 @@ public TableInfo(Class<? extends Model> model, ORMConfig config) throws ORMConfi
82131
else
83132
fieldSize = fieldConfig.size();
84133

85-
SQLType sqlType = config.getType(field.getType(), fieldSize);
134+
SQLType sqlType = config.getType(field.getType(), fieldSize);
86135
if (sqlType != null) {
87136
sqlTypes.put(fieldName, sqlType);
88137
sqlTypeParameters.put(fieldName, config.getTypeParameters(field.getType(), fieldSize));
@@ -106,31 +155,6 @@ public TableInfo(Class<? extends Model> model, ORMConfig config) throws ORMConfi
106155
if (field.isAnnotationPresent(Searchable.class))
107156
this.searchable.add(fieldName);
108157
}
109-
if (!fields.containsKey(idField))
110-
idField = "uuid";
111-
if (!fields.containsKey(idField))
112-
throw new ORMConfigurationException("No id field found!");
113-
if (model.isAnnotationPresent(RelationField.class)) {
114-
relationField = model.getDeclaredAnnotationsByType(RelationField.class)[0].value();
115-
} else {
116-
relationField = Helper.pascalToCamelCase(model.getSimpleName()) + ((getIdType().equals(UUID.class) && !idField.equalsIgnoreCase("id")) ? "UUID" : "Id");
117-
}
118-
if (config.isIdPrimaryKey()) {
119-
if (primaryKey == null)
120-
primaryKey = idField;
121-
}
122-
if (model.isAnnotationPresent(SoftDelete.class)) {
123-
softDelete = model.getDeclaredAnnotationsByType(SoftDelete.class)[0];
124-
if (!fields.containsKey(softDelete.value()))
125-
throw new ORMConfigurationException("Missing soft-delete field '" + softDelete.value() + "'");
126-
}
127-
if (model.isAnnotationPresent(Dates.class)) {
128-
dates = model.getDeclaredAnnotationsByType(Dates.class)[0];
129-
if (!fields.containsKey(dates.create()))
130-
throw new ORMConfigurationException("Missing dates field '" + dates.create() + "'");
131-
if (!fields.containsKey(dates.update()))
132-
throw new ORMConfigurationException("Missing dates field '" + dates.update() + "'");
133-
}
134158
}
135159

136160
public boolean isSoftDelete() {

src/main/java/org/javawebstack/orm/mapper/AbstractDataTypeMapper.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44
import org.javawebstack.orm.SQLType;
55

66
public class AbstractDataTypeMapper implements TypeMapper {
7+
8+
private static final int BYTES_OVERHEAD_TEXT = 2;
9+
private static final int BYTES_OVERHEAD_MEDIUMTEXT = 3;
10+
private static final int BYTES_OVERHEAD_LONGTEXT = 4;
11+
12+
private static final long MAX_SIZE_TEXT = (long) Math.floor((65535 - BYTES_OVERHEAD_TEXT) / 4);
13+
private static final long MAX_SIZE_MEDIUMTEXT = (long) Math.floor((16777215 - BYTES_OVERHEAD_MEDIUMTEXT) / 4);
14+
private static final long MAX_SIZE_LONGTEXT = (long) Math.floor((4294967295L - BYTES_OVERHEAD_LONGTEXT) / 4);
15+
716
public Object mapToSQL(Object source, Class<?> type) {
817
if (source == null)
918
return null;
@@ -21,8 +30,13 @@ public Object mapToJava(Object source, Class<?> type) {
2130
}
2231

2332
public SQLType getType(Class<?> type, int size) {
24-
if (AbstractElement.class.isAssignableFrom(type))
33+
if (AbstractElement.class.isAssignableFrom(type)) {
34+
if (size > MAX_SIZE_MEDIUMTEXT)
35+
return SQLType.LONGTEXT;
36+
if (size > MAX_SIZE_TEXT)
37+
return SQLType.MEDIUMTEXT;
2538
return SQLType.TEXT;
39+
}
2640
return null;
2741
}
2842

src/main/java/org/javawebstack/orm/mapper/DefaultMapper.java

+16-5
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public Object mapToJava(Object source, Class<?> type) {
109109
}
110110

111111
public SQLType getType(Class<?> type, int size) {
112-
if (type.equals(String.class) || type.equals(char[].class))
112+
if (type.equals(String.class) || type.equals(char[].class)) {
113113
// Upper limit of 4294967295 exceeds the int boundaries
114114
if (size > MAX_SIZE_MEDIUMTEXT)
115115
return SQLType.LONGTEXT;
@@ -119,12 +119,18 @@ public SQLType getType(Class<?> type, int size) {
119119
return SQLType.VARCHAR;
120120
if (size == 1)
121121
return SQLType.CHAR;
122+
}
122123
if (type.equals(UUID.class))
123124
return SQLType.VARCHAR;
124125
if (type.equals(char.class))
125126
return SQLType.CHAR;
126-
if (type.isEnum())
127-
return SQLType.ENUM;
127+
if (type.isEnum()) {
128+
if(size < 1) {
129+
return SQLType.ENUM;
130+
} else {
131+
return SQLType.VARCHAR;
132+
}
133+
}
128134
if (type.equals(boolean.class) || type.equals(Boolean.class) || type.equals(byte.class) || type.equals(Byte.class))
129135
return SQLType.TINYINT;
130136
if (type.equals(short.class) || type.equals(Short.class))
@@ -147,8 +153,13 @@ public SQLType getType(Class<?> type, int size) {
147153
}
148154

149155
public String getTypeParameters(Class<?> type, int size) {
150-
if (type.isEnum())
151-
return Arrays.stream(((Class<? extends Enum<?>>) type).getEnumConstants()).map(c -> "'" + c.name() + "'").collect(Collectors.joining(","));
156+
if (type.isEnum()) {
157+
if(size < 1) {
158+
return Arrays.stream(((Class<? extends Enum<?>>) type).getEnumConstants()).map(c -> "'" + c.name() + "'").collect(Collectors.joining(","));
159+
} else {
160+
return String.valueOf(size);
161+
}
162+
}
152163
if (type.equals(String.class) || type.equals(char[].class))
153164
return size > MAX_SIZE_VARCHAR || size < 1 ? null : String.valueOf(size);
154165
if (type.equals(byte[].class))

0 commit comments

Comments
 (0)