Compare commits

..
Author SHA1 Message Date
Rob Bygrave 4e8b3f22de [maven-release-plugin] prepare release avaje-ebeanorm-4.2.0 2014-11-13 01:27:58 +13:00
Rob Bygrave 55e43ddc36 Add whitespace for MANIFEST.MF 2014-11-13 01:26:47 +13:00
Rob Bygrave 97d75c06a1 Revert MANIFEST.MF - invalid header 2014-11-13 01:15:47 +13:00
Rob Bygrave adcfa939e4 revert MANIFEST.MF - invalid jackson part 2014-11-13 01:11:07 +13:00
Rob Bygrave 8a4d78a3f5 Fix JSON for ScalarTypePostgresHstore with field name and nulls 2014-11-13 00:49:20 +13:00
Rob Bygrave 04e77d9949 Bump pom to 4.2.0-SNAPSHOT 2014-11-12 23:30:31 +13:00
Rob Bygrave 76e7b8d199 Add to Model the apply(PathProperties) method 2014-11-12 23:06:26 +13:00
Rob Bygrave 00f85a42f8 JSON Refactor - move EJson into text.json package 2014-11-12 22:56:42 +13:00
Rob Bygrave e649a70509 make SimpleTextParser class not public 2014-11-12 22:35:48 +13:00
Rob Bygrave 2ec50d2c71 Add query.apply(PathProperties) 2014-11-12 22:24:37 +13:00
Rob Bygrave eaee3a9c02 JSON refactor - tidy up 2014-11-12 22:10:28 +13:00
Rob Bygrave 221272328c WIP JSON refactor - tidy up ScalarTypes 2014-11-12 00:17:24 +13:00
Rob Bygrave 1677917465 Move from javax.json to jackson-core for parser/generator 2014-11-10 20:31:11 +13:00
Rob Bygrave bfefdbac41 Merge from JSON refactoring branch 2014-11-06 23:32:27 +13:00
Rob Bygrave 58755a51a9 JSON Refactor - compound type support 2014-11-06 23:18:20 +13:00
Rob Bygrave b313809894 WIP json refactor - initial tidy 2014-11-05 23:15:09 +13:00
rbygrave 0f3b1eb812 Tidy up test - TestInfoOneToOne, oneToOne cascade update 2014-10-29 23:45:24 +13:00
rbygrave 306cc4adf4 Add test for oneToOne cascade update 2014-10-29 23:43:11 +13:00
rbygrave ed88978173 No effective change - javadoc tweak on params 2014-10-29 23:41:40 +13:00
rbygrave ae266968b4 [maven-release-plugin] prepare for next development iteration 2014-10-29 00:11:43 +13:00
rbygrave aa86454cc4 [maven-release-plugin] prepare release avaje-ebeanorm-4.1.9 2014-10-29 00:11:20 +13:00
rbygrave c99bec4940 Add First/Second/SuperSecond test 2014-10-29 00:07:25 +13:00
rbygrave 7426274ef6 bump agent to 4.1.9 2014-10-28 23:46:20 +13:00
Rob Bygrave 130b7e3327 Add another self referencing test - SelfParent 2014-10-20 23:06:50 +13:00
Rob Bygrave de201715fc #196 - Add support for using java.net.InetAddress in entity beans 2014-10-20 22:36:18 +13:00
Rob Bygrave 241f6f3d6d #196 - Add support for using java.net.InetAddress in entity beans 2014-10-20 22:31:22 +13:00
Rob Bygrave 1210aca027 Add test for SqlUpdate in various transaction scopes 2014-10-20 20:18:17 +13:00
Rob Bygrave e653c34211 Fix for #188 - ClassPathSearch not searching in running Jar 2014-10-16 23:15:16 +13:00
Rob Bygrave 131750cf85 No effective change - format 2014-10-16 22:58:13 +13:00
Rob Bygrave 17b16fd5d9 Merge pull request #194 from nedge/master
FIX for ManyToOne targetType & OSGI MANIFEST
2014-10-15 19:55:17 +13:00
Eddie Mc Greal 1065a84709 FIX for ManyToOne targetType & OSGI MANIFEST 2014-10-14 08:10:31 +02:00
Rob Bygrave 13791a2e58 Update version in readme 2014-10-08 22:13:48 +13:00
Rob Bygrave 277703d750 [maven-release-plugin] prepare for next development iteration 2014-10-08 21:44:25 +13:00
Rob Bygrave 637cbc6489 [maven-release-plugin] prepare release avaje-ebeanorm-4.1.8 2014-10-08 21:44:15 +13:00
Rob Bygrave 5d09ca16d6 Fix for #192 - Backslash literal in LIKE expression - Postgres (and H2, MySql) behaviour 2014-10-08 21:42:39 +13:00
Rob Bygrave 6ed1f25e22 [maven-release-plugin] prepare for next development iteration 2014-09-10 00:02:41 +12:00
Rob Bygrave b8ae443074 [maven-release-plugin] prepare release avaje-ebeanorm-4.1.7 2014-09-10 00:02:31 +12:00
Rob Bygrave ab9762bbd9 Fix for #190 - javax.persistence.PersistenceException: Server [null] was not found? at EntityBeanIntercept.loadBean(EntityBeanIntercept.java:693) 2014-09-10 00:00:49 +12:00
Rob Bygrave 2c90b239cd [maven-release-plugin] prepare for next development iteration 2014-08-22 00:45:30 +12:00
Rob Bygrave 13806767a3 [maven-release-plugin] prepare release avaje-ebeanorm-4.1.6 2014-08-22 00:45:20 +12:00
Rob Bygrave 40e43b9d5f update agent and maven plugin versions to 4.1.6 2014-08-22 00:44:08 +12:00
Rob Bygrave 29f1e63146 Fix for #186 - Fix for Lazy load when fetched optional ManyToOne bean is null in database 2014-08-22 00:41:12 +12:00
rbygrave 5cf008b521 Fix for #182 Modify pom removing provided scope from slf4j-api dependency 2014-08-12 23:30:41 +12:00
rbygrave 3e788d4598 [maven-release-plugin] prepare for next development iteration 2014-08-01 21:43:53 +12:00
rbygrave 8a29454893 [maven-release-plugin] prepare release avaje-ebeanorm-4.1.5 2014-08-01 21:43:31 +12:00
rbygrave 62c083a6ea Add LongMaxUpdater, change CQueryPlanStats to use LongMaxUpdater 2014-07-29 23:48:38 +12:00
rbygrave 7f8e4be396 Merge branch 'master' of github.com:ebean-orm/avaje-ebeanorm 2014-07-29 23:44:38 +12:00
rbygrave 2ad39974e8 No effective change - code format and javadoc tidy 2014-07-29 23:44:03 +12:00
Rob Bygrave 664e95d87b Merge pull request #180 from rvbiljouw/master
Index annotation for generating single-column indexes in DDL
2014-07-29 22:45:39 +12:00
Rick van Biljouw 5cf668f65b Disallow Index annotation on fields that have a relationship annotation (OneToMany, ManyToOne or OneToOne) 2014-07-28 19:44:25 +01:00
Rick van Biljouw 31f56621ff Added @Index annotation to generate single-column indexes 2014-07-28 18:43:50 +01:00
rbygrave 11a6cd04ea Update README with latest version 2014-07-26 00:12:41 +12:00
rbygrave fdb573bfe2 Fix for #177 - EbeanServer.refresh() not loading/refreshing @Lob property unless it is annotated with @Basic(fetch=FetchType.EAGER) 2014-07-26 00:09:26 +12:00
rbygrave ae0e1fe691 No effective change - remove some incorrect javadoc 2014-07-25 23:21:14 +12:00
rbygrave 0511e01273 [maven-release-plugin] prepare for next development iteration 2014-07-24 19:45:56 +12:00
Rob Bygrave 0ceda6406e WIP on JSON refactor 2014-06-28 03:09:10 +12:00
206 changed files with 10017 additions and 6787 deletions
+1 -1
View File
@@ -7,6 +7,6 @@ Maven Dependency
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.1.3</version>
<version>4.1.8</version>
</dependency>
+25 -11
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.1.4</version>
<version>4.2.0</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
@@ -48,6 +48,18 @@
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
@@ -77,13 +89,6 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-agentloader</artifactId>
@@ -94,7 +99,7 @@
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-agent</artifactId>
<version>4.1.5</version>
<version>4.1.9</version>
<scope>test</scope>
</dependency>
@@ -186,7 +191,7 @@
<plugin>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
<version>4.1.5</version>
<version>4.1.9</version>
<executions>
<!-- Not going to enhance Model bean -->
<execution>
@@ -218,7 +223,16 @@
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
+10 -2
View File
@@ -1383,10 +1383,18 @@ public final class Ebean {
}
/**
* Create a JsonContext that will use the default configuration options.
* Return the JsonContext for reading/writing JSON.
*/
public static JsonContext json() {
return serverMgr.getPrimaryServer().json();
}
/**
* Return the JsonContext for reading/writing JSON.
* @deprecated Please use #json instead.
*/
public static JsonContext createJsonContext() {
return serverMgr.getPrimaryServer().createJsonContext();
return json();
}
}
+11 -6
View File
@@ -433,7 +433,7 @@ public interface EbeanServer {
* @param id
* the id value
*/
public <T> T getReference(Class<T> beanType, Object uid);
public <T> T getReference(Class<T> beanType, Object id);
/**
* Return the number of 'top level' or 'root' entities this query should
@@ -489,7 +489,7 @@ public interface EbeanServer {
*
* @param query
* the query to execute the row count on
* @param t
* @param transaction
* the transaction (can be null).
* @return a Future object for the row count query
*/
@@ -505,7 +505,7 @@ public interface EbeanServer {
*
* @param query
* the query to execute the fetch Id's on
* @param t
* @param transaction
* the transaction (can be null).
* @return a Future object for the list of Id's
*/
@@ -521,7 +521,7 @@ public interface EbeanServer {
*
* @param query
* the query to execute in the background
* @param t
* @param transaction
* the transaction (can be null).
* @return a Future object for the list result of the query
* @deprecated
@@ -538,7 +538,7 @@ public interface EbeanServer {
*
* @param query
* the query to execute in the background
* @param t
* @param transaction
* the transaction (can be null).
* @return a Future object for the list result of the query
* @deprecated
@@ -1119,9 +1119,14 @@ public interface EbeanServer {
public void runCacheWarming(Class<?> beanType);
/**
* Create a JsonContext that will use the default configuration options.
* Return the JsonContext for reading/writing JSON.
* @deprecated Please use #json instead.
*/
public JsonContext createJsonContext();
/**
* Return the JsonContext for reading/writing JSON.
*/
public JsonContext json();
}
@@ -1,5 +1,7 @@
package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
@@ -87,6 +89,11 @@ public interface ExpressionList<T> extends Serializable {
*/
public Query<T> setOrderBy(String orderBy);
/**
* Apply the path properties to the query replacing the select and fetch clauses.
*/
public Query<T> apply(PathProperties pathProperties);
/**
* Execute the query iterating over the results.
*
@@ -242,7 +249,8 @@ public interface ExpressionList<T> extends Serializable {
* Specify a property (associated bean) to join and <em>fetch</em> including
* all its properties.
*
* @see Query#join(String)
* @see Query#fetch(String)
* @deprecated
*/
public Query<T> join(String assocProperties);
@@ -250,7 +258,8 @@ public interface ExpressionList<T> extends Serializable {
* Specify a property (associated bean) to join and <em>fetch</em> with its
* specific properties to include (aka partial object).
*
* @see Query#join(String,String)
* @see Query#fetch(String,String)
* @deprecated
*/
public Query<T> join(String assocProperty, String assocProperties);
+37 -28
View File
@@ -1,5 +1,7 @@
package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -176,11 +178,11 @@ public abstract class Model {
* Typically a Finder is defined as a public static field on an entity bean class to provide a
* nice way to write queries.
*
* @param I
* @param <I>
* The Id type. This is most often a {@link Long} but is also often a {@link UUID} or
* {@link String}.
*
* @param T
*
* @param <T>
* The bean type
*/
public static class Finder<I, T> {
@@ -265,7 +267,7 @@ public abstract class Model {
* Retrieves an entity by ID.
*
* <p>
* Equivilent to {@link EbeanServer#find(Class, Object)}
* Equivalent to {@link EbeanServer#find(Class, Object)}
*/
public T byId(I id) {
return db().find(type, id);
@@ -275,7 +277,7 @@ public abstract class Model {
* Creates an entity reference for this ID.
*
* <p>
* Equivilent to {@link EbeanServer#getReference(Class, Object)}
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
*/
public T ref(I id) {
return db().getReference(type, id);
@@ -285,7 +287,7 @@ public abstract class Model {
* Creates a filter for sorting and filtering lists of entities locally without going back to
* the database.
* <p>
* Equivilent to {@link EbeanServer#filter(Class)}
* Equivalent to {@link EbeanServer#filter(Class)}
*/
public Filter<T> filter() {
return db().filter(type);
@@ -294,12 +296,19 @@ public abstract class Model {
/**
* Creates a query.
* <p>
* Equivilent to {@link EbeanServer#find(Class)}
* Equivalent to {@link EbeanServer#find(Class)}
*/
public Query<T> query() {
return db().find(type);
}
/**
* Creates a query applying the path properties to set the select and fetch clauses.
*/
public Query<T> apply(PathProperties pathProperties) {
return db().find(type).apply(pathProperties);
}
/**
* Returns the next identity value.
*
@@ -313,7 +322,7 @@ public abstract class Model {
/**
* Executes a query and returns the results as a list of IDs.
* <p>
* Equivilent to {@link Query#findIds()}
* Equivalent to {@link Query#findIds()}
*/
public List<Object> findIds() {
return query().findIds();
@@ -324,7 +333,7 @@ public abstract class Model {
* <p>
* The same as {@link #all()}
* <p>
* Equivilent to {@link Query#findList()}
* Equivalent to {@link Query#findList()}
*/
public List<T> findList() {
return query().findList();
@@ -333,7 +342,7 @@ public abstract class Model {
/**
* Returns all the entities of the given type as a set.
* <p>
* Equivilent to {@link Query#findSet()}
* Equivalent to {@link Query#findSet()}
*/
public Set<T> findSet() {
return query().findSet();
@@ -342,7 +351,7 @@ public abstract class Model {
/**
* Retrieves all entities of the given type as a map of objects.
* <p>
* Equivilent to {@link Query#findMap()}
* Equivalent to {@link Query#findMap()}
*/
public Map<?, T> findMap() {
return query().findMap();
@@ -352,7 +361,7 @@ public abstract class Model {
* Executes the query and returns the results as a map of the objects specifying the map key
* property.
* <p>
* Equivilent to {@link Query#findMap(String, Class)}
* Equivalent to {@link Query#findMap(String, Class)}
*/
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
return query().findMap(keyProperty, keyType);
@@ -362,7 +371,7 @@ public abstract class Model {
* Return a PagedList of all entities of the given type (use where() to specify predicates as
* needed).
* <p>
* Equivilent to {@link Query#findPagedList(int, int)}
* Equivalent to {@link Query#findPagedList(int, int)}
*/
public PagedList<T> findPagedList(int pageIndex, int pageSize) {
return query().findPagedList(pageIndex, pageSize);
@@ -371,7 +380,7 @@ public abstract class Model {
/**
* Executes a find row count query in a background thread.
* <p>
* Equivilent to {@link Query#findFutureRowCount()}
* Equivalent to {@link Query#findFutureRowCount()}
*/
public FutureRowCount<T> findFutureRowCount() {
return query().findFutureRowCount();
@@ -380,7 +389,7 @@ public abstract class Model {
/**
* Returns the total number of entities for this type. *
* <p>
* Equivilent to {@link Query#findRowCount()}
* Equivalent to {@link Query#findRowCount()}
*/
public int findRowCount() {
return query().findRowCount();
@@ -397,7 +406,7 @@ public abstract class Model {
* Explicitly sets a comma delimited list of the properties to fetch on the 'main' entity bean,
* to load a partial object.
* <p>
* Equivilent to {@link Query#select(String)}
* Equivalent to {@link Query#select(String)}
*/
public Query<T> select(String fetchProperties) {
return query().select(fetchProperties);
@@ -406,7 +415,7 @@ public abstract class Model {
/**
* Specifies a path to load including all its properties.
* <p>
* Equivilent to {@link Query#fetch(String)}
* Equivalent to {@link Query#fetch(String)}
*/
public Query<T> fetch(String path) {
return query().fetch(path);
@@ -416,7 +425,7 @@ public abstract class Model {
* Additionally specifies a <code>FetchConfig</code> to specify a 'query join' and/or define the
* lazy loading query.
* <p>
* Equivilent to {@link Query#fetch(String, FetchConfig)}
* Equivalent to {@link Query#fetch(String, FetchConfig)}
*/
public Query<T> fetch(String path, FetchConfig joinConfig) {
return query().fetch(path, joinConfig);
@@ -426,7 +435,7 @@ public abstract class Model {
* Specifies a path to fetch with a specific list properties to include, to load a partial
* object.
* <p>
* Equivilent to {@link Query#fetch(String, String)}
* Equivalent to {@link Query#fetch(String, String)}
*/
public Query<T> fetch(String path, String fetchProperties) {
return query().fetch(path, fetchProperties);
@@ -436,7 +445,7 @@ public abstract class Model {
* Additionally specifies a <code>FetchConfig</code> to use a separate query or lazy loading to
* load this path.
* <p>
* Equivilent to {@link Query#fetch(String, String, FetchConfig)}
* Equivalent to {@link Query#fetch(String, String, FetchConfig)}
*/
public Query<T> fetch(String assocProperty, String fetchProperties, FetchConfig fetchConfig) {
return query().fetch(assocProperty, fetchProperties, fetchConfig);
@@ -446,7 +455,7 @@ public abstract class Model {
* Adds expressions to the <code>where</code> clause with the ability to chain on the
* <code>ExpressionList</code>.
* <p>
* Equivilent to {@link Query#where()}
* Equivalent to {@link Query#where()}
*/
public ExpressionList<T> where() {
return query().where();
@@ -458,7 +467,7 @@ public abstract class Model {
* <p>
* This is exactly the same as {@link #orderBy}.
* <p>
* Equivilent to {@link Query#order()}
* Equivalent to {@link Query#order()}
*/
public OrderBy<T> order() {
return query().order();
@@ -480,7 +489,7 @@ public abstract class Model {
* <p>
* This is exactly the same as {@link #order}.
* <p>
* Equivilent to {@link Query#orderBy()}
* Equivalent to {@link Query#orderBy()}
*/
public OrderBy<T> orderBy() {
return query().orderBy();
@@ -499,7 +508,7 @@ public abstract class Model {
/**
* Sets the first row to return for this query.
* <p>
* Equivilent to {@link Query#setFirstRow(int)}
* Equivalent to {@link Query#setFirstRow(int)}
*/
public Query<T> setFirstRow(int firstRow) {
return query().setFirstRow(firstRow);
@@ -508,7 +517,7 @@ public abstract class Model {
/**
* Sets the maximum number of rows to return in the query.
* <p>
* Equivilent to {@link Query#setMaxRows(int)}
* Equivalent to {@link Query#setMaxRows(int)}
*/
public Query<T> setMaxRows(int maxRows) {
return query().setMaxRows(maxRows);
@@ -521,7 +530,7 @@ public abstract class Model {
* Use this to perform a find byId query but with additional control over the query such as
* using select and fetch to control what parts of the object graph are returned.
* <p>
* Equivilent to {@link Query#setId(Object)}
* Equivalent to {@link Query#setId(Object)}
*/
public Query<T> setId(Object id) {
return query().setId(id);
@@ -530,7 +539,7 @@ public abstract class Model {
/**
* Create and return a new query using the OQL.
* <p>
* Equivilent to {@link EbeanServer#createQuery(Class, String)}
* Equivalent to {@link EbeanServer#createQuery(Class, String)}
*/
public Query<T> setQuery(String oql) {
return db().createQuery(type, oql);
@@ -539,7 +548,7 @@ public abstract class Model {
/**
* Create and return a new query based on the <code>RawSql</code>.
* <p>
* Equivilent to {@link Query#setRawSql(RawSql)}
* Equivalent to {@link Query#setRawSql(RawSql)}
*/
public Query<T> setRawSql(RawSql rawSql) {
return query().setRawSql(rawSql);
+10
View File
@@ -1,5 +1,7 @@
package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
@@ -413,6 +415,14 @@ public interface Query<T> extends Serializable {
*/
public Query<T> fetch(String path, FetchConfig joinConfig);
/**
* Apply the path properties replacing the select and fetch clauses.
* <p>
* This is typically used when the PathProperties is applied to both the query and the JSON output.
* </p>
*/
public Query<T> apply(PathProperties pathProperties);
/**
* Execute the query returning the list of Id's.
* <p>
@@ -1,6 +1,6 @@
package com.avaje.ebean;
public class SimpleTextParser {
class SimpleTextParser {
private final String oql;
private final char[] chars;
@@ -10,9 +10,7 @@ public class SimpleTextParser {
private String word;
private String lowerWord;
private int openParenthesisCount;
public SimpleTextParser(String oql) {
SimpleTextParser(String oql) {
this.oql = oql;
this.chars = oql.toCharArray();
this.eof = oql.length();
@@ -22,10 +20,6 @@ public class SimpleTextParser {
return pos;
}
public String getOql() {
return oql;
}
public String getWord() {
return word;
}
@@ -104,7 +98,7 @@ public class SimpleTextParser {
private void moveToClose() {
pos++;
openParenthesisCount = 0;
int openParenthesisCount = 0;
for (; pos < eof; pos++) {
char c = chars[pos];
@@ -143,11 +137,7 @@ public class SimpleTextParser {
if (isOperator(c)) {
return !isOperator;
}
if (c == '(') {
return true;
}
return isOperator;
return c == '(' || isOperator;
}
private boolean isOperator(char c) {
@@ -0,0 +1,24 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An annotation for declaring an index on a single column.
*
* @author rvbiljouw
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Index {
/**
* Name of the index
*
* @return index name
*/
String value() default "";
}
@@ -55,21 +55,6 @@ import com.avaje.ebean.TxType;
* Ebean.save(order);
* }
* </pre>
*
* <p>
* During development and testing you can set a debug level which will log the
* transaction begin, commit and rollback events so that you can easily confirm
* it is behaving as you would expect.
* </p>
*
* <pre class="code">
* ## in ebean.properties file
*
* ## Log transaction begins and ends etc
* ## (0=NoLogging 1=minimal ... 9=logAll)
* ebean.debug.transaction=3
*
* </pre>
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@@ -39,8 +39,6 @@ public final class EntityBeanIntercept implements Serializable {
private transient PersistenceContext persistenceContext;
private transient BeanLoader beanLoader;
private int beanLoaderIndex;
private String ebeanServerName;
@@ -200,34 +198,22 @@ public final class EntityBeanIntercept implements Serializable {
}
/**
* Return the index position for batch loading via BeanLoader.
* Set the BeanLoader with PersistenceContext.
*/
public int getBeanLoaderIndex() {
return beanLoaderIndex;
}
/**
* Set Lazy Loading by ebeanServerName.
* <p>
* This is for reference beans created by themselves.
* </p>
*/
public void setBeanLoaderByServerName(String ebeanServerName) {
this.beanLoaderIndex = 0;
this.beanLoader = null;
this.ebeanServerName = ebeanServerName;
}
/**
* Set the BeanLoader for general lazy loading.
*/
public void setBeanLoader(int index, BeanLoader beanLoader, PersistenceContext ctx) {
this.beanLoaderIndex = index;
public void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) {
this.beanLoader = beanLoader;
this.persistenceContext = ctx;
this.ebeanServerName = beanLoader.getName();
}
/**
* Set the BeanLoader.
*/
public void setBeanLoader(BeanLoader beanLoader) {
this.beanLoader = beanLoader;
this.ebeanServerName = beanLoader.getName();
}
public boolean isFullyLoadedBean() {
return fullyLoadedBean;
}
@@ -20,6 +20,7 @@ import com.avaje.ebean.event.ServerConfigStartup;
import com.avaje.ebean.event.TransactionEventListener;
import com.avaje.ebean.meta.MetaInfoManager;
import com.avaje.ebean.util.ClassUtil;
import com.fasterxml.jackson.core.JsonFactory;
/**
* The configuration used for creating a EbeanServer.
@@ -241,6 +242,8 @@ public class ServerConfig {
private boolean collectQueryOrigins;
private JsonFactory jsonFactory;
/**
* Construct a Server Configuration for programmatically creating an
* EbeanServer.
@@ -248,6 +251,24 @@ public class ServerConfig {
public ServerConfig() {
}
/**
* Return the Jackson JsonFactory to use.
* <p>
* If not set a default implmentation will be used.
*/
public JsonFactory getJsonFactory() {
return jsonFactory;
}
/**
* Set the Jackson JsonFactory to use.
* <p>
* If not set a default implmentation will be used.
*/
public void setJsonFactory(JsonFactory jsonFactory) {
this.jsonFactory = jsonFactory;
}
/**
* Return the name of the EbeanServer.
@@ -6,6 +6,7 @@ import javax.sql.DataSource;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,40 +15,61 @@ import org.slf4j.LoggerFactory;
*/
public class DatabasePlatform {
/** The Constant logger. */
private static final Logger logger = LoggerFactory.getLogger(DatabasePlatform.class);
/** The open quote used by quoted identifiers. */
/**
* The open quote used by quoted identifiers.
*/
protected String openQuote = "\"";
/** The close quote used by quoted identifiers. */
/**
* The close quote used by quoted identifiers.
*/
protected String closeQuote = "\"";
/** For limit/offset, row_number etc limiting of SQL queries. */
/**
* For limit/offset, row_number etc limiting of SQL queries.
*/
protected SqlLimiter sqlLimiter = new LimitOffsetSqlLimiter();
/** Mapping of JDBC to Database types. */
/**
* Mapping of JDBC to Database types.
*/
protected DbTypeMap dbTypeMap = new DbTypeMap();
/** DB specific DDL syntax. */
/**
* DB specific DDL syntax.
*/
protected DbDdlSyntax dbDdlSyntax = new DbDdlSyntax();
/** Defines DB identity/sequence features. */
/**
* Defines DB identity/sequence features.
*/
protected DbIdentity dbIdentity = new DbIdentity();
/** The JDBC type to map booleans to (by default). */
/**
* The JDBC type to map booleans to (by default).
*/
protected int booleanDbType = Types.BOOLEAN;
/** The JDBC type to map Blob to. */
/**
* The JDBC type to map Blob to.
*/
protected int blobDbType = Types.BLOB;
/** The JDBC type to map Clob to. */
/**
* The JDBC type to map Clob to.
*/
protected int clobDbType = Types.CLOB;
/** For Oracle treat empty strings as null. */
/**
* For Oracle treat empty strings as null.
*/
protected boolean treatEmptyStringsAsNull;
/** The name. */
/**
* The database platform name.
*/
protected String name = "generic";
/**
@@ -57,6 +79,11 @@ public class DatabasePlatform {
*/
private static final char BACK_TICK = '`';
/**
* The like clause. Can be overridden to disable default escape character.
*/
protected String likeClause = "like ?";
protected DbEncrypt dbEncrypt;
protected boolean idInExpandedForm;
@@ -299,4 +326,13 @@ public class DatabasePlatform {
return sql;
}
/**
* Returns the like clause used by this database platform.
* <p>
* This may include an escape clause to disable a default escape character.
*/
public String getLikeClause() {
return likeClause;
}
}
@@ -14,6 +14,7 @@ public class H2Platform extends DatabasePlatform {
super();
this.name = "h2";
this.dbEncrypt = new H2DbEncrypt();
this.likeClause = "like ? escape''";
// only support getGeneratedKeys with non-batch JDBC
// so generally use SEQUENCE instead of IDENTITY for H2
@@ -20,6 +20,7 @@ public class MySqlPlatform extends DatabasePlatform {
public MySqlPlatform() {
super();
this.name = "mysql";
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.dbEncrypt = new MySqlDbEncrypt();
@@ -23,6 +23,7 @@ public class PostgresPlatform extends DatabasePlatform {
public PostgresPlatform() {
super();
this.name = "postgres";
this.likeClause = "like ? escape''";
this.dbDdlSyntax = new PostgresDdlSyntax();
@@ -53,6 +53,9 @@ class PathPropertiesParser {
case '(':
return currentWord();
default:
if (pos == 1) {
return "";
}
}
} while (pos < eof);
throw new RuntimeException("Hit EOF while reading sectionTitle from " + startPos);
@@ -91,6 +94,10 @@ class PathPropertiesParser {
}
} while (pos < eof);
if (startPos < pos) {
String currentWord = source.substring(startPos, pos);
currentPathProps.addProperty(currentWord);
}
}
private void addSubpath() {
@@ -1,7 +1,7 @@
package com.avaje.ebean.text;
/**
* An exception occured typically in processing CSV, JSON or XML.
* An exception occurred typically in processing CSV, JSON or XML.
*
* @author rbygrave
*/
@@ -0,0 +1,115 @@
package com.avaje.ebean.text.json;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* Utility that converts between JSON content and simple java Maps/Lists.
*/
public class EJson {
/**
* Write the nested Map/List as json.
*/
public static String write(Object object) throws IOException {
return EJsonWriter.write(object);
}
/**
* Write the nested Map/List as json to the writer.
*/
public static void write(Object object, Writer writer) throws IOException {
EJsonWriter.write(object, writer);
}
/**
* Write the nested Map/List as json to the jsonGenerator.
*/
public static void write(Object object, JsonGenerator jsonGenerator) throws IOException {
EJsonWriter.write(object, jsonGenerator);
}
/**
* Parse the json and return as a Map.
*/
public static Map<String,Object> parseObject(String json) throws IOException {
return EJsonReader.parseObject(json);
}
/**
* Parse the json and return as a Map taking a reader.
*/
public static Map<String,Object> parseObject(Reader reader) throws IOException {
return EJsonReader.parseObject(reader);
}
/**
* Parse the json and return as a Map taking a JsonParser.
*/
public static Map<String,Object> parseObject(JsonParser parser) throws IOException {
return EJsonReader.parseObject(parser);
}
/**
* Parse the json and return as a Map taking a JsonParser and a starting token.
* <p>
* Used when the first token is checked to see if the value is null prior to calling this.
* </p>
*/
public static Map<String,Object> parseObject(JsonParser parser, JsonToken token) throws IOException {
return EJsonReader.parseObject(parser, token);
}
/**
* Parse the json and return as a List.
* @throws IOException
*/
public static List<Object> parseList(String json) throws IOException {
return EJsonReader.parseList(json);
}
/**
* Parse the json and return as a List taking a Reader.
* @throws IOException
*/
public static List<Object> parseList(Reader reader) throws IOException {
return EJsonReader.parseList(reader);
}
/**
* Parse the json and return as a List taking a JsonParser.
*/
public static List<Object> parseList(JsonParser parser) throws IOException {
return EJsonReader.parseList(parser);
}
/**
* Parse the json and return as a List or Map.
*/
public static Object parse(String json) throws IOException {
return EJsonReader.parse(json);
}
/**
* Parse the json and return as a List or Map.
*/
public static Object parse(Reader reader) throws IOException {
return EJsonReader.parse(reader);
}
/**
* Parse the json and return as a List or Map.
*/
public static Object parse(JsonParser parser) throws IOException {
return EJsonReader.parse(parser);
}
}
@@ -0,0 +1,282 @@
package com.avaje.ebean.text.json;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
class EJsonReader {
static JsonFactory json = new JsonFactory();
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(String json) throws IOException {
return (Map<String, Object>) parse(json);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(Reader reader) throws IOException {
return (Map<String, Object>) parse(reader);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(JsonParser parser) throws IOException {
return (Map<String, Object>) parse(parser);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(JsonParser parser, JsonToken token) throws IOException {
return (Map<String, Object>)parse(parser, token);
}
@SuppressWarnings("unchecked")
static List<Object> parseList(String json) throws IOException {
return (List<Object>) parse(json);
}
@SuppressWarnings("unchecked")
static List<Object> parseList(Reader reader) throws IOException {
return (List<Object>) parse(reader);
}
@SuppressWarnings("unchecked")
static List<Object> parseList(JsonParser parser) throws IOException {
return (List<Object>) parse(parser);
}
static Object parse(String json) throws IOException {
return parse(new StringReader(json));
}
static Object parse(Reader reader) throws IOException {
return parse(json.createParser(reader));
}
static Object parse(JsonParser parser) throws IOException {
return parse(parser, null);
}
static Object parse(JsonParser parser, JsonToken token) throws IOException {
return new EJsonReader(parser).parseJson(token);
}
private final JsonParser parser;
private int depth;
private Stack stack;
private Context currentContext;
EJsonReader(JsonParser parser) {
this.parser = parser;
}
private void startArray() {
depth++;
stack.push(currentContext);
currentContext = new ArrayContext();
}
private void startObject() {
depth++;
stack.push(currentContext);
currentContext = new ObjectContext();
}
private void endArray() {
end();
}
private void endObject() {
end();
}
private void end() {
depth--;
if (!stack.isEmpty()) {
currentContext = stack.pop(currentContext);
}
}
private void setValue(Object value) {
currentContext.setValue(value);
}
private void setValueNull() {
currentContext.setValueNull();
}
private Object parseJson(JsonToken token) throws IOException {
if (token == null) {
// no initial token so expect to read START_OBJECT or similar
token = parser.nextToken();
if (JsonToken.VALUE_NULL == token) {
return null;
}
}
stack = new Stack();
// it is a object or array, process the first JsonToken
processJsonToken(token);
// process the rest of the object or array
while (depth > 0) {
token = parser.nextToken();
processJsonToken(token);
}
return currentContext.getValue();
}
/**
* Process the JsonToken for objects and arrays.
*/
private void processJsonToken(JsonToken token) throws IOException {
switch (token) {
case START_ARRAY:
startArray();
break;
case START_OBJECT:
startObject();
break;
case FIELD_NAME:
currentContext.setKey(parser.getCurrentName());
break;
case VALUE_STRING:
setValue(parser.getValueAsString());
break;
case VALUE_NUMBER_INT:
setValue(parser.getLongValue());
break;
case VALUE_NUMBER_FLOAT:
setValue(parser.getDecimalValue());
break;
case VALUE_TRUE:
setValue(Boolean.TRUE);
break;
case VALUE_FALSE:
setValue(Boolean.FALSE);
break;
case VALUE_NULL:
setValueNull();
break;
case END_OBJECT:
endObject();
break;
case END_ARRAY:
endArray();
break;
default:
break;
}
}
private static final class Stack {
private Context head;
private void push(Context context) {
if (context != null) {
context.next = head;
head = context;
}
}
private Context pop(Context endingContext) {
if (head == null) {
throw new NoSuchElementException();
}
Context temp = head;
head = head.next;
temp.popContext(endingContext);
return temp;
}
private boolean isEmpty() {
return head == null;
}
}
private static abstract class Context {
Context next;
abstract void popContext(Context temp);
abstract Object getValue();
abstract void setKey(String key);
abstract void setValue(Object value);
abstract void setValueNull();
}
private static class ObjectContext extends Context {
private final Map<String, Object> map = new LinkedHashMap<String, Object>();
private String key;
public void popContext(Context temp) {
setValue(temp.getValue());
}
Object getValue() {
return map;
}
void setKey(String key) {
this.key = key;
}
void setValue(Object value) {
map.put(key, value);
}
void setValueNull() {
map.put(key, null);
}
}
private static class ArrayContext extends Context {
private final List<Object> values = new ArrayList<Object>();
public void popContext(Context temp) {
values.add(temp.getValue());
}
Object getValue() {
return values;
}
void setValue(Object value) {
values.add(value);
}
void setValueNull() {
// ignore
}
void setKey(String key) {
// not expected
}
}
}
@@ -0,0 +1,209 @@
package com.avaje.ebean.text.json;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
class EJsonWriter {
/**
* Base jsonFactory implementation used when it is not passed in.
*/
static JsonFactory jsonFactory = new JsonFactory();
static String write(Object object) throws IOException {
StringWriter writer = new StringWriter(200);
write(object, writer);
return writer.toString();
}
static void write(Object object, Writer writer) throws IOException {
JsonGenerator generator = jsonFactory.createGenerator(writer);
write(object, generator);
generator.close();
}
static void write(Object object, JsonGenerator jsonGenerator) {
new EJsonWriter(jsonGenerator).writeJson(object);
}
private final JsonGenerator jsonGenerator;
private EJsonWriter(JsonGenerator jsonGenerator) {
this.jsonGenerator = jsonGenerator;
}
private void writeJson(Object object) {
writeJson(null, object);
}
@SuppressWarnings("unchecked")
private void writeJson(String name, Object object) {
try {
if (object == null) {
writeNull(name);
} else if (object instanceof Map) {
writeMap(name, (Map<Object, Object>) object);
} else if (object instanceof Collection) {
writeCollection(name, (Collection<Object>) object);
} else if (object instanceof Boolean) {
writeBoolean(name, (Boolean) object);
} else if (object instanceof Number) {
writeNumber(name, (Number) object);
} else if (object instanceof Date) {
writeDate(name, (Date) object);
} else if (object instanceof String) {
writeString(name, (String) object);
} else if (object instanceof Map.Entry<?, ?>) {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
writeJson(entry.getKey().toString(), entry.getValue());
} else {
writeString(name, object.toString());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void writeBoolean(String name, Boolean object) throws IOException {
if (name == null) {
jsonGenerator.writeBoolean(object);
} else {
jsonGenerator.writeBooleanField(name, object);
}
}
private void writeDate(String name, Date object) throws IOException {
if (name == null) {
jsonGenerator.writeNumber(object.getTime());
} else {
jsonGenerator.writeNumberField(name, object.getTime());
}
}
private void writeNumber(String name, Number object) throws IOException {
if (object instanceof Long) {
writeLong(name, object);
} else if (object instanceof Integer) {
writeInteger(name, object);
} else if (object instanceof Double) {
writeDouble(name, object);
} else if (object instanceof BigDecimal) {
writeBigDecimal(name, object);
} else if (object instanceof BigInteger) {
writeBigInteger(name, object);
} else {
writeGeneralNumber(name, object);
}
}
private void writeGeneralNumber(String name, Number object) throws IOException {
writeBigDecimal(name, new BigDecimal(object.toString()));
}
private void writeBigDecimal(String name, Number object) throws IOException {
if (name == null) {
jsonGenerator.writeNumber((BigDecimal) object);
} else {
jsonGenerator.writeNumberField(name, (BigDecimal) object);
}
}
private void writeBigInteger(String name, Number object) throws IOException {
if (name == null) {
jsonGenerator.writeNumber((BigInteger) object);
} else {
jsonGenerator.writeNumberField(name, object.longValue());
}
}
private void writeDouble(String name, Number object) throws IOException {
if (name == null) {
jsonGenerator.writeNumber((Double) object);
} else {
jsonGenerator.writeNumberField(name, (Double) object);
}
}
private void writeLong(String name, Number object) throws IOException {
if (name == null) {
jsonGenerator.writeNumber((Long) object);
} else {
jsonGenerator.writeNumberField(name, (Long) object);
}
}
private void writeInteger(String name, Number object) throws IOException {
if (name == null) {
jsonGenerator.writeNumber((Integer) object);
} else {
jsonGenerator.writeNumberField(name, (Integer) object);
}
}
private void writeNull(String name) throws IOException {
if (name == null) {
jsonGenerator.writeNull();
} else {
jsonGenerator.writeNullField(name);
}
}
private void writeString(String name, String object) throws IOException {
if (name == null) {
jsonGenerator.writeString(object);
} else {
jsonGenerator.writeStringField(name, object);
}
}
private void writeCollection(String name, Collection<Object> collection) throws IOException {
if (name != null) {
jsonGenerator.writeFieldName(name);
}
jsonGenerator.writeStartArray();
for (Object object : collection) {
writeJson(null, object);
}
jsonGenerator.writeEndArray();
}
private void writeMap(String name, Map<Object, Object> map) throws IOException {
if (name != null) {
jsonGenerator.writeFieldName(name);
}
jsonGenerator.writeStartObject();
Set<Entry<Object, Object>> entrySet = map.entrySet();
for (Entry<Object, Object> entry : entrySet) {
writeJson(entry.getKey().toString(), entry.getValue());
}
jsonGenerator.writeEndObject();
}
}
@@ -1,131 +1,99 @@
package com.avaje.ebean.text.json;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.List;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
/**
* Converts objects to and from JSON format.
*
* @author rbygrave
*/
public interface JsonContext {
/**
* Convert json string input into a Bean of a specific type.
*/
public <T> T toBean(Class<T> rootType, String json);
public <T> T toBean(Class<T> rootType, String json) throws IOException;
/**
* Convert json reader input into a Bean of a specific type.
*/
public <T> T toBean(Class<T> rootType, Reader json);
/**
* Convert json string input into a Bean of a specific type with options.
*/
public <T> T toBean(Class<T> rootType, String json, JsonReadOptions options);
/**
* Convert json reader input into a Bean of a specific type with options.
*/
public <T> T toBean(Class<T> rootType, Reader json, JsonReadOptions options);
public <T> T toBean(Class<T> rootType, Reader json) throws IOException;
/**
* Convert json string input into a list of beans of a specific type.
*/
public <T> List<T> toList(Class<T> rootType, String json);
/**
* Convert json string input into a list of beans of a specific type with
* options.
*/
public <T> List<T> toList(Class<T> rootType, String json, JsonReadOptions options);
public <T> List<T> toList(Class<T> rootType, String json) throws IOException;
/**
* Convert json reader input into a list of beans of a specific type.
* @throws IOException
*/
public <T> List<T> toList(Class<T> rootType, Reader json);
/**
* Convert json reader input into a list of beans of a specific type with
* options.
*/
public <T> List<T> toList(Class<T> rootType, Reader json, JsonReadOptions options);
public <T> List<T> toList(Class<T> rootType, Reader json) throws IOException;
/**
* Use the genericType to determine if this should be converted into a List or
* bean.
*/
public Object toObject(Type genericType, Reader json, JsonReadOptions options);
public Object toObject(Type genericType, Reader json) throws IOException;
/**
* Use the genericType to determine if this should be converted into a List or
* bean.
*/
public Object toObject(Type genericType, String json, JsonReadOptions options);
public Object toObject(Type genericType, String json) throws IOException;
/**
* Write the bean or collection in JSON format to the writer with default
* options.
*
* @param o
* @param value
* the bean or collection of beans to write
* @param writer
* used to write the json output to
*/
public void toJsonWriter(Object o, Writer writer);
/**
* With additional pretty output option.
*/
public void toJsonWriter(Object o, Writer writer, boolean pretty);
public void toJson(Object value, Writer writer) throws IOException;
/**
* With additional options to specify JsonValueAdapter and
* JsonWriteBeanVisitor's.
*
* @param o
* @param value
* the bean or collection of beans to write
* @param writer
* used to write the json output to
* @param options
* additional options to control the JSON output
*/
public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options);
/**
* With additional JSONP callback function.
*/
public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options,
String callback);
public void toJson(Object value, Writer writer, JsonWriteOptions options) throws IOException;
/**
* Convert a bean or collection to json string using default options.
*/
public String toJsonString(Object o);
public String toJson(Object value) throws IOException;
/**
* Convert a bean or collection to json string with pretty format using
* default options.
* Convert a bean or collection to json string.
*/
public String toJsonString(Object o, boolean pretty);
public String toJson(Object value, JsonWriteOptions options) throws IOException;
/**
* Convert a bean or collection to json string using options.
*/
public String toJsonString(Object o, boolean pretty, JsonWriteOptions options);
/**
* Convert a bean or collection to json string using a JSONP callback.
*/
public String toJsonString(Object o, boolean pretty, JsonWriteOptions options, String callback);
/**
* Return true if the type is known as an Entity or Xml type or a List Set or
* Map of known bean types.
* Return true if the type is known as an Entity bean or a List Set or
* Map of entity beans.
*/
public boolean isSupportedType(Type genericType);
/**
* Create and return a new JsonGenerator for the given writer.
*/
public JsonGenerator createGenerator(Writer writer) throws IOException;
/**
* Create and return a new JsonParser for the given reader.
*/
public JsonParser createParser(Reader reader) throws IOException;
}
@@ -1,39 +0,0 @@
package com.avaje.ebean.text.json;
/**
* Marker interface for all the Raw JSON types.
* <p>
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
* The JSON elements that are not mapped to a bean property are made available
* to the JsonReadBeanVisitor.
* </p>
*
* @see JsonReadBeanVisitor
*
* @author rbygrave
*/
public interface JsonElement {
/**
* Return true if this is a JSON primitive type (null, boolean, number or
* string).
*/
public boolean isPrimitive();
/**
* Return the string value of this primitive JSON element.
* <p>
* This can not be used for JsonElementObject or JsonElementArray.
* </p>
*/
public String toPrimitiveString();
public Object eval(String exp);
public int evalInt(String exp);
public String evalString(String exp);
public boolean evalBoolean(String exp);
}
@@ -1,112 +0,0 @@
package com.avaje.ebean.text.json;
import java.util.ArrayList;
import java.util.List;
/**
* JSON Array element.
* <p>
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
* The JSON elements that are not mapped to a bean property are made available
* to the JsonReadBeanVisitor.
* </p>
*
* @see JsonReadBeanVisitor
*
* @author rbygrave
*/
public class JsonElementArray implements JsonElement {
private final List<JsonElement> values = new ArrayList<JsonElement>();
public List<JsonElement> getValues() {
return values;
}
public void add(JsonElement value) {
values.add(value);
}
public String toString() {
return values.toString();
}
public boolean isPrimitive() {
return false;
}
public String toPrimitiveString() {
return null;
}
private String[] split(String exp) {
int pos = exp.indexOf('.');
if (pos == -1) {
return new String[] { exp, null };
}
String exp0 = exp.substring(0, pos);
String exp1 = exp.substring(pos + 1);
return new String[] { exp0, exp1 };
}
public Object eval(String exp) {
String[] e = split(exp);
return eval(e[0], e[1]);
}
public int evalInt(String exp) {
String[] e = split(exp);
return evalInt(e[0], e[1]);
}
public String evalString(String exp) {
String[] e = split(exp);
return evalString(e[0], e[1]);
}
public boolean evalBoolean(String exp) {
// TODO Auto-generated method stub
return false;
}
private Object eval(String exp0, String exp1) {
if ("size".equals(exp0)) {
return values.size();
}
if ("isEmpty".equals(exp0)) {
return values.isEmpty();
}
int idx = Integer.parseInt(exp0);
JsonElement element = values.get(idx);
return element.eval(exp1);
}
private int evalInt(String exp0, String exp1) {
if ("size".equals(exp0)) {
return values.size();
}
if ("isEmpty".equals(exp0)) {
return values.isEmpty() ? 1 : 0;
}
int idx = Integer.parseInt(exp0);
JsonElement element = values.get(idx);
return element.evalInt(exp1);
}
private String evalString(String exp0, String exp1) {
if ("size".equals(exp0)) {
return String.valueOf(values.size());
}
if ("isEmpty".equals(exp0)) {
return String.valueOf(values.isEmpty());
}
int idx = Integer.parseInt(exp0);
JsonElement element = values.get(idx);
return element.evalString(exp1);
}
public String getString() {
return toString();
}
}
@@ -1,63 +0,0 @@
package com.avaje.ebean.text.json;
/**
* JSON boolean element.
* <p>
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
* The JSON elements that are not mapped to a bean property are made available
* to the JsonReadBeanVisitor.
* </p>
*
* @see JsonReadBeanVisitor
*
* @author rbygrave
*/
public class JsonElementBoolean implements JsonElement {
public static final JsonElementBoolean TRUE = new JsonElementBoolean(true);
public static final JsonElementBoolean FALSE = new JsonElementBoolean(false);
private final Boolean value;
private JsonElementBoolean(Boolean value) {
this.value = value;
}
public Boolean getValue() {
return value;
}
public String toString() {
return Boolean.toString(value);
}
public boolean isPrimitive() {
return true;
}
public String toPrimitiveString() {
return value.toString();
}
public Object eval(String exp) {
if (exp != null) {
throw new IllegalArgumentException("expression [" + exp + "] not allowed on boolean");
}
return value;
}
public int evalInt(String exp) {
return value ? 1 : 0;
}
public String evalString(String exp) {
return toString();
}
public boolean evalBoolean(String exp) {
return value;
}
}
@@ -1,57 +0,0 @@
package com.avaje.ebean.text.json;
/**
* JSON null element.
* <p>
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
* The JSON elements that are not mapped to a bean property are made available
* to the JsonReadBeanVisitor.
* </p>
*
* @see JsonReadBeanVisitor
*
* @author rbygrave
*/
public class JsonElementNull implements JsonElement {
public static final JsonElementNull NULL = new JsonElementNull();
private JsonElementNull() {
}
public String getValue() {
return "null";
}
public String toString() {
return "json null";
}
public boolean isPrimitive() {
return true;
}
public String toPrimitiveString() {
return null;
}
public Object eval(String exp) {
if (exp != null) {
throw new IllegalArgumentException("expression [" + exp + "] not allowed on null");
}
return null;
}
public int evalInt(String exp) {
return 0;
}
public String evalString(String exp) {
return null;
}
public boolean evalBoolean(String exp) {
return false;
}
}
@@ -1,67 +0,0 @@
package com.avaje.ebean.text.json;
/**
* JSON number element.
* <p>
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
* The JSON elements that are not mapped to a bean property are made available
* to the JsonReadBeanVisitor.
* </p>
*
* @see JsonReadBeanVisitor
*
* @author rbygrave
*/
public class JsonElementNumber implements JsonElement {
private final String value;
public JsonElementNumber(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public String toString() {
return value;
}
public boolean isPrimitive() {
return true;
}
public String toPrimitiveString() {
return value;
}
public Object eval(String exp) {
if (exp != null) {
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
}
return Double.parseDouble(value);
}
public int evalInt(String exp) {
if (exp != null) {
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
}
return Integer.parseInt(value);
}
public String evalString(String exp) {
if (exp != null) {
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
}
return value;
}
public boolean evalBoolean(String exp) {
if (exp != null) {
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
}
return Boolean.parseBoolean(value);
}
}
@@ -1,108 +0,0 @@
package com.avaje.ebean.text.json;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* JSON Object element.
* <p>
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
* The JSON elements that are not mapped to a bean property are made available
* to the JsonReadBeanVisitor.
* </p>
*
* @see JsonReadBeanVisitor
*
* @author rbygrave
*/
public class JsonElementObject implements JsonElement {
private final Map<String, JsonElement> map = new LinkedHashMap<String, JsonElement>();
public void put(String key, JsonElement value) {
map.put(key, value);
}
private String[] split(String exp) {
int pos = exp.indexOf('.');
if (pos == -1) {
return new String[] { exp, null };
}
String exp0 = exp.substring(0, pos);
String exp1 = exp.substring(pos + 1);
return new String[] { exp0, exp1 };
}
public Object eval(String exp) {
String[] e = split(exp);
return eval(e[0], e[1]);
}
public int evalInt(String exp) {
String[] e = split(exp);
return evalInt(e[0], e[1]);
}
public String evalString(String exp) {
if (exp == null) {
return map.toString();
}
String[] e = split(exp);
return evalString(e[0], e[1]);
}
public boolean evalBoolean(String exp) {
String[] e = split(exp);
return evalBoolean(e[0], e[1]);
}
private Object eval(String exp0, String exp1) {
JsonElement e = map.get(exp0);
return e == null ? null : e.eval(exp1);
}
private int evalInt(String exp0, String exp1) {
JsonElement e = map.get(exp0);
return e == null ? 0 : e.evalInt(exp1);
}
private String evalString(String exp0, String exp1) {
JsonElement e = map.get(exp0);
return e == null ? "" : e.evalString(exp1);
}
private boolean evalBoolean(String exp0, String exp1) {
JsonElement e = map.get(exp0);
return e == null ? false : e.evalBoolean(exp1);
}
public JsonElement get(String key) {
return map.get(key);
}
public JsonElement getValue(String key) {
return map.get(key);
}
public Set<String> keySet() {
return map.keySet();
}
public Set<Map.Entry<String, JsonElement>> entrySet() {
return map.entrySet();
}
public String toString() {
return map.toString();
}
public boolean isPrimitive() {
return false;
}
public String toPrimitiveString() {
return null;
}
}
@@ -1,71 +0,0 @@
package com.avaje.ebean.text.json;
/**
* JSON string element.
* <p>
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
* The JSON elements that are not mapped to a bean property are made available
* to the JsonReadBeanVisitor.
* </p>
*
* @see JsonReadBeanVisitor
*
* @author rbygrave
*/
public class JsonElementString implements JsonElement {
private final String value;
public JsonElementString(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public String toString() {
return value;
}
public boolean isPrimitive() {
return true;
}
public String toPrimitiveString() {
return value;
}
public Object eval(String exp) {
if (exp != null) {
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
}
return value;
}
public int evalInt(String exp) {
if (exp != null) {
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
}
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return 0;
}
}
public String evalString(String exp) {
if (exp != null) {
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
}
return value;
}
public boolean evalBoolean(String exp) {
if (exp != null) {
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
}
return Boolean.parseBoolean(exp);
}
}
@@ -1,34 +0,0 @@
package com.avaje.ebean.text.json;
import java.util.Map;
/**
* Provides for some custom handling of json content as it is read.
* <p>
* This visit method is called after all the known properties of the bean have
* been processed. Any JSON elements that could not be mapped to known bean
* properties are available in the unmapped Map.
* </p>
*
* @author rbygrave
*
* @param <T>
* The type of entity bean
*/
public interface JsonReadBeanVisitor<T> {
/**
* Visit the bean that has just been processed.
* <p>
* This provides a method of customising the bean and processing any custom
* JSON content.
* </p>
*
* @param bean
* the bean being processed
* @param unmapped
* Map of any JSON elements that didn't map to known bean properties
*/
public void visit(T bean, Map<String, JsonElement> unmapped);
}
@@ -1,71 +0,0 @@
package com.avaje.ebean.text.json;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Provides the ability to customise the reading of JSON content.
* <p>
* You can optionally provide a custom JsonValueAdapter to handle specific
* formatting for Date and DateTime types.
* </p>
* <p>
* You can optionally register JsonReadBeanVisitors to customise the processing
* of the beans as they are processed and handle any custom JSON elements that
* could not be mapped to bean properties.
* </p>
*
* @author rbygrave
*
*/
public class JsonReadOptions {
protected JsonValueAdapter valueAdapter;
protected Map<String, JsonReadBeanVisitor<?>> visitorMap;
/**
* Default constructor.
*/
public JsonReadOptions() {
this.visitorMap = new LinkedHashMap<String, JsonReadBeanVisitor<?>>();
}
/**
* Return the JsonValueAdapter.
*/
public JsonValueAdapter getValueAdapter() {
return valueAdapter;
}
/**
* Return the map of JsonReadBeanVisitor's.
*/
public Map<String, JsonReadBeanVisitor<?>> getVisitorMap() {
return visitorMap;
}
/**
* Set a JsonValueAdapter for custom DateTime and Date formatting.
*/
public JsonReadOptions setValueAdapter(JsonValueAdapter valueAdapter) {
this.valueAdapter = valueAdapter;
return this;
}
/**
* Register a JsonReadBeanVisitor for the root level.
*/
public JsonReadOptions addRootVisitor(JsonReadBeanVisitor<?> visitor) {
return addVisitor(null, visitor);
}
/**
* Register a JsonReadBeanVisitor for a given path.
*/
public JsonReadOptions addVisitor(String path, JsonReadBeanVisitor<?> visitor) {
visitorMap.put(path, visitor);
return this;
}
}
@@ -1,61 +0,0 @@
/**
* Copyright (C) 2009 Authors
*
* This file is part of Ebean.
*
* Ebean is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Ebean 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Ebean; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.avaje.ebean.text.json;
import java.sql.Timestamp;
/**
* Allows you to customise the Date and Timestamp formats.
* <p>
* There is not a standard JSON format for Date or Timestamp types. By default
* Ebean uses ISO8601 "yyyy-MM-dd'T'HH:mm:ss.SSSZ" and "yyyy-MM-dd".
* </p>
* <p>
* Note that Ebean will convert Joda types to either of the Date or Timestamp
* types and back for you.
* </p>
*
* @see JsonReadOptions
*
* @author rbygrave
*/
public interface JsonValueAdapter {
/**
* Convert the Date to json string.
*/
public String jsonFromDate(java.sql.Date date);
/**
* Convert the DateTime to json string.
*/
public String jsonFromTimestamp(java.sql.Timestamp date);
/**
* Parse the JSON string into a Date.
*/
public java.sql.Date jsonToDate(String jsonDate);
/**
* Parse the JSON DateTime into a Timestamp.
*/
public Timestamp jsonToTimestamp(String jsonDateTime);
}
@@ -1,33 +0,0 @@
package com.avaje.ebean.text.json;
/**
* Allows for customising the JSON write processing.
* <p>
* You can use this to add raw JSON content via {@link JsonWriter}.
* </p>
* <p>
* You register a JsonWriteBeanVisitor with {@link JsonWriteOptions}.
* </p>
*
* @author rbygrave
*
* @param <T>
* the type of entity bean
*
* @see JsonWriteOptions
*/
public interface JsonWriteBeanVisitor<T> {
/**
* Visit the bean that has just been writing it's content to JSON. You can
* write your own additional JSON content to the JsonWriter if you wish.
*
* @param bean
* the bean that has been writing it's content
* @param jsonWriter
* the JsonWriter which you can append custom json content to if you
* wish.
*/
public void visit(T bean, JsonWriter jsonWriter);
}
@@ -1,78 +1,23 @@
package com.avaje.ebean.text.json;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import com.avaje.ebean.text.PathProperties;
/**
* Provides options for customising the JSON write process.
* <p>
* You can optionally provide a custom JsonValueAdapter to handle specific
* formatting for Date and DateTime types.
* </p>
* <p>
* You can optionally register JsonWriteBeanVisitors to customise the processing
* of the beans as they are processed and <strong>add raw JSON
* elements</strong>.
* </p>
* <p>
* You can explicitly state which properties to include in the JSON output for
* the root level and each path.
* </p>
*
* <pre class="code">
* // find some customers ...
*
* List&lt;Customer&gt; list = Ebean.find(Customer.class).select(&quot;id, name, status, shippingAddress&quot;)
* .fetch(&quot;billingAddress&quot;,
* &quot;line1, city&quot;).fetch(&quot;billingAddress.country&quot;, &quot;*&quot;).fetch(&quot;contacts&quot;, &quot;firstName,email&quot;)
* .order().desc(&quot;id&quot;)
* .findList();
*
* JsonContext json = Ebean.createJsonContext();
*
* JsonWriteOptions writeOptions = new JsonWriteOptions();
* writeOptions.setRootPathVisitor(new JsonWriteBeanVisitor&lt;Customer&gt;() {
*
* public void visit(Customer bean, JsonWriter ctx) {
* System.out.println(&quot;write visit customer: &quot; + bean);
* ctx.appendKeyValue(&quot;dummyCust&quot;, &quot;34&quot;);
* ctx.appendKeyValue(&quot;smallCustObject&quot;, &quot;{\&quot;a\&quot;:34,\&quot;b\&quot;:\&quot;asdasdasd\&quot;}&quot;);
* }
* });
*
* writeOptions.setPathProperties(&quot;contacts&quot;, &quot;firstName,id&quot;);
* writeOptions.setPathVisitor(&quot;contacts&quot;, new JsonWriteBeanVisitor&lt;Contact&gt;() {
*
* public void visit(Contact bean, JsonWriter ctx) {
* System.out.println(&quot;write additional custom json on customer: &quot; + bean);
* ctx.appendKeyValue(&quot;dummy&quot;, &quot; 3400&quot; + bean.getId() + &quot;&quot;);
* ctx.appendKeyValue(&quot;smallObject&quot;, &quot;{\&quot;contactA\&quot;:34,\&quot;contactB\&quot;:\&quot;banana\&quot;}&quot;);
* }
*
* });
*
* // output as a JSON string with pretty formatting
* String s = json.toJsonString(list, true, writeOptions);
* String s = json.toJson(list, true, writeOptions);
*
* </pre>
*
* @see JsonContext#toList(Class, String, JsonReadOptions)
*
* @author rbygrave
*
*/
public class JsonWriteOptions {
protected String callback;
protected JsonValueAdapter valueAdapter;
protected Map<String, JsonWriteBeanVisitor<?>> visitorMap;
protected PathProperties pathProperties;
/**
@@ -88,138 +33,6 @@ public class JsonWriteOptions {
return o;
}
/**
* This creates and returns a copy of these options.
* <p>
* Note that it assumes that the JsonWriteBeanVisitor (if defined) are
* immutable and any JsonWriteBeanVisitor instances are shared between the
* original and the copy.
* </p>
*/
public JsonWriteOptions copy() {
JsonWriteOptions copy = new JsonWriteOptions();
copy.callback = callback;
copy.valueAdapter = valueAdapter;
copy.pathProperties = pathProperties;
if (visitorMap != null) {
copy.visitorMap = new HashMap<String, JsonWriteBeanVisitor<?>>(visitorMap);
}
return copy;
}
/**
* Return a JSONP callback function.
*/
public String getCallback() {
return callback;
}
/**
* Set a JSONP callback function.
*/
public JsonWriteOptions setCallback(String callback) {
this.callback = callback;
return this;
}
/**
* Return the JsonValueAdapter.
*/
public JsonValueAdapter getValueAdapter() {
return valueAdapter;
}
/**
* Set a JsonValueAdapter for custom DateTime and Date formatting.
*/
public JsonWriteOptions setValueAdapter(JsonValueAdapter valueAdapter) {
this.valueAdapter = valueAdapter;
return this;
}
/**
* Register a JsonWriteBeanVisitor for the root level.
*/
public JsonWriteOptions setRootPathVisitor(JsonWriteBeanVisitor<?> visitor) {
return setPathVisitor(null, visitor);
}
/**
* Register a JsonWriteBeanVisitor for the given path.
*/
public JsonWriteOptions setPathVisitor(String path, JsonWriteBeanVisitor<?> visitor) {
if (visitorMap == null) {
visitorMap = new HashMap<String, JsonWriteBeanVisitor<?>>();
}
visitorMap.put(path, visitor);
return this;
}
/**
* Set the properties to include in the JSON output for the given path.
*
* @param propertiesToInclude
* The set of properties to output
*/
public JsonWriteOptions setPathProperties(String path, Set<String> propertiesToInclude) {
if (pathProperties == null) {
pathProperties = new PathProperties();
}
pathProperties.put(path, propertiesToInclude);
return this;
}
/**
* Set the properties to include in the JSON output for the given path.
*
* @param propertiesToInclude
* Comma delimited list of properties to output
*/
public JsonWriteOptions setPathProperties(String path, String propertiesToInclude) {
return setPathProperties(path, parseProps(propertiesToInclude));
}
/**
* Set the properties to include in the JSON output for the root level.
*
* @param propertiesToInclude
* Comma delimited list of properties to output
*/
public JsonWriteOptions setRootPathProperties(String propertiesToInclude) {
return setPathProperties(null, parseProps(propertiesToInclude));
}
/**
* Set the properties to include in the JSON output for the root level.
*
* @param propertiesToInclude
* The set of properties to output
*/
public JsonWriteOptions setRootPathProperties(Set<String> propertiesToInclude) {
return setPathProperties(null, propertiesToInclude);
}
private Set<String> parseProps(String propertiesToInclude) {
LinkedHashSet<String> props = new LinkedHashSet<String>();
String[] split = propertiesToInclude.split(",");
for (int i = 0; i < split.length; i++) {
String s = split[i].trim();
if (s.length() > 0) {
props.add(s);
}
}
return props;
}
/**
* Return the Map of registered JsonWriteBeanVisitor's by path.
*/
public Map<String, JsonWriteBeanVisitor<?>> getVisitorMap() {
return visitorMap;
}
/**
* Set the Map of properties to include by path.
*/
@@ -1,28 +0,0 @@
package com.avaje.ebean.text.json;
/**
* The JSON Writer made available to JsonWriteBeanVisitor's so that you can
* append your own JSON content into the output.
*
* @see JsonWriteBeanVisitor
* @see JsonWriteOptions#setRootPathVisitor(JsonWriteBeanVisitor)
* @see JsonWriteOptions#setPathVisitor(String, JsonWriteBeanVisitor)
*
* @author rbygrave
*/
public interface JsonWriter {
/**
* Use this to append some custom content into the JSON output.
*
* @param key
* the json key
*
* @param rawJsonValue
* raw json value
*/
public void appendRawValue(String key, String rawJsonValue);
public void appendQuoteEscapeValue(String key, String rawJsonValue);
}
@@ -19,31 +19,10 @@
* .order().desc(&quot;id&quot;)
* .findList();
*
* JsonContext json = Ebean.createJsonContext();
*
* JsonWriteOptions writeOptions = new JsonWriteOptions();
* writeOptions.setRootPathVisitor(new JsonWriteBeanVisitor&lt;Customer&gt;() {
*
* public void visit(Customer bean, JsonWriter ctx) {
* System.out.println(&quot;write visit customer: &quot; + bean);
* ctx.appendKeyValue(&quot;dummyCust&quot;, &quot;34&quot;);
* ctx.appendKeyValue(&quot;smallCustObject&quot;, &quot;{\&quot;a\&quot;:34,\&quot;b\&quot;:\&quot;asdasdasd\&quot;}&quot;);
* }
* });
*
* writeOptions.setPathProperties(&quot;contacts&quot;, &quot;firstName,id&quot;);
* writeOptions.setPathVisitor(&quot;contacts&quot;, new JsonWriteBeanVisitor&lt;Contact&gt;() {
*
* public void visit(Contact bean, JsonWriter ctx) {
* System.out.println(&quot;write additional custom json on customer: &quot; + bean);
* ctx.appendKeyValue(&quot;dummy&quot;, &quot; 3400&quot; + bean.getId() + &quot;&quot;);
* ctx.appendKeyValue(&quot;smallObject&quot;, &quot;{\&quot;contactA\&quot;:34,\&quot;contactB\&quot;:\&quot;banana\&quot;}&quot;);
* }
*
* });
*
* // output as a JSON string with pretty formatting
* String s = json.toJsonString(list, true, writeOptions);
* JsonContext json = Ebean.json();
*
* // output as a JSON string
* String jsonOutput = json.toJson(list);
*
* </pre>
*/
@@ -44,9 +44,14 @@ public interface SpiExpressionRequest {
* Return the ordered list of bind values for all expressions in this request.
*/
public ArrayList<Object> getBindValues();
/**
* Increments the parameter index and returns that value.
*/
public int nextParameter();
/**
* Increments the parameter index and returns that value.
*/
public int nextParameter();
/**
* Append a DB Like clause.
*/
public void appendLike();
}
@@ -415,6 +415,13 @@ public class DefaultBeanLoader {
if (ebi.isReadOnly()) {
query.setReadOnly(true);
}
if (SpiQuery.Mode.REFRESH_BEAN.equals(mode)) {
// explicitly state to load all properties on REFRESH.
// Lobs default to fetch lazy so this forces lobs to be
// included in a 'refresh' query
query.select("*");
}
Object dbBean = query.findUnique();
if (dbBean == null) {
@@ -65,7 +65,6 @@ import com.avaje.ebean.meta.MetaBeanInfo;
import com.avaje.ebean.meta.MetaInfoManager;
import com.avaje.ebean.text.csv.CsvReader;
import com.avaje.ebean.text.json.JsonContext;
import com.avaje.ebean.text.json.JsonElement;
import com.avaje.ebeaninternal.api.LoadBeanRequest;
import com.avaje.ebeaninternal.api.LoadManyRequest;
import com.avaje.ebeaninternal.api.ScopeTrans;
@@ -286,6 +285,13 @@ public final class DefaultServer implements SpiEbeanServer {
ddlGenerator = (DdlGenerator)plugin;
}
}
if (ddlGenerator == null) {
// ServiceLoader not finding ddlGenerator (typically OSGi)
ddlGenerator = new DdlGenerator();
spiPlugins.add(ddlGenerator);
ddlGenerator.setup(this, this.getDatabasePlatform(), config.getServerConfig());
}
ebeanPlugins = Collections.unmodifiableList(spiPlugins);
}
@@ -1956,10 +1962,6 @@ public final class DefaultServer implements SpiEbeanServer {
if (typeInfo == null) {
return false;
}
Class<?> beanType = typeInfo.getBeanType();
if (JsonElement.class.isAssignableFrom(beanType)) {
return true;
}
return getBeanDescriptor(typeInfo.getBeanType()) != null;
}
@@ -2079,11 +2081,18 @@ public final class DefaultServer implements SpiEbeanServer {
return new CallStack(finalTrace);
}
public JsonContext createJsonContext() {
@Override
public JsonContext json() {
// immutable thread safe so return shared instance
return jsonContext;
}
@Override
public JsonContext createJsonContext() {
return json();
}
@Override
public void collectQueryStats(ObjectGraphNode node, long loadedBeanCount, long timeMicros) {
@@ -11,8 +11,6 @@ import com.avaje.ebean.config.ExternalTransactionManager;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.text.json.JsonContext;
import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebeaninternal.api.ClassUtil;
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
@@ -33,7 +31,6 @@ import com.avaje.ebeaninternal.server.query.DefaultRelationalQueryEngine;
import com.avaje.ebeaninternal.server.resource.ResourceManager;
import com.avaje.ebeaninternal.server.resource.ResourceManagerFactory;
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
import com.avaje.ebeaninternal.server.text.json.DefaultJsonValueAdapter;
import com.avaje.ebeaninternal.server.transaction.AutoCommitTransactionManager;
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
import com.avaje.ebeaninternal.server.transaction.ExternalTransactionScopeManager;
@@ -42,10 +39,13 @@ import com.avaje.ebeaninternal.server.transaction.TransactionManager;
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
import com.avaje.ebeaninternal.server.type.TypeManager;
import com.fasterxml.jackson.core.JsonFactory;
/**
* Used to extend the ServerConfig with additional objects used to configure and
* construct an EbeanServer.
*
* @author rbygrave
*/
public class InternalConfiguration {
@@ -89,10 +89,13 @@ public class InternalConfiguration {
private final XmlConfig xmlConfig;
private final JsonFactory jsonFactory;
public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager,
ServerCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor,
ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
this.jsonFactory = serverConfig.getJsonFactory();
this.xmlConfig = xmlConfig;
this.pstmtBatch = pstmtBatch;
this.clusterManager = clusterManager;
@@ -163,16 +166,7 @@ public class InternalConfiguration {
public JsonContext createJsonContext(SpiEbeanServer server) {
String s = serverConfig.getProperty("json.pretty", "false");
boolean dfltPretty = "true".equalsIgnoreCase(s);
s = serverConfig.getProperty("json.jsonValueAdapter", null);
JsonValueAdapter va = new DefaultJsonValueAdapter();
if (s != null) {
va = (JsonValueAdapter) ClassUtil.newInstance(s, this.getClass());
}
return new DJsonContext(server, va, dfltPretty);
return new DJsonContext(server, jsonFactory);
}
public XmlConfig getXmlConfig() {
@@ -0,0 +1,266 @@
package com.avaje.ebeaninternal.server.core;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.ExpressionFactory;
import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.config.ExternalTransactionManager;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.text.json.JsonContext;
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManagerFactory;
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
import com.avaje.ebeaninternal.server.deploy.DeployOrmXml;
import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool;
import com.avaje.ebeaninternal.server.persist.Binder;
import com.avaje.ebeaninternal.server.persist.DefaultPersister;
import com.avaje.ebeaninternal.server.query.CQueryEngine;
import com.avaje.ebeaninternal.server.query.DefaultOrmQueryEngine;
import com.avaje.ebeaninternal.server.query.DefaultRelationalQueryEngine;
import com.avaje.ebeaninternal.server.resource.ResourceManager;
import com.avaje.ebeaninternal.server.resource.ResourceManagerFactory;
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
<<<<<<< HEAD
import com.avaje.ebeaninternal.server.text.json.DefaultJsonValueAdapter;
import com.avaje.ebeaninternal.server.transaction.AutoCommitTransactionManager;
=======
>>>>>>> json-refactor
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
import com.avaje.ebeaninternal.server.transaction.ExternalTransactionScopeManager;
import com.avaje.ebeaninternal.server.transaction.JtaTransactionManager;
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
import com.avaje.ebeaninternal.server.type.TypeManager;
/**
* Used to extend the ServerConfig with additional objects used to configure and
* construct an EbeanServer.
*/
public class InternalConfiguration {
private static final Logger logger = LoggerFactory.getLogger(InternalConfiguration.class);
private final ServerConfig serverConfig;
private final BootupClasses bootupClasses;
private final DeployInherit deployInherit;
private final ResourceManager resourceManager;
private final DeployOrmXml deployOrmXml;
private final TypeManager typeManager;
private final Binder binder;
private final DeployCreateProperties deployCreateProperties;
private final DeployUtil deployUtil;
private final BeanDescriptorManager beanDescriptorManager;
private final TransactionManager transactionManager;
private final TransactionScopeManager transactionScopeManager;
private final CQueryEngine cQueryEngine;
private final ClusterManager clusterManager;
private final ServerCacheManager cacheManager;
private final ExpressionFactory expressionFactory;
private final SpiBackgroundExecutor backgroundExecutor;
private final PstmtBatch pstmtBatch;
private final XmlConfig xmlConfig;
public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager,
ServerCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor,
ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
this.xmlConfig = xmlConfig;
this.pstmtBatch = pstmtBatch;
this.clusterManager = clusterManager;
this.backgroundExecutor = backgroundExecutor;
this.cacheManager = cacheManager;
this.serverConfig = serverConfig;
this.bootupClasses = bootupClasses;
this.expressionFactory = new DefaultExpressionFactory();
this.typeManager = new DefaultTypeManager(serverConfig, bootupClasses);
this.binder = new Binder(typeManager);
this.resourceManager = ResourceManagerFactory.createResourceManager(serverConfig);
this.deployOrmXml = new DeployOrmXml(resourceManager.getResourceSource());
this.deployInherit = new DeployInherit(bootupClasses);
this.deployCreateProperties = new DeployCreateProperties(typeManager);
this.deployUtil = new DeployUtil(typeManager, serverConfig);
this.beanDescriptorManager = new BeanDescriptorManager(this);
beanDescriptorManager.deploy();
this.transactionManager = createTransactionManager();
this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), binder);
ExternalTransactionManager externalTransactionManager = serverConfig.getExternalTransactionManager();
if (externalTransactionManager == null && serverConfig.isUseJtaTransactionManager()) {
externalTransactionManager = new JtaTransactionManager();
}
if (externalTransactionManager != null) {
externalTransactionManager.setTransactionManager(transactionManager);
this.transactionScopeManager = new ExternalTransactionScopeManager(transactionManager, externalTransactionManager);
logger.info("Using Transaction Manager [" + externalTransactionManager.getClass() + "]");
} else {
this.transactionScopeManager = new DefaultTransactionScopeManager(transactionManager);
}
}
/**
* Create the TransactionManager taking into account autoCommit mode.
*/
private TransactionManager createTransactionManager() {
if (isAutoCommitMode()) {
return new AutoCommitTransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
}
return new TransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
}
/**
* Return true if autoCommit mode is on.
*/
private boolean isAutoCommitMode() {
if (serverConfig.isAutoCommitMode()) {
// explicitly set
return true;
}
DataSource dataSource = serverConfig.getDataSource();
if (dataSource instanceof DataSourcePool && ((DataSourcePool)dataSource).getAutoCommit()) {
// We know the DataSourcePool is using autoCommit
return true;
}
return false;
}
public JsonContext createJsonContext(SpiEbeanServer server) {
return new DJsonContext(server);
}
public XmlConfig getXmlConfig() {
return xmlConfig;
}
public AutoFetchManager createAutoFetchManager(SpiEbeanServer server) {
return AutoFetchManagerFactory.create(server, serverConfig, resourceManager);
}
public RelationalQueryEngine createRelationalQueryEngine() {
return new DefaultRelationalQueryEngine(binder, serverConfig.getDatabaseBooleanTrue());
}
public OrmQueryEngine createOrmQueryEngine() {
return new DefaultOrmQueryEngine(beanDescriptorManager, cQueryEngine);
}
public Persister createPersister(SpiEbeanServer server) {
return new DefaultPersister(server, binder, beanDescriptorManager, pstmtBatch);
}
public PstmtBatch getPstmtBatch() {
return pstmtBatch;
}
public ServerCacheManager getCacheManager() {
return cacheManager;
}
public BootupClasses getBootupClasses() {
return bootupClasses;
}
public DatabasePlatform getDatabasePlatform() {
return serverConfig.getDatabasePlatform();
}
public ServerConfig getServerConfig() {
return serverConfig;
}
public ExpressionFactory getExpressionFactory() {
return expressionFactory;
}
public TypeManager getTypeManager() {
return typeManager;
}
public Binder getBinder() {
return binder;
}
public BeanDescriptorManager getBeanDescriptorManager() {
return beanDescriptorManager;
}
public DeployInherit getDeployInherit() {
return deployInherit;
}
public ResourceManager getResourceManager() {
return resourceManager;
}
public DeployOrmXml getDeployOrmXml() {
return deployOrmXml;
}
public DeployCreateProperties getDeployCreateProperties() {
return deployCreateProperties;
}
public DeployUtil getDeployUtil() {
return deployUtil;
}
public TransactionManager getTransactionManager() {
return transactionManager;
}
public TransactionScopeManager getTransactionScopeManager() {
return transactionScopeManager;
}
public CQueryEngine getCQueryEngine() {
return cQueryEngine;
}
public ClusterManager getClusterManager() {
return clusterManager;
}
public SpiBackgroundExecutor getBackgroundExecutor() {
return backgroundExecutor;
}
}
@@ -71,6 +71,15 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
this.readOnly = query.isReadOnly();
}
/**
* Return the database platform like clause.
*/
@Override
public String getDBLikeClause() {
return ebeanServer.getDatabasePlatform().getLikeClause();
}
public void executeSecondaryQueries(int defaultQueryBatch) {
loadContext.executeSecondaryQueries(this, defaultQueryBatch);
}
@@ -95,4 +95,9 @@ public interface SpiOrmQueryRequest<T> {
*/
public BeanCollection<T> getFromQueryCache();
/**
* Return the Database platform like clause.
*/
public String getDBLikeClause();
}
@@ -0,0 +1,87 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* A visitor that creates indexes for columns annotated with ColumnIndex
*
* @author rvbiljouw
* @see com.avaje.ebean.annotation.Index
*/
public class CreateIndexVisitor extends AbstractBeanVisitor {
private final IndexPropertyVisitor iv;
public CreateIndexVisitor(DdlGenContext ctx) {
this.iv = new IndexPropertyVisitor(ctx);
}
@Override
public void visitBegin() {
}
@Override
public boolean visitBean(BeanDescriptor<?> descriptor) {
return descriptor.isInheritanceRoot();
}
@Override
public PropertyVisitor visitProperty(BeanProperty p) {
return iv;
}
@Override
public void visitBeanEnd(BeanDescriptor<?> descriptor) {
visitInheritanceProperties(descriptor, iv);
}
@Override
public void visitEnd() {
}
private static final class IndexPropertyVisitor extends BaseTablePropertyVisitor {
private final DdlGenContext ctx;
public IndexPropertyVisitor(DdlGenContext ctx) {
this.ctx = ctx;
}
@Override
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
}
@Override
public void visitOneImported(BeanPropertyAssocOne<?> p) {
}
@Override
public void visitScalar(BeanProperty p) {
String baseTable = p.getBeanDescriptor().getBaseTable();
if (p.isIndexed()) {
String indexName = p.getIndexName();
if (indexName.length() == 0) {
indexName = ctx.getDdlSyntax().getIndexName(baseTable, p.getDbColumn(), ctx.incrementIxCount());
}
ctx.write("create index ")
.write(indexName)
.write(" on ")
.write(baseTable)
.write("(")
.write(p.getDbColumn())
.write(");")
.writeNewLine();
}
}
@Override
public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) {
}
}
}
@@ -98,17 +98,17 @@ public class DdlGenerator implements SpiEbeanPlugin {
}
}
protected void writeDrop(String dropFile) {
protected void writeDrop(String dropFile) {
try {
String c = generateDropDdl();
writeFile(dropFile, c);
try {
String c = generateDropDdl();
writeFile(dropFile, c);
} catch (IOException e) {
String msg = "Error generating Drop DDL";
throw new PersistenceException(msg, e);
}
}
} catch (IOException e) {
String msg = "Error generating Drop DDL";
throw new PersistenceException(msg, e);
}
}
protected void writeCreate(String createFile) {
@@ -149,6 +149,9 @@ public class DdlGenerator implements SpiEbeanPlugin {
AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(ctx);
VisitorUtil.visit(server, fkeys);
CreateIndexVisitor indexes = new CreateIndexVisitor(ctx);
VisitorUtil.visit(server, indexes);
ctx.flush();
createContent = ctx.getContent();
return createContent;
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.deploy;
import java.io.IOException;
import java.util.Iterator;
import com.avaje.ebean.EbeanServer;
@@ -9,7 +10,7 @@ import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
/**
* Helper functions for performing tasks on Lists Sets or Maps.
@@ -59,9 +60,9 @@ public interface BeanCollectionHelp<T> {
*/
public void refresh(BeanCollection<?> bc, EntityBean parentBean);
/**
* Write the collection out as json.
*/
public void jsonWrite(WriteJsonContext ctx, String name, Object collection, boolean explicitInclude);
/**
* Write the collection out as json.
*/
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException;
}
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.deploy;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -34,8 +35,6 @@ import com.avaje.ebean.event.BeanPersistListener;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.meta.MetaBeanInfo;
import com.avaje.ebean.meta.MetaQueryPlanStatistic;
import com.avaje.ebean.text.TextException;
import com.avaje.ebean.text.json.JsonWriteBeanVisitor;
import com.avaje.ebeaninternal.api.HashQueryPlan;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.SpiQuery;
@@ -62,15 +61,13 @@ import com.avaje.ebeaninternal.server.query.CQueryPlan;
import com.avaje.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
import com.avaje.ebeaninternal.server.query.SplitName;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
import com.avaje.ebeaninternal.server.text.json.ReadJsonContext;
import com.avaje.ebeaninternal.server.text.json.ReadJsonContext.ReadBeanState;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext.WriteBeanState;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.type.TypeManager;
import com.avaje.ebeaninternal.util.SortByClause;
import com.avaje.ebeaninternal.util.SortByClause.Property;
import com.avaje.ebeaninternal.util.SortByClauseParser;
import com.fasterxml.jackson.core.JsonParser;
/**
* Describes Beans including their deployment information.
@@ -195,12 +192,12 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
/**
* Inheritance information. Server side only.
*/
private final InheritInfo inheritInfo;
protected final InheritInfo inheritInfo;
/**
* Derived list of properties that make up the unique id.
*/
private final BeanProperty idProperty;
protected final BeanProperty idProperty;
private final int idPropertyIndex;
/**
@@ -327,7 +324,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
private final boolean cacheSharableBeans;
private final BeanDescriptorCacheHelp<T> cacheHelp;
private final BeanDescriptorJsonHelp<T> jsonHelp;
private final String defaultSelectClause;
private final Set<String> defaultSelectClauseSet;
@@ -422,7 +420,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly();
this.cacheHelp = new BeanDescriptorCacheHelp<T>(this, owner.getCacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported);
this.jsonHelp = new BeanDescriptorJsonHelp<T>(this);
// Check if there are no cascade save associated beans ( subject to change
// in initialiseOther()). Note that if we are in an inheritance hierarchy
@@ -1210,8 +1208,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
convertSetId(id, eb);
EntityBeanIntercept ebi = eb._ebean_getIntercept();
ebi.setBeanLoaderByServerName(ebeanServer.getName());
ebi.setBeanLoader(ebeanServer);
// Note: not creating proxies for many's...
ebi.setReference(idPropertyIndex);
@@ -2116,167 +2113,23 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
return propertiesLocal;
}
public void jsonWrite(WriteJsonContext ctx, EntityBean bean) {
if (bean != null) {
ctx.appendObjectBegin();
WriteBeanState prevState = ctx.pushBeanState(bean);
if (inheritInfo != null) {
InheritInfo localInheritInfo = inheritInfo.readType(bean.getClass());
String discValue = localInheritInfo.getDiscriminatorStringValue();
String discColumn = localInheritInfo.getDiscriminatorColumn();
ctx.appendDiscriminator(discColumn, discValue);
BeanDescriptor<?> localDescriptor = localInheritInfo.getBeanDescriptor();
localDescriptor.jsonWriteProperties(ctx, bean);
} else {
jsonWriteProperties(ctx, bean);
}
ctx.pushPreviousState(prevState);
ctx.appendObjectEnd();
}
}
@SuppressWarnings("unchecked")
private void jsonWriteProperties(WriteJsonContext ctx, EntityBean bean) {
JsonWriteBeanVisitor<T> beanVisitor = (JsonWriteBeanVisitor<T>) ctx.getBeanVisitor();
Set<String> props = ctx.getIncludeProperties();
boolean explicitAllProps;
if (props == null) {
explicitAllProps = false;
} else {
explicitAllProps = props.contains("*");
if (explicitAllProps || props.isEmpty()) {
props = null;
}
}
if (idProperty != null) {
Object idValue = idProperty.getValue(bean);
if (idValue != null) {
if (props == null || props.contains(idProperty.getName())) {
idProperty.jsonWrite(ctx, bean);
}
}
}
if (!explicitAllProps && props == null) {
// just render the loaded properties
props = ((EntityBean)bean)._ebean_getIntercept().getLoadedPropertyNames();
}
if (props != null) {
// render only the appropriate properties (when not all properties)
for (String prop : props) {
BeanProperty p = getBeanProperty(prop);
if (p != null && !p.isId()) {
p.jsonWrite(ctx, bean);
}
}
} else {
if (explicitAllProps || !isReference(bean._ebean_getIntercept())) {
// render all the properties and invoke lazy loading if required
for (int j = 0; j < propertiesNonTransient.length; j++) {
propertiesNonTransient[j].jsonWrite(ctx, bean);
}
for (int j = 0; j < propertiesTransient.length; j++) {
propertiesTransient[j].jsonWrite(ctx, bean);
}
}
}
if (beanVisitor != null) {
beanVisitor.visit((T) bean, ctx);
}
}
@SuppressWarnings("unchecked")
public T jsonReadBean(ReadJsonContext ctx, String path) {
ReadBeanState beanState = jsonRead(ctx, path);
if (beanState == null) {
return null;
} else {
return (T) beanState.getBean();
}
}
public ReadBeanState jsonRead(ReadJsonContext ctx, String path) {
if (!ctx.readObjectBegin()) {
// the object is null
return null;
}
if (inheritInfo == null) {
return jsonReadObject(ctx, path);
} else {
// check for the discriminator value to determine the correct sub type
String discColumn = inheritInfo.getRoot().getDiscriminatorColumn();
if (!ctx.readKeyNext()) {
String msg = "Error reading inheritance discriminator - expected [" + discColumn + "] but no json key?";
throw new TextException(msg);
}
String propName = ctx.getTokenKey();
String discValue;
if (propName.equalsIgnoreCase(discColumn)) {
discValue = ctx.readScalarValue();
if (!ctx.readValueNext()) {
// Expected to read a comma to setup for reading the real properties of the bean
String msg = "Error reading inheritance discriminator [" + discColumn + "]. Expected more json name values?";
throw new TextException(msg);
}
} else {
// Assume that the we are just reading using this bean type
// Push the token key back so that it is re-read as it is one
// of the real properties of the bean itself
ctx.pushTokenKey();
discValue = inheritInfo.getDiscriminatorStringValue();
}
// determine the sub type for this particular json object
InheritInfo localInheritInfo = inheritInfo.readType(discValue);
BeanDescriptor<?> localDescriptor = localInheritInfo.getBeanDescriptor();
return localDescriptor.jsonReadObject(ctx, path);
}
}
public void jsonWrite(WriteJson writeJson, EntityBean bean) throws IOException {
jsonHelp.jsonWrite(writeJson, bean, null);
}
private ReadBeanState jsonReadObject(ReadJsonContext ctx, String path) {
public void jsonWrite(WriteJson writeJson, EntityBean bean, String key) throws IOException {
jsonHelp.jsonWrite(writeJson, bean, key);
}
EntityBean bean = createEntityBean();
ctx.pushBean(bean, path, this);
do {
if (!ctx.readKeyNext()) {
break;
} else {
// we read a property key ...
String propName = ctx.getTokenKey();
BeanProperty p = getBeanProperty(propName);
if (p != null) {
p.jsonRead(ctx, bean);
ctx.setProperty(propName);
} else {
// unknown property key ...
ctx.readUnmappedJson(propName);
}
if (!ctx.readValueNext()) {
break;
}
}
} while (true);
return ctx.popBeanState();
protected void jsonWriteProperties(WriteJson writeJson, EntityBean bean) throws IOException {
jsonHelp.jsonWriteProperties(writeJson, bean);
}
public T jsonRead(JsonParser parser, String path) throws IOException {
return jsonHelp.jsonRead(parser, path);
}
protected T jsonReadObject(JsonParser parser, String path) throws IOException {
return jsonHelp.jsonReadObject(parser, path);
}
}
@@ -429,18 +429,21 @@ public final class BeanDescriptorCacheHelp<T> {
EntityBean bean = desc.createEntityBean();
desc.convertSetId(id, bean);
EntityBeanIntercept ebi = bean._ebean_getIntercept();
ebi.setBeanLoader(desc.getEbeanServer());
if (Boolean.TRUE.equals(readOnly)) {
bean._ebean_getIntercept().setReadOnly(true);
ebi.setReadOnly(true);
}
beanLoadData(bean, data);
if (beanLog.isTraceEnabled()) {
beanLog.trace(" GET {}({}) - hit", cacheName, id);
}
return (T) bean;
}
/**
* Remove a bean from the cache given its Id.
*/
@@ -0,0 +1,131 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.avaje.ebeaninternal.server.text.json.WriteJson.WriteBean;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import java.io.IOException;
public class BeanDescriptorJsonHelp<T> {
private final BeanDescriptor<T> desc;
private final InheritInfo inheritInfo;
public BeanDescriptorJsonHelp(BeanDescriptor<T> desc) {
this.desc = desc;
this.inheritInfo = desc.inheritInfo;
}
public void jsonWrite(WriteJson writeJson, EntityBean bean, String key) throws IOException {
writeJson.writeStartObject(key);
if (inheritInfo == null) {
jsonWriteProperties(writeJson, bean);
} else {
InheritInfo localInheritInfo = inheritInfo.readType(bean.getClass());
String discValue = localInheritInfo.getDiscriminatorStringValue();
String discColumn = localInheritInfo.getDiscriminatorColumn();
writeJson.gen().writeStringField(discColumn, discValue);
BeanDescriptor<?> localDescriptor = localInheritInfo.getBeanDescriptor();
localDescriptor.jsonWriteProperties(writeJson, bean);
}
writeJson.writeEndObject();
}
protected void jsonWriteProperties(WriteJson writeJson, EntityBean bean) throws IOException {
WriteBean writeBean = writeJson.createWriteBean(desc, bean);
writeBean.write(writeJson);
}
@SuppressWarnings("unchecked")
public T jsonRead(JsonParser parser, String path) throws IOException {
JsonToken token = parser.nextToken();
if (JsonToken.VALUE_NULL == token || JsonToken.END_ARRAY == token) {
return null;
}
if (JsonToken.START_OBJECT != token) {
throw new JsonParseException("Unexpected token "+token+" - expecting start_object", parser.getCurrentLocation());
}
if (desc.inheritInfo == null) {
return jsonReadObject(parser, path);
}
// check for the discriminator value to determine the correct sub type
String discColumn = inheritInfo.getRoot().getDiscriminatorColumn();
token = parser.nextToken();
if (token != JsonToken.FIELD_NAME) {
String msg = "Error reading inheritance discriminator - expected [" + discColumn + "] but no json key?";
throw new JsonParseException(msg, parser.getCurrentLocation());
}
String propName = parser.getCurrentName();
if (!propName.equalsIgnoreCase(discColumn)) {
// just try to assume this is the correct bean type in the inheritance
BeanProperty property = desc.getBeanProperty(propName);
if (property != null) {
EntityBean bean = desc.createEntityBean();
property.jsonRead(parser, bean);
return jsonReadProperties(parser, bean);
}
String msg = "Error reading inheritance discriminator, expected property ["+discColumn+"] but got [" + propName + "] ?";
throw new JsonParseException(msg, parser.getCurrentLocation());
}
String discValue = parser.nextTextValue();
// determine the sub type for this particular json object
InheritInfo localInheritInfo = inheritInfo.readType(discValue);
BeanDescriptor<?> localDescriptor = localInheritInfo.getBeanDescriptor();
return (T) localDescriptor.jsonReadObject(parser, path);
}
protected T jsonReadObject(JsonParser parser, String path) throws IOException {
EntityBean bean = desc.createEntityBean();
return jsonReadProperties(parser, bean);
}
@SuppressWarnings("unchecked")
protected T jsonReadProperties(JsonParser parser, EntityBean bean) throws IOException {
do {
JsonToken event = parser.nextToken();
if (JsonToken.FIELD_NAME == event) {
String key = parser.getCurrentName();
BeanProperty p = desc.getBeanProperty(key);
if (p != null) {
p.jsonRead(parser, bean);
} else {
// Object rawValue = EJson.parse(parser);
// unknown property key ...
// ctx.readUnmappedJson(propName);
}
} else if (JsonToken.END_OBJECT == event) {
break;
} else {
throw new RuntimeException("Unexpected token " + event + " - expecting key or end_object at: " + parser.getCurrentLocation());
}
} while (true);
return (T)bean;
}
}
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.deploy;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -12,7 +13,7 @@ import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.common.BeanList;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
/**
* Helper object for dealing with Lists.
@@ -128,7 +129,7 @@ public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
}
}
public void jsonWrite(WriteJsonContext ctx, String name, Object collection, boolean explicitInclude) {
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
List<?> list;
if (collection instanceof BeanCollection<?>) {
@@ -147,15 +148,11 @@ public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
list = (List<?>) collection;
}
ctx.beginAssocMany(name);
ctx.writeStartArray(name);
for (int j = 0; j < list.size(); j++) {
if (j > 0) {
ctx.appendComma();
}
Object detailBean = list.get(j);
targetDescriptor.jsonWrite(ctx, (EntityBean)detailBean);
targetDescriptor.jsonWrite(ctx, (EntityBean)list.get(j));
}
ctx.endAssocMany();
ctx.writeEndArray();
}
}
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.deploy;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -13,7 +14,7 @@ import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.common.BeanMap;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
/**
* Helper specifically for dealing with Maps.
@@ -156,7 +157,7 @@ public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
}
}
public void jsonWrite(WriteJsonContext ctx, String name, Object collection, boolean explicitInclude) {
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
Map<?,?> map;
if (collection instanceof BeanCollection<?>){
@@ -175,19 +176,14 @@ public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
map = (Map<?,?>)collection;
}
int count = 0;
ctx.beginAssocMany(name);
ctx.writeStartArray(name);
Iterator<?> it = map.entrySet().iterator();
while (it.hasNext()) {
Entry<?, ?> entry = (Entry<?, ?>)it.next();
if (count++ > 0){
ctx.appendComma();
}
//FIXME: json write map key ...
Object detailBean = entry.getValue();
targetDescriptor.jsonWrite(ctx, (EntityBean)detailBean);
targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue());
}
ctx.endAssocMany();
ctx.writeEndArray();
}
}
@@ -18,7 +18,6 @@ import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.text.StringFormatter;
import com.avaje.ebean.text.StringParser;
import com.avaje.ebean.text.TextException;
import com.avaje.ebeaninternal.server.core.InternString;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
@@ -30,10 +29,11 @@ import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
import com.avaje.ebeaninternal.server.reflect.BeanReflectGetter;
import com.avaje.ebeaninternal.server.reflect.BeanReflectSetter;
import com.avaje.ebeaninternal.server.text.json.ReadJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* Description of a property of a bean. Includes its deployment information such
@@ -262,6 +262,9 @@ public class BeanProperty implements ElPropertyValue {
final boolean jsonDeserialize;
final boolean indexed;
final String indexName;
public BeanProperty(DeployBeanProperty deploy) {
this(null, null, deploy);
}
@@ -271,7 +274,8 @@ public class BeanProperty implements ElPropertyValue {
this.descriptor = descriptor;
this.name = InternString.intern(deploy.getName());
this.propertyIndex = deploy.getPropertyIndex();
this.indexed = deploy.isIndexed();
this.indexName = deploy.getIndexName();
this.unidirectionalShadow = deploy.isUndirectionalShadow();
this.discriminator = deploy.isDiscriminator();
this.localEncrypted = deploy.isLocalEncrypted();
@@ -362,6 +366,8 @@ public class BeanProperty implements ElPropertyValue {
this.name = InternString.intern(source.getName());
this.propertyIndex = source.propertyIndex;
this.indexed = source.isIndexed();
this.indexName = source.getIndexName();
this.dbColumn = InternString.intern(override.getDbColumn());
this.sqlFormulaJoin = InternString.intern(override.getSqlFormulaJoin());
this.sqlFormulaSelect = InternString.intern(override.getSqlFormulaSelect());
@@ -446,7 +452,7 @@ public class BeanProperty implements ElPropertyValue {
}
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain,
boolean propertyDeploy) {
boolean propertyDeploy) {
throw new PersistenceException("Not valid on scalar bean property " + getFullBeanName());
}
@@ -475,17 +481,17 @@ public class BeanProperty implements ElPropertyValue {
* Return true if this property maps to the inheritance discriminator column.
*/
public boolean isDiscriminator() {
return discriminator;
return discriminator;
}
/**
* Return true if the underlying type is mutable.
*/
public boolean isMutableScalarType() {
if (scalarType == null) {
return false;
}
return scalarType.isMutable();
if (scalarType == null) {
return false;
}
return scalarType.isMutable();
}
public void copyProperty(EntityBean sourceBean, EntityBean destBean) {
@@ -665,6 +671,14 @@ public class BeanProperty implements ElPropertyValue {
public BeanProperty getBeanProperty() {
return this;
}
public boolean isIndexed() {
return indexed;
}
public String getIndexName() {
return indexName;
}
/**
* Return the getter method.
@@ -725,12 +739,12 @@ public class BeanProperty implements ElPropertyValue {
private static Object[] NO_ARGS = new Object[0];
public Object getCacheDataValue(EntityBean bean){
return getValue(bean);
}
public void setCacheDataValue(EntityBean bean, Object cacheData){
setValue(bean, cacheData);
public Object getCacheDataValue(EntityBean bean) {
return getValue(bean);
}
public void setCacheDataValue(EntityBean bean, Object cacheData) {
setValue(bean, cacheData);
}
/**
@@ -819,10 +833,9 @@ public class BeanProperty implements ElPropertyValue {
return false;
}
@Override
public boolean containsFormulaWithJoin() {
return formula && sqlFormulaJoin != null;
return formula && sqlFormulaJoin != null;
}
public boolean containsManySince(String sinceProperty) {
@@ -880,10 +893,10 @@ public class BeanProperty implements ElPropertyValue {
/**
* Return true if the mutable value is considered dirty.
* This is only used for 'mutable' scalar types like hstore etc.
* This is only used for 'mutable' scalar types like hstore etc.
*/
public boolean isDirtyValue(Object value) {
return scalarType.isDirty(value);
return scalarType.isDirty(value);
}
/**
@@ -906,10 +919,10 @@ public class BeanProperty implements ElPropertyValue {
}
public int getJdbcType() {
return scalarType == null ? 0 : scalarType.getJdbcType();
return scalarType == null ? 0 : scalarType.getJdbcType();
}
public Object parseDateTime(long systemTimeMillis) {
public Object parseDateTime(long systemTimeMillis) {
return scalarType.parseDateTime(systemTimeMillis);
}
@@ -972,10 +985,10 @@ public class BeanProperty implements ElPropertyValue {
* Return true if this is the natural key property.
*/
public boolean isNaturalKey() {
return naturalKey;
return naturalKey;
}
/**
/**
* Return true if this property is mandatory.
*/
public boolean isNullable() {
@@ -1008,7 +1021,7 @@ public class BeanProperty implements ElPropertyValue {
* Return true if this property is loadable from a resultSet.
*/
public boolean isLoadProperty() {
return !isTransient || formula;
return !isTransient || formula;
}
/**
@@ -1051,10 +1064,10 @@ public class BeanProperty implements ElPropertyValue {
* Lob's usually default to fetch lazy.
*/
public boolean isFetchEager() {
return fetchEager;
return fetchEager;
}
/**
/**
* Return true if this is mapped to a Clob Blob LongVarchar or
* LongVarbinary.
*/
@@ -1064,17 +1077,17 @@ public class BeanProperty implements ElPropertyValue {
private boolean isLobType(int type) {
switch (type) {
case Types.CLOB:
return true;
case Types.BLOB:
return true;
case Types.LONGVARBINARY:
return true;
case Types.LONGVARCHAR:
return true;
case Types.CLOB:
return true;
case Types.BLOB:
return true;
case Types.LONGVARBINARY:
return true;
case Types.LONGVARCHAR:
return true;
default:
return false;
default:
return false;
}
}
@@ -1173,35 +1186,30 @@ public class BeanProperty implements ElPropertyValue {
return name;
}
@SuppressWarnings("unchecked")
public void jsonWrite(WriteJsonContext ctx, EntityBean bean) {
if(!jsonSerialize){
return;
}
Object value = getValueIntercept(bean);
if (value == null) {
ctx.appendNull(name);
} else {
ctx.appendNameValue(name, scalarType, value);
}
public void jsonWrite(WriteJson writeJson, EntityBean bean) throws IOException {
if (!jsonSerialize) {
return;
}
Object value = getValueIntercept(bean);
if (value == null) {
writeJson.writeNull(name);
} else {
scalarType.jsonWrite(writeJson.gen(), name, value);
}
}
public void jsonRead(JsonParser ctx, EntityBean bean) throws IOException {
if (!jsonDeserialize) {
return;
}
public void jsonRead(ReadJsonContext ctx, EntityBean bean) {
if(!jsonDeserialize){
return;
}
String jsonValue;
try {
jsonValue = ctx.readScalarValue();
} catch (TextException e){
throw new TextException("Error reading property "+getFullBeanName(), e);
}
Object objValue;
if (jsonValue == null) {
objValue = null;
} else {
objValue = scalarType.jsonFromString(jsonValue, ctx.getValueAdapter());
}
setValue(bean, objValue);
JsonToken event = ctx.nextToken();
if (JsonToken.VALUE_NULL == event) {
setValue(bean, null);
} else {
// expect to read non-null json value
Object objValue = scalarType.jsonRead(ctx, event);
setValue(bean, objValue);
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,51 @@
package com.avaje.ebeaninternal.server.deploy;
import java.io.IOException;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.EntityBean;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class BeanPropertyAssocManyJsonHelp {
private final BeanPropertyAssocMany<?> many;
public BeanPropertyAssocManyJsonHelp(BeanPropertyAssocMany<?> many) {
this.many = many;
}
public void jsonRead(JsonParser parser, EntityBean parentBean) throws IOException {
if (!this.many.jsonDeserialize) {
return;
}
JsonToken event = parser.nextToken();
if (JsonToken.VALUE_NULL == event) {
return;
}
if (JsonToken.START_ARRAY != event) {
throw new JsonParseException("Unexpected token " + event + " - expecting start_array ", parser.getCurrentLocation());
}
Object collection = many.createEmpty(false);
BeanCollectionAdd add = many.getBeanCollectionAdd(collection, null);
do {
EntityBean detailBean = (EntityBean) many.targetDescriptor.jsonRead(parser, many.name);
if (detailBean == null) {
// read the entire array
break;
}
add.addBean(detailBean);
if (parentBean != null && many.childMasterProperty != null) {
// bind detail bean back to master via mappedBy property
many.childMasterProperty.setValue(detailBean, parentBean);
}
} while (true);
many.setValue(parentBean, collection);
}
}
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.deploy;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -24,8 +25,8 @@ import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.query.SplitName;
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
import com.avaje.ebeaninternal.server.text.json.ReadJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.fasterxml.jackson.core.JsonParser;
/**
* Property mapped to a joined bean.
@@ -830,38 +831,40 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
}
}
@Override
public void jsonWrite(WriteJsonContext ctx, EntityBean bean) {
Object value = getValueIntercept(bean);
if (value == null){
ctx.beginAssocOneIsNull(name);
} else {
if (ctx.isParentBean(value)){
// bi-directional and already rendered parent
} else {
// Hmmm, not writing complex non-entity bean
if (value instanceof EntityBean) {
ctx.pushParentBean(bean);
ctx.beginAssocOne(name);
BeanDescriptor<?> refDesc = descriptor.getBeanDescriptor(value.getClass());
refDesc.jsonWrite(ctx, (EntityBean)value);
ctx.endAssocOne();
ctx.popParentBean();
}
}
}
@Override
public void jsonWrite(WriteJson writeJson, EntityBean bean) throws IOException {
if (!jsonSerialize) {
return;
}
@Override
public void jsonRead(ReadJsonContext ctx, EntityBean bean){
if (targetDescriptor != null) {
T assocBean = targetDescriptor.jsonReadBean(ctx, name);
setValue(bean, assocBean);
Object value = getValueIntercept(bean);
if (value == null) {
writeJson.writeNull(name);
} else {
if (writeJson.isParentBean(value)) {
// bi-directional and already rendered parent
} else {
// Hmmm, not writing complex non-entity bean
if (value instanceof EntityBean) {
writeJson.beginAssocOne(name, bean);
BeanDescriptor<?> refDesc = descriptor.getBeanDescriptor(value.getClass());
refDesc.jsonWrite(writeJson, (EntityBean) value, name);
writeJson.endAssocOne();
}
}
}
}
@Override
public void jsonRead(JsonParser parser, EntityBean bean) throws IOException {
if (jsonDeserialize && targetDescriptor != null) {
T assocBean = targetDescriptor.jsonRead(parser, name);
setValue(bean, assocBean);
}
}
public boolean isReference(Object detailBean) {
EntityBean eb = (EntityBean)detailBean;
@@ -1,20 +1,23 @@
package com.avaje.ebeaninternal.server.deploy;
import java.io.IOException;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.config.ScalarTypeConverter;
import com.avaje.ebean.text.json.EJson;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
import com.avaje.ebeaninternal.server.text.json.ReadJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
import com.avaje.ebeaninternal.server.type.CtCompoundPropertyElAdapter;
import com.avaje.ebeaninternal.server.type.CtCompoundType;
import com.fasterxml.jackson.core.JsonParser;
/**
* Property mapped to an Immutable Compound Value Object.
@@ -177,15 +180,32 @@ public class BeanPropertyCompound extends BeanProperty {
return bean;
}
public void jsonWrite(WriteJsonContext ctx, EntityBean bean) {
Object valueObject = getValueIntercept(bean);
compoundType.jsonWrite(ctx, valueObject, name);
public void jsonWrite(WriteJson ctx, EntityBean bean) throws IOException {
if (!jsonSerialize) {
return;
}
Object value = getValueIntercept(bean);
if (value == null) {
ctx.writeNull(name);
} else {
compoundType.jsonWrite(ctx, value, name);
}
}
public void jsonRead(ReadJsonContext ctx, EntityBean bean){
Object objValue = compoundType.jsonRead(ctx);
public void jsonRead(JsonParser ctx, EntityBean bean) throws IOException {
if (!jsonDeserialize) {
return;
}
Object value = EJson.parse(ctx);
if (value == null) {
setValue(bean, null);
} else {
@SuppressWarnings("unchecked")
Map<String,Object> map = (Map<String,Object>)value;
Object objValue = compoundType.jsonConvert(map);
setValue(bean, objValue);
}
}
}
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.deploy;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -12,7 +13,7 @@ import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.common.BeanSet;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
/**
* Helper specifically for dealing with Sets.
@@ -129,7 +130,7 @@ public final class BeanSetHelp<T> implements BeanCollectionHelp<T> {
}
}
public void jsonWrite(WriteJsonContext ctx, String name, Object collection, boolean explicitInclude) {
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
Set<?> set;
if (collection instanceof BeanCollection<?>){
@@ -148,16 +149,11 @@ public final class BeanSetHelp<T> implements BeanCollectionHelp<T> {
set = (Set<?>)collection;
}
int count = 0;
ctx.beginAssocMany(name);
ctx.writeStartArray(name);
Iterator<?> it = set.iterator();
while (it.hasNext()) {
Object detailBean = it.next();
if (count++ > 0){
ctx.appendComma();
}
targetDescriptor.jsonWrite(ctx, (EntityBean)detailBean);
targetDescriptor.jsonWrite(ctx, (EntityBean)it.next());
}
ctx.endAssocMany();
ctx.writeEndArray();
}
}
@@ -71,6 +71,9 @@ public abstract class DeployParser {
sb.append(deployWord);
if (pos < sourceLength) {
sb.append(wordTerminator);
if (wordTerminator == SINGLE_QUOTE) {
readLiteral();
}
}
}
@@ -217,6 +217,9 @@ public class DeployBeanProperty {
private int sortOrder;
private boolean indexed;
private String indexName;
public DeployBeanProperty(DeployBeanDescriptor<?> desc, Class<?> propertyType, ScalarType<?> scalarType, ScalarTypeConverter<?, ?> typeConverter) {
this.desc = desc;
this.propertyType = propertyType;
@@ -930,4 +933,19 @@ public class DeployBeanProperty {
return desc.getFullName() + "." + name;
}
public boolean isIndexed() {
return indexed;
}
public void setIndexed(boolean indexed) {
this.indexed = indexed;
}
public String getIndexName() {
return indexName;
}
public void setIndexName(String indexName) {
this.indexName = indexName;
}
}
@@ -4,36 +4,18 @@ import java.sql.Types;
import java.util.Map;
import java.util.UUID;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.PersistenceException;
import javax.persistence.SequenceGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.Version;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import com.avaje.ebean.annotation.CreatedTimestamp;
import com.avaje.ebean.annotation.EmbeddedColumns;
import com.avaje.ebean.annotation.Encrypted;
import com.avaje.ebean.annotation.Expose;
import com.avaje.ebean.annotation.Formula;
import com.avaje.ebean.annotation.UpdatedTimestamp;
import com.avaje.ebean.annotation.*;
import com.avaje.ebean.config.EncryptDeploy;
import com.avaje.ebean.config.EncryptDeploy.Mode;
import com.avaje.ebean.config.GlobalProperties;
import com.avaje.ebean.config.dbplatform.DbEncrypt;
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
@@ -65,7 +47,7 @@ public class AnnotationFields extends AnnotationParser {
if (GlobalProperties.getBoolean("ebean.lobEagerFetch", false)) {
defaultLobFetchType = FetchType.EAGER;
}
}
}
/**
@@ -104,7 +86,7 @@ public class AnnotationFields extends AnnotationParser {
if (prop.isId() && !prop.isEmbedded()) {
prop.setEmbedded(true);
}
readEmbeddedAttributeOverrides((DeployBeanPropertyAssocOne<?>)prop);
readEmbeddedAttributeOverrides((DeployBeanPropertyAssocOne<?>) prop);
}
}
@@ -149,7 +131,7 @@ public class AnnotationFields extends AnnotationParser {
if (id != null) {
readId(id, prop);
}
// determine the JDBC type using Lob/Temporal
// otherwise based on the property Class
Lob lob = get(prop, Lob.class);
@@ -199,9 +181,9 @@ public class AnnotationFields extends AnnotationParser {
if (notNull != null && isNotNullOnAllValidationGroups(notNull.groups())) {
// Not null on all validation groups so enable
// DDL generation of Not Null Constraint
prop.setNullable(false);
prop.setNullable(false);
}
Size size = get(prop, Size.class);
if (size != null) {
if (size.max() < Integer.MAX_VALUE) {
@@ -229,7 +211,7 @@ public class AnnotationFields extends AnnotationParser {
} else {
throw new RuntimeException("Can't use EmbeddedColumns on ScalarType "
+ prop.getFullBeanName());
+ prop.getFullBeanName());
}
}
@@ -246,7 +228,7 @@ public class AnnotationFields extends AnnotationParser {
if (!prop.isTransient()) {
EncryptDeploy encryptDeploy = util.getEncryptDeploy(info.getDescriptor().getBaseTableFull(),
prop.getDbColumn());
prop.getDbColumn());
if (encryptDeploy == null || encryptDeploy.getMode().equals(Mode.MODE_ANNOTATION)) {
Encrypted encrypted = get(prop, Encrypted.class);
if (encrypted != null) {
@@ -257,6 +239,20 @@ public class AnnotationFields extends AnnotationParser {
}
}
Index index = get(prop, Index.class);
if (index != null) {
if(hasRelationshipItem(prop)) {
throw new RuntimeException("Can't use Index on foreign key relationships.");
}
prop.setIndexed(true);
prop.setIndexName(index.value());
}
}
private boolean hasRelationshipItem(DeployBeanProperty prop) {
return get(prop, OneToMany.class) != null ||
get(prop, ManyToOne.class) != null ||
get(prop, OneToOne.class) != null;
}
/**
@@ -313,7 +309,7 @@ public class AnnotationFields extends AnnotationParser {
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
private ScalarTypeEncryptedWrapper<?> createScalarType(DeployBeanProperty prop, ScalarType<?> st) {
// Use Java Encryptor wrapping the logical scalar type
@@ -6,6 +6,7 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import javax.persistence.ManyToOne;
import javax.persistence.PersistenceException;
import javax.persistence.Transient;
@@ -273,6 +274,17 @@ public class DeployCreateProperties {
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field) {
Class<?> propertyType = field.getType();
ManyToOne manyToOne = field.getAnnotation(ManyToOne.class);
if (manyToOne != null){
Class<?> tt = manyToOne.targetEntity();
if (tt != null && !tt.equals(void.class)){
propertyType = tt;
logger.debug("target type" + tt);
}
}
Class<?> innerType = propertyType;
String specialTypeKey = getSpecialScalarType(field);
@@ -5,18 +5,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import com.avaje.ebean.Expression;
import com.avaje.ebean.ExpressionList;
import com.avaje.ebean.FutureIds;
import com.avaje.ebean.FutureList;
import com.avaje.ebean.FutureRowCount;
import com.avaje.ebean.Junction;
import com.avaje.ebean.OrderBy;
import com.avaje.ebean.PagedList;
import com.avaje.ebean.PagingList;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.QueryResultVisitor;
import com.avaje.ebean.*;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.ManyWhereJoins;
import com.avaje.ebeaninternal.api.SpiExpression;
@@ -206,6 +197,11 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
throw new RuntimeException("filterMany not allowed on Junction expression list");
}
@Override
public Query<T> apply(PathProperties pathProperties) {
return exprList.apply(pathProperties);
}
public FutureIds<T> findFutureIds() {
return exprList.findFutureIds();
}
@@ -53,7 +53,8 @@ class LikeExpression extends AbstractExpression {
if (type.equals(LikeType.EQUAL_TO)) {
request.append(" = ? ");
} else {
request.append(" like ? ");
// append db platform like clause
request.appendLike();
}
}
@@ -57,7 +57,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
currentBuffer = createBuffer(secondaryBatchSize);
}
// set the persistenceContext on the bean first
ebi.setBeanLoader(0, currentBuffer, getPersistenceContext());
ebi.setBeanLoader(currentBuffer, getPersistenceContext());
currentBuffer.add(ebi);
}
@@ -8,126 +8,121 @@ import com.avaje.ebeaninternal.api.SpiUpdatePlan;
import com.avaje.ebeaninternal.server.persist.dmlbind.Bindable;
/**
* Cachable plan for executing bean updates for a given set of changed
* properties.
*
* @author rbygrave
* Plan for executing bean updates for a given set of changed properties.
*/
public class UpdatePlan implements SpiUpdatePlan {
/**
* Special plan used when there is nothing in the set clause and the update
* should in fact be skipped. Occurs when the updated properties have
* updatable=false in their deployment.
* Special plan used when there is nothing in the set clause and the update should in fact be
* skipped. Occurs when the updated properties have updatable=false in their deployment.
*/
public static final UpdatePlan EMPTY_SET_CLAUSE = new UpdatePlan();
private final Integer key;
private final ConcurrencyMode mode;
private final Integer key;
private final String sql;
private final ConcurrencyMode mode;
private final Bindable set;
private final String sql;
private final long timeCreated;
private final Bindable set;
private final boolean emptySetClause;
private Long timeLastUsed;
private final long timeCreated;
/**
* Create a non cachable UpdatePlan.
*/
public UpdatePlan(ConcurrencyMode mode, String sql, Bindable set) {
private final boolean emptySetClause;
this(null, mode, sql, set);
}
private Long timeLastUsed;
/**
* Create a cachable UpdatePlan with a given key.
*/
public UpdatePlan(Integer key, ConcurrencyMode mode, String sql, Bindable set) {
/**
* Create a non cached UpdatePlan.
*/
public UpdatePlan(ConcurrencyMode mode, String sql, Bindable set) {
this.emptySetClause = (sql == null);
this.key = key;
this.mode = mode;
this.sql = sql;
this.set = set;
this.timeCreated = System.currentTimeMillis();
}
this(null, mode, sql, set);
}
/**
* Special constructor for emptySetClause=true instance.
*/
private UpdatePlan(){
this.emptySetClause = true;
this.key = Integer.valueOf(0);
this.mode = ConcurrencyMode.NONE;
this.sql = null;
this.set = null;
this.timeCreated = 0;
}
public boolean isEmptySetClause() {
return emptySetClause;
}
/**
* Create a UpdatePlan with a given key.
*/
public UpdatePlan(Integer key, ConcurrencyMode mode, String sql, Bindable set) {
/**
* Run the prepared statement binding for the 'update set' properties.
*/
public void bindSet(DmlHandler bind, EntityBean bean) throws SQLException {
this.emptySetClause = (sql == null);
this.key = key;
this.mode = mode;
this.sql = sql;
this.set = set;
this.timeCreated = System.currentTimeMillis();
}
set.dmlBind(bind, bean);
/**
* Special constructor for emptySetClause=true instance.
*/
private UpdatePlan() {
this.emptySetClause = true;
this.key = Integer.valueOf(0);
this.mode = ConcurrencyMode.NONE;
this.sql = null;
this.set = null;
this.timeCreated = 0;
}
// not strictly 'thread safe' but object assignment is atomic
Long touched = Long.valueOf(System.currentTimeMillis());
this.timeLastUsed = touched;
}
public boolean isEmptySetClause() {
return emptySetClause;
}
/**
* Return the time this plan was created.
*/
public long getTimeCreated() {
return timeCreated;
}
/**
* Run the prepared statement binding for the 'update set' properties.
*/
public void bindSet(DmlHandler bind, EntityBean bean) throws SQLException {
/**
* Return the time this plan was last used.
*/
public Long getTimeLastUsed() {
set.dmlBind(bind, bean);
// not thread safe but atomic
return timeLastUsed;
}
// not strictly 'thread safe' but object assignment is atomic
Long touched = Long.valueOf(System.currentTimeMillis());
this.timeLastUsed = touched;
}
/**
* Return the hash key.
*/
public Integer getKey() {
return key;
}
/**
* Return the time this plan was created.
*/
public long getTimeCreated() {
return timeCreated;
}
/**
* Return the concurrency mode for this plan.
*/
public ConcurrencyMode getMode() {
return mode;
}
/**
* Return the time this plan was last used.
*/
public Long getTimeLastUsed() {
/**
* Return the DML statement.
*/
public String getSql() {
return sql;
}
// not thread safe but atomic
return timeLastUsed;
}
/**
* Return the Bindable properties for the update set.
*/
public Bindable getSet() {
return set;
}
/**
* Return the hash key.
*/
public Integer getKey() {
return key;
}
/**
* Return the concurrency mode for this plan.
*/
public ConcurrencyMode getMode() {
return mode;
}
/**
* Return the DML statement.
*/
public String getSql() {
return sql;
}
/**
* Return the Bindable properties for the update set.
*/
public Bindable getSet() {
return set;
}
}
@@ -1,4 +1,3 @@
package com.avaje.ebeaninternal.server.query;
import java.util.ArrayList;
@@ -12,6 +11,7 @@ import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.meta.MetaQueryPlanOriginCount;
import com.avaje.ebean.meta.MetaQueryPlanStatistic;
import com.avaje.ebeaninternal.server.util.LongAdder;
import com.avaje.ebeaninternal.server.util.LongMaxUpdater;
/**
* Statistics for a specific query plan that can accumulate.
@@ -26,7 +26,7 @@ public final class CQueryPlanStats {
private final LongAdder totalBeans = new LongAdder();
private final AtomicLong maxTime = new AtomicLong();
private final LongMaxUpdater maxTime = new LongMaxUpdater();
private final AtomicLong startTime = new AtomicLong(System.currentTimeMillis());
@@ -34,19 +34,25 @@ public final class CQueryPlanStats {
private final ConcurrentHashMap<ObjectGraphNode, LongAdder> origins;
/**
* Construct for a given query plan.
*/
public CQueryPlanStats(CQueryPlan queryPlan, boolean collectQueryOrigins) {
this.queryPlan = queryPlan;
this.origins = !collectQueryOrigins ? null : new ConcurrentHashMap<ObjectGraphNode, LongAdder>();
}
/**
* Add a query execution to the statistics.
*/
public void add(long loadedBeanCount, long timeMicros, ObjectGraphNode objectGraphNode) {
count.increment();
totalBeans.add(loadedBeanCount);
totalTime.add(timeMicros);
if (timeMicros > maxTime.get()) {
// effectively a high water mark
maxTime.set(timeMicros);
}
maxTime.update(timeMicros);
// not safe but should be atomic
lastQueryTime = System.currentTimeMillis();
@@ -64,12 +70,16 @@ public final class CQueryPlanStats {
}
}
/**
* Reset the internal statistics counters.
*/
public void reset() {
// Racey but near enough for our purposes as we don't want locks
count.reset();
totalBeans.reset();
totalTime.reset();
maxTime.set(0);
maxTime.reset();
startTime.set(System.currentTimeMillis());
if (origins != null) {
@@ -77,13 +87,18 @@ public final class CQueryPlanStats {
counter.reset();
}
}
}
/**
* Return the last time this query was executed.
*/
public long getLastQueryTime() {
return lastQueryTime;
}
/**
* Return a Snapshot of the query execution statistics potentially resetting the internal counters.
*/
public Snapshot getSnapshot(boolean reset) {
List<MetaQueryPlanOriginCount> origins = getOrigins(reset);
@@ -91,9 +106,9 @@ public final class CQueryPlanStats {
// not guaranteed to be consistent due to time gaps between getting each value out of LongAdders but can live with that
// relative to the cost of making sure count and totalTime etc are all guaranteed to be consistent
if (reset) {
return new Snapshot(queryPlan, count.sumThenReset(), totalTime.sumThenReset(), totalBeans.sumThenReset(), maxTime.getAndSet(0), startTime.getAndSet(System.currentTimeMillis()), lastQueryTime, origins);
return new Snapshot(queryPlan, count.sumThenReset(), totalTime.sumThenReset(), totalBeans.sumThenReset(), maxTime.maxThenReset(), startTime.getAndSet(System.currentTimeMillis()), lastQueryTime, origins);
}
return new Snapshot(queryPlan, count.sum(), totalTime.sum(), totalBeans.sum(), maxTime.get(), startTime.get(), lastQueryTime, origins);
return new Snapshot(queryPlan, count.sum(), totalTime.sum(), totalBeans.sum(), maxTime.max(), startTime.get(), lastQueryTime, origins);
}
/**
@@ -310,7 +310,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
}
}
if (parentBean != null && contextBean != null) {
if (parentBean != null) {
// set this back to the parentBean
nodeBeanProp.setValue(parentBean, contextBean);
}
@@ -31,6 +31,7 @@ import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.bean.ObjectGraphOrigin;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebeaninternal.api.BindParams;
import com.avaje.ebeaninternal.api.HashQuery;
import com.avaje.ebeaninternal.api.HashQueryPlan;
@@ -270,6 +271,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
this.totalHits = totalHits;
}
@Override
public Query<T> apply(PathProperties pathProperties) {
pathProperties.apply(this);
return this;
}
/**
* Set the BeanDescriptor for the root type of this query.
*/
@@ -1,306 +1,236 @@
package com.avaje.ebeaninternal.server.text.json;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.TextException;
import com.avaje.ebean.text.json.EJson;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebean.text.json.JsonContext;
import com.avaje.ebean.text.json.JsonElement;
import com.avaje.ebean.text.json.JsonReadOptions;
import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebean.text.json.JsonWriteOptions;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.type.EscapeJson;
import com.avaje.ebeaninternal.util.ParamTypeHelper;
import com.avaje.ebeaninternal.util.ParamTypeHelper.ManyType;
import com.avaje.ebeaninternal.util.ParamTypeHelper.TypeInfo;
import com.fasterxml.jackson.core.*;
import java.io.*;
import java.lang.reflect.Type;
import java.util.*;
import java.util.Map.Entry;
/**
* Default implementation of JsonContext.
*
* @author rbygrave
*/
public class DJsonContext implements JsonContext {
private final SpiEbeanServer server;
private final SpiEbeanServer server;
private final JsonFactory jsonFactory;
public DJsonContext(SpiEbeanServer server, JsonFactory jsonFactory) {
this.server = server;
this.jsonFactory = (jsonFactory != null) ? jsonFactory : new JsonFactory();
}
public boolean isSupportedType(Type genericType) {
return server.isSupportedType(genericType);
}
public JsonGenerator createGenerator(Writer writer) throws IOException {
return jsonFactory.createGenerator(writer);
}
public JsonParser createParser(Reader reader) throws IOException {
return jsonFactory.createParser(reader);
}
public <T> T toBean(Class<T> cls, String json) throws IOException {
return toBean(cls, new StringReader(json));
}
public <T> T toBean(Class<T> cls, Reader jsonReader) throws IOException {
return toBean(cls, createParser(jsonReader));
}
private <T> T toBean(Class<T> cls, JsonParser parser) throws IOException {
BeanDescriptor<T> d = getDescriptor(cls);
return d.jsonRead(parser, null);
}
public <T> List<T> toList(Class<T> cls, String json) throws IOException {
return toList(cls, new StringReader(json));
}
public <T> List<T> toList(Class<T> cls, Reader jsonReader) throws IOException {
return toList(cls, createParser(jsonReader));
}
private <T> List<T> toList(Class<T> cls, JsonParser src) throws IOException {
BeanDescriptor<T> d = getDescriptor(cls);
List<T> list = new ArrayList<T>();
JsonToken event = src.nextToken();
if (event != JsonToken.START_ARRAY) {
throw new JsonParseException("Expecting start_array event but got " + event ,src.getCurrentLocation());
}
do {
T bean = d.jsonRead(src, null);
if (bean == null) {
break;
} else {
list.add(bean);
}
} while (true);
return list;
}
public Object toObject(Type genericType, String json) throws IOException {
TypeInfo info = ParamTypeHelper.getTypeInfo(genericType);
ManyType manyType = info.getManyType();
switch (manyType) {
case NONE:
return toBean(info.getBeanType(), json);
case LIST:
return toList(info.getBeanType(), json);
default:
throw new IOException("Type " + manyType + " not supported");
}
}
public Object toObject(Type genericType, Reader json) throws IOException {
TypeInfo info = ParamTypeHelper.getTypeInfo(genericType);
ManyType manyType = info.getManyType();
switch (manyType) {
case NONE:
return toBean(info.getBeanType(), json);
case LIST:
return toList(info.getBeanType(), json);
default:
throw new IOException("Type " + manyType + " not supported");
}
}
public void toJson(Object o, Writer writer) throws IOException {
toJson(o, writer, null);
}
public void toJson(Object o, Writer writer, JsonWriteOptions options) throws IOException {
JsonGenerator generator = createGenerator(writer);
toJsonInternal(o, generator, options);
generator.close();
}
public String toJson(Object o) throws IOException {
return toJsonString(o, null);
}
public String toJson(Object o, JsonWriteOptions options) throws IOException {
return toJsonString(o, options);
}
private String toJsonString(Object o, JsonWriteOptions options) throws IOException {
StringWriter writer = new StringWriter(500);
JsonGenerator gen = createGenerator(writer);
toJsonInternal(o, gen, options);
gen.close();
return writer.toString();
}
@SuppressWarnings("unchecked")
private void toJsonInternal(Object o, JsonGenerator gen, JsonWriteOptions options) throws IOException {
if (o == null) {
gen.writeNull();
} else if (o instanceof Number) {
gen.writeNumber(((Number) o).doubleValue());
} else if (o instanceof Boolean) {
gen.writeBoolean((Boolean) o);
} else if (o instanceof String) {
gen.writeString((String) o);
// } else if (o instanceof JsonElement) {
} else if (o instanceof Map<?, ?>) {
toJsonFromMap((Map<Object, Object>) o, gen, options);
} else if (o instanceof Collection<?>) {
toJsonFromCollection((Collection<?>) o, null, gen, options);
} else if (o instanceof EntityBean) {
BeanDescriptor<?> d = getDescriptor(o.getClass());
WriteJson writeJson = createWriteJson(gen, options);
d.jsonWrite(writeJson, (EntityBean)o, null);
}
}
private WriteJson createWriteJson(JsonGenerator gen, JsonWriteOptions options) {
PathProperties pathProps = (options == null) ? null : options.getPathProperties();
return new WriteJson(server, gen, pathProps);
}
private <T> void toJsonFromCollection(Collection<T> collection, String key, JsonGenerator gen, JsonWriteOptions options) throws IOException {
if (key != null) {
gen.writeFieldName(key);
}
gen.writeStartArray();
WriteJson writeJson = createWriteJson(gen, options);
for (T bean : collection) {
BeanDescriptor<?> d = getDescriptor(bean.getClass());
d.jsonWrite(writeJson, (EntityBean) bean, null);
}
gen.writeEndArray();
}
private void toJsonFromMap(Map<Object, Object> map, JsonGenerator gen, JsonWriteOptions options) throws IOException {
Set<Entry<Object, Object>> entrySet = map.entrySet();
Iterator<Entry<Object, Object>> it = entrySet.iterator();
WriteJson writeJson = createWriteJson(gen, options);
gen.writeStartObject();
private final JsonValueAdapter dfltValueAdapter;
private final boolean dfltPretty;
public DJsonContext(SpiEbeanServer server, JsonValueAdapter dfltValueAdapter, boolean dfltPretty){
this.server = server;
this.dfltValueAdapter = dfltValueAdapter;
this.dfltPretty = dfltPretty;
}
while (it.hasNext()) {
Entry<Object, Object> entry = it.next();
String key = entry.getKey().toString();
Object value = entry.getValue();
if (value == null) {
gen.writeNullField(key);
} else {
if (value instanceof Collection<?>) {
toJsonFromCollection((Collection<?>) value, key, gen, options);
public boolean isSupportedType(Type genericType) {
return server.isSupportedType(genericType);
}
} else if (value instanceof EntityBean) {
BeanDescriptor<?> d = getDescriptor(value.getClass());
d.jsonWrite(writeJson,(EntityBean) value, key);
private ReadJsonSource createReader(Reader jsonReader) {
return new ReadJsonSourceReader(jsonReader, 256, 512);
}
public <T> T toBean(Class<T> cls, String json){
return toBean(cls, new ReadJsonSourceString(json), null);
}
public <T> T toBean(Class<T> cls, Reader jsonReader) {
return toBean(cls, createReader(jsonReader), null);
}
public <T> T toBean(Class<T> cls, String json, JsonReadOptions options){
return toBean(cls, new ReadJsonSourceString(json), options);
}
public <T> T toBean(Class<T> cls, Reader jsonReader, JsonReadOptions options) {
return toBean(cls, createReader(jsonReader), options);
}
private <T> T toBean(Class<T> cls, ReadJsonSource src, JsonReadOptions options){
BeanDescriptor<T> d = getDecriptor(cls);
ReadJsonContext ctx = new ReadJsonContext(src, dfltValueAdapter, options);
return d.jsonReadBean(ctx, null);
}
public <T> List<T> toList(Class<T> cls, String json){
return toList(cls, new ReadJsonSourceString(json), null);
}
public <T> List<T> toList(Class<T> cls, String json, JsonReadOptions options){
return toList(cls, new ReadJsonSourceString(json), options);
}
public <T> List<T> toList(Class<T> cls, Reader jsonReader){
return toList(cls, createReader(jsonReader), null);
}
public <T> List<T> toList(Class<T> cls, Reader jsonReader, JsonReadOptions options){
return toList(cls, createReader(jsonReader), options);
}
private <T> List<T> toList(Class<T> cls, ReadJsonSource src, JsonReadOptions options){
try {
BeanDescriptor<T> d = getDecriptor(cls);
List<T> list = new ArrayList<T>();
ReadJsonContext ctx = new ReadJsonContext(src, dfltValueAdapter, options);
ctx.readArrayBegin();
do {
T bean = d.jsonReadBean(ctx, null);
if (bean != null){
list.add(bean);
}
if (!ctx.readArrayNext()){
break;
}
} while(true);
return list;
} catch (RuntimeException e){
throw new TextException("Error parsing "+src, e);
}
}
public Object toObject(Type genericType, String json, JsonReadOptions options) {
TypeInfo info = ParamTypeHelper.getTypeInfo(genericType);
Class<?> beanType = info.getBeanType();
if (JsonElement.class.isAssignableFrom(beanType)){
return InternalJsonParser.parse(json);
}
ManyType manyType = info.getManyType();
switch (manyType) {
case NONE:
return toBean(info.getBeanType(), json, options);
case LIST:
return toList(info.getBeanType(), json, options);
default:
String msg = "ManyType "+manyType+" not supported yet";
throw new TextException(msg);
}
}
public Object toObject(Type genericType, Reader json, JsonReadOptions options) {
TypeInfo info = ParamTypeHelper.getTypeInfo(genericType);
Class<?> beanType = info.getBeanType();
if (JsonElement.class.isAssignableFrom(beanType)){
return InternalJsonParser.parse(json);
}
ManyType manyType = info.getManyType();
switch (manyType) {
case NONE:
return toBean(info.getBeanType(), json, options);
case LIST:
return toList(info.getBeanType(), json, options);
default:
String msg = "ManyType "+manyType+" not supported yet";
throw new TextException(msg);
}
}
public void toJsonWriter(Object o, Writer writer) {
toJsonWriter(o, writer, dfltPretty, null, null);
}
public void toJsonWriter(Object o, Writer writer, boolean pretty) {
toJsonWriter(o, writer, pretty, null, null);
}
public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options){
toJsonWriter(o, writer, pretty, null, null);
}
public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options, String callback) {
toJsonInternal(o, new WriteJsonBufferWriter(writer), pretty, options, callback);
}
public String toJsonString(Object o){
return toJsonString(o, dfltPretty, null);
}
public String toJsonString(Object o, boolean pretty){
return toJsonString(o, pretty, null);
}
public String toJsonString(Object o, boolean pretty, JsonWriteOptions options){
return toJsonString(o, pretty, options, null);
}
public String toJsonString(Object o, boolean pretty, JsonWriteOptions options, String callback){
WriteJsonBufferString b = new WriteJsonBufferString();
toJsonInternal(o, b, pretty, options, callback);
return b.getBufferOutput();
}
@SuppressWarnings("unchecked")
private void toJsonInternal(Object o, WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback){
if (o == null){
buffer.append("null");
} else if (o instanceof Number) {
buffer.append(o.toString());
} else if (o instanceof Boolean) {
buffer.append(o.toString());
} else if (o instanceof String) {
EscapeJson.escapeQuote(o.toString(), buffer);
} else if (o instanceof JsonElement) {
} else if (o instanceof Map<?,?>){
toJsonFromMap((Map<Object,Object>)o, buffer, pretty, options, requestCallback);
} else if (o instanceof Collection<?>){
toJsonFromCollection((Collection<?>)o, buffer, pretty, options, requestCallback);
} else {
BeanDescriptor<?> d = getDecriptor(o.getClass());
WriteJsonContext ctx = new WriteJsonContext(buffer, pretty, dfltValueAdapter, options, requestCallback, server);
d.jsonWrite(ctx, (EntityBean)o);
ctx.end();
EJson.write(entry, gen);
}
}
}
gen.writeEndObject();
}
private <T> void toJsonFromCollection(Collection<T> c, WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback){
Iterator<T> it = c.iterator();
if (!it.hasNext()){
buffer.append("[]");
return;
}
WriteJsonContext ctx = new WriteJsonContext(buffer, pretty, dfltValueAdapter, options, requestCallback, server);
Object o = it.next();
BeanDescriptor<?> d = getDecriptor(o.getClass());
ctx.appendArrayBegin();
d.jsonWrite(ctx, (EntityBean)o);
while (it.hasNext()) {
ctx.appendComma();
T t = it.next();
d.jsonWrite(ctx, (EntityBean)t);
}
ctx.appendArrayEnd();
ctx.end();
}
private void toJsonFromMap(Map<Object,Object> map, WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback){
if (map.isEmpty()){
buffer.append("{}");
return;
}
WriteJsonContext ctx = new WriteJsonContext(buffer, pretty, dfltValueAdapter, options, requestCallback, server);
Set<Entry<Object,Object>> entrySet = map.entrySet();
Iterator<Entry<Object, Object>> it = entrySet.iterator();
Entry<Object, Object> entry = it.next();
ctx.appendObjectBegin();
toJsonMapKey(buffer, false, entry.getKey());
toJsonMapValue(buffer, pretty, options, requestCallback, entry.getValue());
while (it.hasNext()) {
entry = it.next();
ctx.appendComma();
toJsonMapKey(buffer, pretty, entry.getKey());
toJsonMapValue(buffer, pretty, options, requestCallback, entry.getValue());
}
ctx.appendObjectEnd();
ctx.end();
}
private void toJsonMapKey(WriteJsonBuffer buffer, boolean pretty, Object key) {
if (pretty){
buffer.append("\n");
}
buffer.append("\"");
buffer.append(key.toString());
buffer.append("\":");
}
private void toJsonMapValue(WriteJsonBuffer buffer, boolean pretty, JsonWriteOptions options, String requestCallback,
Object value) {
if (value == null){
buffer.append("null");
} else {
toJsonInternal(value, buffer, pretty, options, requestCallback);
}
}
private <T> BeanDescriptor<T> getDecriptor(Class<T> cls) {
BeanDescriptor<T> d = server.getBeanDescriptor(cls);
if (d == null){
String msg = "No BeanDescriptor found for "+cls;
throw new RuntimeException(msg);
}
return d;
private <T> BeanDescriptor<T> getDescriptor(Class<T> cls) {
BeanDescriptor<T> d = server.getBeanDescriptor(cls);
if (d == null) {
throw new RuntimeException("No BeanDescriptor found for " + cls);
}
return d;
}
}
@@ -5,9 +5,7 @@ import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import com.avaje.ebean.text.json.JsonValueAdapter;
public class DefaultJsonValueAdapter implements JsonValueAdapter {
public class DefaultJsonValueAdapter {//implements JsonValueAdapter {
private final SimpleDateFormat dateTimeProto;
@@ -1,23 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
import java.io.Reader;
import com.avaje.ebean.text.json.JsonElement;
public class InternalJsonParser {
public static JsonElement parse(String s) {
ReadJsonSourceString src = new ReadJsonSourceString(s);
ReadBasicJsonContext b = new ReadBasicJsonContext(src);
return ReadJsonRawReader.readJsonElement(b);
}
public static JsonElement parse(Reader s) {
ReadJsonSourceReader src = new ReadJsonSourceReader(s, 512, 256);
ReadBasicJsonContext b = new ReadBasicJsonContext(src);
return ReadJsonRawReader.readJsonElement(b);
}
}
@@ -4,23 +4,23 @@ import com.avaje.ebeaninternal.server.util.ArrayStack;
public class PathStack extends ArrayStack<String> {
public String peekFullPath(String key){
String prefix = peekWithNull();
if (prefix != null){
return prefix+"."+key;
} else {
return key;
}
}
public void pushPathKey(String key) {
public String peekFullPath(String key) {
String prefix = peekWithNull();
if (prefix != null){
key = prefix+"."+key;
}
push(key);
String prefix = peekWithNull();
if (prefix != null) {
return prefix + "." + key;
} else {
return key;
}
}
public void pushPathKey(String key) {
String prefix = peekWithNull();
if (prefix != null) {
key = prefix + "." + key;
}
push(key);
}
}
@@ -1,273 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
import com.avaje.ebean.text.TextException;
public class ReadBasicJsonContext implements ReadJsonInterface {
private final ReadJsonSource src;
private char tokenStart;
private String tokenKey;
private boolean pushedTokenKey;
public ReadBasicJsonContext(ReadJsonSource src) {
this.src = src;
}
/**
* Push the current token key back onto the 'stack'.
*/
public void pushTokenKey() {
pushedTokenKey = true;
}
public char getToken() {
return tokenStart;
}
public String getTokenKey() {
return tokenKey;
}
public boolean isTokenKey() {
return '\"' == tokenStart;
}
public boolean isTokenObjectEnd() {
return '}' == tokenStart;
}
public boolean readObjectBegin() {
readNextToken();
if ('{' == tokenStart){
return true;
} else if ('n' == tokenStart) {
return false;
} else if (']' == tokenStart) {
// an empty array
return false;
}
throw new RuntimeException("Expected object begin at "+src.getErrorHelp());
}
public boolean readKeyNext() {
readNextToken();
if ('\"' == tokenStart){
return true;
} else if ('}' == tokenStart) {
return false;
}
throw new RuntimeException("Expected '\"' or '}' at "+src.getErrorHelp());
}
public boolean readValueNext() {
readNextToken();
if (',' == tokenStart){
return true;
} else if ('}' == tokenStart) {
return false;
}
throw new RuntimeException("Expected ',' or '}' at "+src.getErrorHelp()+" but got "+tokenStart);
}
public boolean readArrayBegin() {
readNextToken();
if ('[' == tokenStart){
return true;
} else if ('n' == tokenStart) {
return false;
}
throw new RuntimeException("Expected array begin at "+src.getErrorHelp());
}
public boolean readArrayNext() {
readNextToken();
if (',' == tokenStart){
return true;
}
if (']' == tokenStart){
return false;
}
throw new RuntimeException("Expected ',' or ']' at "+src.getErrorHelp());
}
public void readNextToken() {
if (pushedTokenKey) {
// Do nothing
pushedTokenKey = false;
return;
}
ignoreWhiteSpace();
tokenStart = src.nextChar("EOF finding next token");
switch (tokenStart) {
case '"':
internalReadKey();
break;
case '{': break;
case '}': break;
case '[': break; // not expected
case ']': break; // not expected
case ',': break; // not expected
case ':': break; // not expected
case 'n':
internalReadNull();
break; // not expected
default:
throw new RuntimeException("Unexpected tokenStart["+tokenStart+"] "+src.getErrorHelp());
}
}
public String readQuotedValue() {
boolean escape = false;
StringBuilder sb = new StringBuilder();
do {
char ch = src.nextChar("EOF reading quoted value");
if (escape) {
// in escape mode so just append the character
escape = false;
switch (ch) {
case 'n':
sb.append('\n');
break;
case 'r':
sb.append('\r');
break;
case 't':
sb.append('\t');
break;
case 'f':
sb.append('\f');
break;
case 'b':
sb.append('\b');
break;
case '"':
sb.append('"');
break;
case 'u':
String msg = "EOF reading unicode value";
char c1 = src.nextChar(msg);
char c2 = src.nextChar(msg);
char c3 = src.nextChar(msg);
char c4 = src.nextChar(msg);
char u = (char) Integer.parseInt(""+c1+c2+c3+c4, 16);
sb.append(u);
break;
default:
sb.append('\\');
sb.append(ch);
break;
}
} else {
switch (ch) {
case '\\':
// put into 'escape' mode for next character
escape = true;
break;
case '"':
return sb.toString();
default:
sb.append(ch);
}
}
} while (true);
}
public String readUnquotedValue(char c) {
String v = readUnquotedValueRaw(c);
if ("null".equals(v)){
return null;
} else {
return v;
}
}
private String readUnquotedValueRaw(char c) {
StringBuilder sb = new StringBuilder();
sb.append(c);
do {
tokenStart = src.nextChar("EOF reading unquoted value");
switch (tokenStart) {
case ',':
src.back();
return sb.toString();
case '}':
src.back();
return sb.toString();
case ' ':
return sb.toString();
case '\t':
return sb.toString();
case '\r':
return sb.toString();
case '\n':
return sb.toString();
default:
sb.append(tokenStart);
}
} while (true);
}
private void internalReadNull() {
StringBuilder sb = new StringBuilder(4);
sb.append(tokenStart);
for (int i = 0; i < 3; i++) {
char c = src.nextChar("EOF reading null ");
sb.append(c);
}
if (!"null".equals(sb.toString())){
throw new TextException("Expected 'null' but got "+sb.toString()+" "+src.getErrorHelp());
}
}
private void internalReadKey() {
StringBuilder sb = new StringBuilder();
do {
char c = src.nextChar("EOF reading key");
if ('\"' == c){
tokenKey = sb.toString();
break;
} else {
sb.append(c);
}
} while (true);
ignoreWhiteSpace();
char c = src.nextChar("EOF reading ':'");
if (':' != c){
throw new TextException("Expected to find colon after key at "+(src.pos()-1)+" but found ["+c+"]"+src.getErrorHelp());
}
}
public void ignoreWhiteSpace() {
src.ignoreWhiteSpace();
}
public char nextChar() {
tokenStart = src.nextChar("EOF getting nextChar for raw json");
return tokenStart;
}
}
@@ -1,177 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.text.json.JsonElement;
import com.avaje.ebean.text.json.JsonReadBeanVisitor;
import com.avaje.ebean.text.json.JsonReadOptions;
import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.util.ArrayStack;
public class ReadJsonContext extends ReadBasicJsonContext {
private final Map<String, JsonReadBeanVisitor<?>> visitorMap;
private final JsonValueAdapter valueAdapter;
private final PathStack pathStack;
private final ArrayStack<ReadBeanState> beanState;
private ReadBeanState currentState;
public ReadJsonContext(ReadJsonSource src, JsonValueAdapter dfltValueAdapter, JsonReadOptions options) {
super(src);
this.beanState = new ArrayStack<ReadBeanState>();
if (options == null){
this.valueAdapter = dfltValueAdapter;
this.visitorMap = null;
this.pathStack = null;
} else {
this.valueAdapter = getValueAdapter(dfltValueAdapter, options.getValueAdapter());
this.visitorMap = options.getVisitorMap();
this.pathStack = (visitorMap == null || visitorMap.isEmpty()) ? null : new PathStack();
}
}
private JsonValueAdapter getValueAdapter(JsonValueAdapter dfltValueAdapter, JsonValueAdapter valueAdapter) {
return valueAdapter == null ? dfltValueAdapter : valueAdapter;
}
public JsonValueAdapter getValueAdapter() {
return valueAdapter;
}
public String readScalarValue() {
ignoreWhiteSpace();
char prevChar = nextChar();//"EOF reading scalarValue?");
if ('"' == prevChar){
return readQuotedValue();
} else {
return readUnquotedValue(prevChar);
}
}
public void pushBean(Object bean, String path, BeanDescriptor<?> beanDescriptor){
currentState = new ReadBeanState(bean, beanDescriptor);
beanState.push(currentState);
if (pathStack != null){
pathStack.pushPathKey(path);
}
}
public ReadBeanState popBeanState() {
if (pathStack != null){
String path = pathStack.peekWithNull();
JsonReadBeanVisitor<?> beanVisitor = visitorMap.get(path);
if (beanVisitor != null){
currentState.visit(beanVisitor);
}
pathStack.pop();
}
// return the current ReadBeanState as we can't call setLoadedState()
// yet. We might bind master/detail beans together via mappedBy property
// so wait until after that before calling ReadBeanStatesetLoadedState();
ReadBeanState s = currentState;
beanState.pop();
currentState = beanState.peekWithNull();
return s;
}
public void setProperty(String propertyName){
currentState.setLoaded(propertyName);
}
/**
* Got a key that doesn't map to a known property so read the json value
* which could be json primitive, object or array.
* <p>
* Provide these values to a JsonReadBeanVisitor if registered.
* </p>
*/
public JsonElement readUnmappedJson(String key) {
JsonElement rawJsonValue = ReadJsonRawReader.readJsonElement(this);
if (visitorMap != null){
currentState.addUnmappedJson(key, rawJsonValue);
}
return rawJsonValue;
}
public static class ReadBeanState implements PropertyChangeListener {
private final Object bean;
private final BeanDescriptor<?> beanDescriptor;
private final EntityBeanIntercept ebi;
private final Set<String> loadedProps;
private Map<String,JsonElement> unmapped;
private ReadBeanState(Object bean, BeanDescriptor<?> beanDescriptor) {
this.bean = bean;
this.beanDescriptor = beanDescriptor;
if (bean instanceof EntityBean){
this.ebi = ((EntityBean)bean)._ebean_getIntercept();
this.loadedProps = new HashSet<String>();
} else {
this.ebi = null;
this.loadedProps = null;
}
}
public String toString(){
return bean.getClass().getSimpleName()+" loaded:"+loadedProps;
}
/**
* Add a loaded/set property to the set of loadedProps.
*/
public void setLoaded(String propertyName){
if (ebi != null){
loadedProps.add(propertyName);
}
}
private void addUnmappedJson(String key, JsonElement value){
if (unmapped == null){
unmapped = new LinkedHashMap<String, JsonElement>();
}
unmapped.put(key, value);
}
@SuppressWarnings("unchecked")
private <T> void visit(JsonReadBeanVisitor<T> beanVisitor) {
// listen for property change events so that
// we can update the loadedProps if necessary
if (ebi != null){
ebi.addPropertyChangeListener(this);
}
beanVisitor.visit((T)bean, unmapped);
if (ebi != null){
ebi.removePropertyChangeListener(this);
}
}
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
loadedProps.add(propName);
}
public Object getBean() {
return bean;
}
}
}
@@ -1,22 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
public interface ReadJsonInterface {
public void ignoreWhiteSpace();
public char nextChar();
public String getTokenKey();
public boolean readKeyNext();
public boolean readValueNext();
public boolean readArrayNext();
public String readQuotedValue();
public String readUnquotedValue(char c);
}
@@ -1,107 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
import com.avaje.ebean.text.json.JsonElement;
import com.avaje.ebean.text.json.JsonElementArray;
import com.avaje.ebean.text.json.JsonElementBoolean;
import com.avaje.ebean.text.json.JsonElementNull;
import com.avaje.ebean.text.json.JsonElementNumber;
import com.avaje.ebean.text.json.JsonElementObject;
import com.avaje.ebean.text.json.JsonElementString;
public class ReadJsonRawReader {
public static JsonElement readJsonElement(ReadJsonInterface ctx) {
return new ReadJsonRawReader(ctx).readJsonElement();
}
private final ReadJsonInterface ctx;
private ReadJsonRawReader(ReadJsonInterface ctx){
this.ctx = ctx;
}
private JsonElement readJsonElement() {
return readValue();
}
private JsonElement readValue() {
ctx.ignoreWhiteSpace();
char c = ctx.nextChar();
switch (c) {
case '{':
return readObject();
case '[':
return readArray();
case '"':
return readString();
default:
return readUnquoted(c);
}
}
private JsonElement readArray() {
JsonElementArray a = new JsonElementArray();
do {
JsonElement value = readValue();
a.add(value);
if (!ctx.readArrayNext()){
break;
}
} while(true);
return a;
}
private JsonElement readObject() {
JsonElementObject o = new JsonElementObject();
do {
if (!ctx.readKeyNext()){
break;
} else {
// we read a property key ...
String key = ctx.getTokenKey();
JsonElement value = readValue();
o.put(key, value);
if (!ctx.readValueNext()){
break;
}
}
} while(true);
return o;
}
private JsonElement readString() {
String s = ctx.readQuotedValue();
return new JsonElementString(s);
}
private JsonElement readUnquoted(char c) {
String s = ctx.readUnquotedValue(c);
if ("null".equals(s)){
return JsonElementNull.NULL;
} else if ("true".equals(s)){
return JsonElementBoolean.TRUE;
} else if ("false".equals(s)) {
return JsonElementBoolean.FALSE;
}
return new JsonElementNumber(s);
}
}
@@ -1,15 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
public interface ReadJsonSource {
public char nextChar(String eofMsg);
public void ignoreWhiteSpace();
public void back();
public int pos();
public String getErrorHelp();
}
@@ -1,83 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import com.avaje.ebean.text.TextException;
public class ReadJsonSourceReader implements ReadJsonSource {
private final Reader reader;
private char[] localBuffer;
private int totalPos;
private int localPos;
private int localPosEnd;
public ReadJsonSourceReader(Reader reader, int localBufferSize, int bufferSize) {
this.reader = new BufferedReader(reader,bufferSize);
this.localBuffer = new char[localBufferSize];
}
public String toString() {
return String.valueOf(localBuffer);
}
public String getErrorHelp() {
int prev = localPos - 30;
if (prev < 0){
prev = 0;
}
String c = new String(localBuffer, prev, (localPos-prev));
return "pos:"+pos()+" preceding:"+c;
}
public int pos() {
return totalPos+localPos;
}
public void ignoreWhiteSpace() {
do {
char c = nextChar("EOF ignoring whitespace");
if (!Character.isWhitespace(c)){
--localPos;
break;
}
} while(true);
}
public void back() {
localPos--;
}
public char nextChar(String eofMsg) {
if (localPos >= localPosEnd){
if (!loadLocalBuffer()) {
throw new TextException(eofMsg+" at pos:"+(totalPos+localPos));
}
}
return localBuffer[localPos++];
}
private boolean loadLocalBuffer() {
try {
localPosEnd = reader.read(localBuffer);
if (localPosEnd > 0){
totalPos += localPos;
localPos = 0;
return true;
} else {
this.localBuffer = null;
return false;
}
} catch (IOException e){
throw new TextException(e);
}
}
}
@@ -1,54 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
import com.avaje.ebean.text.TextException;
public class ReadJsonSourceString implements ReadJsonSource {
private final String source;
private final int sourceLength;
private int pos;
public ReadJsonSourceString(String source){
this.source = source;
this.sourceLength = source.length();
}
public String getErrorHelp() {
int prev = pos - 50;
if (prev < 0){
prev = 0;
}
String c = source.substring(prev, pos);
return "pos:"+pos+" precedingcontent:"+c;
}
public String toString() {
return source;
}
public int pos() {
return pos;
}
public void back() {
pos--;
}
public char nextChar(String eofMsg) {
if (pos >= sourceLength){
throw new TextException(eofMsg+" at pos:"+pos);
}
return source.charAt(pos++);
}
public void ignoreWhiteSpace() {
do {
char c = source.charAt(pos);
if (Character.isWhitespace(c)){
++pos;
} else {
break;
}
} while(true);
}
}
@@ -0,0 +1,202 @@
package com.avaje.ebeaninternal.server.text.json;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.util.ArrayStack;
import com.fasterxml.jackson.core.JsonGenerator;
import java.io.IOException;
import java.util.Collection;
import java.util.Set;
public class WriteJson {
private final SpiEbeanServer server;
private final JsonGenerator generator;
private final PathProperties pathProperties;
private final PathStack pathStack = new PathStack();
private final ArrayStack<Object> parentBeans = new ArrayStack<Object>();
public WriteJson(SpiEbeanServer server, JsonGenerator generator, PathProperties pathProperties){
this.server = server;
this.generator = generator;
this.pathProperties = pathProperties;
}
public JsonGenerator gen() {
return generator;
}
public boolean isParentBean(Object bean) {
return !parentBeans.isEmpty() && parentBeans.contains(bean);
}
public void pushParentBeanMany(Object parentBean) {
parentBeans.push(parentBean);
}
public void popParentBeanMany() {
parentBeans.pop();
}
public void beginAssocOne(String key, Object bean) {
parentBeans.push(bean);
pathStack.pushPathKey(key);
}
public void endAssocOne() {
parentBeans.pop();
pathStack.pop();
}
public WriteBean createWriteBean(BeanDescriptor<?> desc, EntityBean bean) {
if (pathProperties == null) {
return new WriteBean(desc, bean);
}
boolean explicitAllProps = false;
Set<String> currentIncludeProps = pathProperties.get(pathStack.peekWithNull());
if (currentIncludeProps != null) {
explicitAllProps = currentIncludeProps.contains("*");
if (explicitAllProps || currentIncludeProps.isEmpty()) {
currentIncludeProps = null;
}
}
return new WriteBean(desc, explicitAllProps, currentIncludeProps, bean);
}
public class WriteBean {
final boolean explicitAllProps;
final Set<String> currentIncludeProps;
final BeanDescriptor<?> desc;
final EntityBean currentBean;
WriteBean(BeanDescriptor<?> desc, EntityBean currentBean){
this(desc, false, null, currentBean);
}
WriteBean(BeanDescriptor<?> desc, boolean explicitAllProps, Set<String> currentIncludeProps, EntityBean currentBean) {
super();
this.desc = desc;
this.currentBean = currentBean;
this.explicitAllProps = explicitAllProps;
this.currentIncludeProps = currentIncludeProps;
}
private boolean isReferenceOnly() {
return !explicitAllProps && currentIncludeProps == null && currentBean._ebean_getIntercept().isReference();
}
private boolean isIncludeProperty(BeanProperty prop) {
if (explicitAllProps)
return true;
if (currentIncludeProps != null) {
// explicitly controlled by pathProperties
return currentIncludeProps.contains(prop.getName());
} else {
// include only loaded properties
return currentBean._ebean_getIntercept().isLoadedProperty(prop.getPropertyIndex());
}
}
public void write(WriteJson writeJson) throws IOException {
BeanProperty beanProp = desc.getIdProperty();
if (beanProp != null) {
if (isIncludeProperty(beanProp)) {
beanProp.jsonWrite(writeJson, currentBean);
}
}
if (!isReferenceOnly()) {
// render all the properties and invoke lazy loading if required
BeanProperty[] props = desc.propertiesNonTransient();
for (int j = 0; j < props.length; j++) {
if (isIncludeProperty(props[j])) {
props[j].jsonWrite(writeJson, currentBean);
}
}
props = desc.propertiesTransient();
for (int j = 0; j < props.length; j++) {
if (isIncludeProperty(props[j])) {
props[j].jsonWrite(writeJson, currentBean);
}
}
}
}
}
public Boolean includeMany(String key) {
if (pathProperties != null) {
String fullPath = pathStack.peekFullPath(key);
return pathProperties.hasPath(fullPath);
}
return null;
}
public void toJson(String name, Collection<?> c) throws IOException {
beginAssocMany(name);
for (Object bean : c) {
BeanDescriptor<?> d = getDescriptor(bean.getClass());
d.jsonWrite(this, (EntityBean)bean, null);
}
endAssocMany();
}
private <T> BeanDescriptor<T> getDescriptor(Class<T> cls) {
BeanDescriptor<T> d = server.getBeanDescriptor(cls);
if (d == null) {
throw new RuntimeException("No BeanDescriptor found for " + cls);
}
return d;
}
public void beginAssocMany(String key) throws IOException {
pathStack.pushPathKey(key);
generator.writeFieldName(key);
generator.writeStartArray();
}
public void endAssocMany() throws IOException {
pathStack.pop();
generator.writeEndArray();
}
public void writeStartArray(String key) throws IOException {
if (key != null) {
generator.writeFieldName(key);
}
generator.writeStartArray();
}
public void writeStartObject(String key) throws IOException {
if (key != null) {
generator.writeFieldName(key);
}
generator.writeStartObject();
}
public void writeNull(String name) throws IOException {
generator.writeNullField(name);
}
public void writeEndObject() throws IOException {
generator.writeEndObject();
}
public void writeEndArray() throws IOException {
generator.writeEndArray();
}
}
@@ -1,8 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
public interface WriteJsonBuffer extends Appendable {
public WriteJsonBuffer append(String content);
}
@@ -1,40 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
import java.io.IOException;
public class WriteJsonBufferString implements WriteJsonBuffer {
private final StringBuilder buffer;
public WriteJsonBufferString(){
this.buffer = new StringBuilder(256);
}
public WriteJsonBufferString append(CharSequence csq) throws IOException {
buffer.append(csq);
return this;
}
public WriteJsonBufferString append(CharSequence csq, int start, int end) throws IOException {
buffer.append(csq, start, end);
return this;
}
public WriteJsonBufferString append(char c) throws IOException {
buffer.append(c);
return this;
}
public WriteJsonBufferString append(String content){
buffer.append(content);
return this;
}
public String getBufferOutput() {
return buffer.toString();
}
public String toString() {
return buffer.toString();
}
}
@@ -1,45 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
import java.io.IOException;
import java.io.Writer;
import com.avaje.ebean.text.TextException;
public class WriteJsonBufferWriter implements WriteJsonBuffer {
private final Writer buffer;
public WriteJsonBufferWriter(Writer buffer){
this.buffer = buffer;
}
public WriteJsonBufferWriter append(String content){
try {
buffer.write(content);
return this;
} catch (IOException e) {
throw new TextException(e);
}
}
public WriteJsonBufferWriter append(CharSequence csq) throws IOException {
return append(csq, 0, csq.length());
}
public WriteJsonBufferWriter append(CharSequence csq, int start, int end) throws IOException {
for (int i = start; i < end; i++) {
buffer.append(csq.charAt(i));
}
return this;
}
public WriteJsonBufferWriter append(char c) throws IOException {
try {
buffer.write(c);
return this;
} catch (IOException e) {
throw new TextException(e);
}
}
}
@@ -1,376 +0,0 @@
package com.avaje.ebeaninternal.server.text.json;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebean.text.json.JsonWriteBeanVisitor;
import com.avaje.ebean.text.json.JsonWriteOptions;
import com.avaje.ebean.text.json.JsonWriter;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.type.EscapeJson;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.util.ArrayStack;
public class WriteJsonContext implements JsonWriter {
private final SpiEbeanServer server;
private final WriteJsonBuffer buffer;
private final boolean pretty;
private final JsonValueAdapter valueAdapter;
private final ArrayStack<Object> parentBeans = new ArrayStack<Object>();
private final PathProperties pathProperties;
private final Map<String, JsonWriteBeanVisitor<?>> visitorMap;
private final String callback;
private final PathStack pathStack;
private WriteBeanState beanState;
private int depthOffset;
boolean assocOne;
public WriteJsonContext(WriteJsonBuffer buffer, boolean pretty, JsonValueAdapter dfltValueAdapter,
JsonWriteOptions options, String requestCallback, SpiEbeanServer server){
this.server = server;
this.buffer = buffer;
this.pretty = pretty;
this.pathStack = new PathStack();
this.callback = getCallback(requestCallback, options);
if (options == null){
this.valueAdapter = dfltValueAdapter;
this.visitorMap = null;
this.pathProperties = null;
} else {
this.valueAdapter = getValueAdapter(dfltValueAdapter, options.getValueAdapter());
this.visitorMap = emptyToNull(options.getVisitorMap());
this.pathProperties = emptyToNull(options.getPathProperties());
}
if (callback != null){
buffer.append(requestCallback).append("(");
}
}
public void toJson(String name, Collection<?> c) {
beginAssocMany(name);
Iterator<?> it = c.iterator();
if (!it.hasNext()){
endAssocMany();
return;
}
EntityBean o = (EntityBean)it.next();
BeanDescriptor<?> d = getDecriptor(o.getClass());
d.jsonWrite(this, o);
while (it.hasNext()) {
appendComma();
EntityBean t = (EntityBean)it.next();
d.jsonWrite(this, t);
}
endAssocMany();
}
private <T> BeanDescriptor<T> getDecriptor(Class<T> cls) {
BeanDescriptor<T> d = server.getBeanDescriptor(cls);
if (d == null){
String msg = "No BeanDescriptor found for "+cls;
throw new RuntimeException(msg);
}
return d;
}
public void appendRawValue(String key, String rawJsonValue) {
appendKeyWithComma(key, true);
buffer.append(rawJsonValue);
}
public void appendQuoteEscapeValue(String key, String valueToEscape) {
appendKeyWithComma(key, true);
EscapeJson.escapeQuote(valueToEscape, buffer);
}
public void end() {
if (callback != null){
buffer.append(")");
}
}
private <MK,MV> Map<MK,MV> emptyToNull(Map<MK,MV> m){
if ( m == null || m.isEmpty()) {
return null;
} else {
return m;
}
}
private PathProperties emptyToNull(PathProperties m){
if ( m == null || m.isEmpty()) {
return null;
} else {
return m;
}
}
private String getCallback(String requestCallback, JsonWriteOptions options) {
if (requestCallback != null){
return requestCallback;
}
if (options != null){
return options.getCallback();
}
return null;
}
private JsonValueAdapter getValueAdapter(JsonValueAdapter dfltValueAdapter, JsonValueAdapter valueAdapter) {
return valueAdapter == null ? dfltValueAdapter : valueAdapter;
}
/**
* Return the set of properties to write to JSON. If null is returned then
* the default will output the properties loaded for this bean.
*/
public Set<String> getIncludeProperties() {
if (pathProperties != null){
String path = pathStack.peekWithNull();
return pathProperties.get(path);
}
return null;
}
public JsonWriteBeanVisitor<?> getBeanVisitor() {
if (visitorMap != null){
String path = pathStack.peekWithNull();
return visitorMap.get(path);
}
return null;
}
public String getJson() {
return buffer.toString();
}
private void appendIndent(){
buffer.append("\n");
int depth = depthOffset + parentBeans.size();
for (int i = 0; i < depth; i++) {
buffer.append(" ");
}
}
public void appendObjectBegin(){
if (pretty && !assocOne){
appendIndent();
}
buffer.append("{");
}
public void appendObjectEnd(){
buffer.append("}");
}
public void appendArrayBegin(){
if (pretty){
appendIndent();
}
buffer.append("[");
depthOffset++;
}
public void appendArrayEnd(){
depthOffset--;
if (pretty){
appendIndent();
}
buffer.append("]");
}
public void appendComma(){
buffer.append(",");
}
public void addDepthOffset(int offset){
depthOffset += offset;
}
public void beginAssocOneIsNull(String key) {
depthOffset++;
internalAppendKeyBegin(key);
appendNull();
depthOffset--;
}
public void beginAssocOne(String key) {
pathStack.pushPathKey(key);
internalAppendKeyBegin(key);
assocOne = true;
}
public void endAssocOne() {
pathStack.pop();
assocOne = false;
}
public Boolean includeMany(String key) {
if (pathProperties != null){
String fullPath = pathStack.peekFullPath(key);
return pathProperties.hasPath(fullPath);
}
return null;
}
public void beginAssocMany(String key) {
pathStack.pushPathKey(key);
depthOffset--;
internalAppendKeyBegin(key);
depthOffset++;
buffer.append("[");
}
public void endAssocMany(){
pathStack.pop();
if (pretty){
depthOffset--;
appendIndent();
depthOffset++;
}
buffer.append("]");
}
private void internalAppendKeyBegin(String key) {
if (!beanState.isFirstKey()){
buffer.append(",");
}
if (pretty){
appendIndent();
}
appendKeyWithComma(key, false);
}
public <T> void appendNameValue(String key, ScalarType<T> scalarType, T value) {
appendKeyWithComma(key, true);
scalarType.jsonWrite(buffer, value, getValueAdapter());
}
public void appendDiscriminator(String key, String discValue) {
appendKeyWithComma(key, true);
buffer.append("\"");
buffer.append(discValue);
buffer.append("\"");
}
private void appendKeyWithComma(String key, boolean withComma) {
if (withComma){
if (!beanState.isFirstKey()){
buffer.append(",");
}
}
buffer.append("\"");
if(key == null) {
buffer.append("null");
} else {
buffer.append(key);
}
buffer.append("\":");
}
public void appendNull(String key) {
appendKeyWithComma(key, true);
buffer.append("null");
}
public void appendNull() {
buffer.append("null");
}
public JsonValueAdapter getValueAdapter() {
return valueAdapter;
}
public String toString() {
return buffer.toString();
}
public void popParentBean(){
parentBeans.pop();
}
public void pushParentBean(Object parentBean){
parentBeans.push(parentBean);
}
public void popParentBeanMany(){
parentBeans.pop();
depthOffset--;
}
public void pushParentBeanMany(Object parentBean){
parentBeans.push(parentBean);
depthOffset++;
}
public boolean isParentBean(Object bean){
if (parentBeans.isEmpty()){
return false;
} else {
return parentBeans.contains(bean);
}
}
public WriteBeanState pushBeanState(Object bean) {
WriteBeanState newState = new WriteBeanState();//bean);
WriteBeanState prevState = beanState;
beanState = newState;
return prevState;
}
public void pushPreviousState(WriteBeanState previousState) {
this.beanState = previousState;
}
public static class WriteBeanState {
private boolean firstKeyOut;
public WriteBeanState() {
}
public boolean isFirstKey() {
if (!firstKeyOut){
firstKeyOut = true;
return true;
} else {
return false;
}
}
}
}
@@ -0,0 +1,374 @@
package com.avaje.ebeaninternal.server.type;
/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Locale;
/**
* Rob Bygrave: This is a copy of the google guava InetAddresses class
* with some features removed.
*
*
* Static utility methods pertaining to {@link InetAddress} instances.
*
* <p><b>Important note:</b> Unlike {@code InetAddress.getByName()}, the
* methods of this class never cause DNS services to be accessed. For
* this reason, you should prefer these methods as much as possible over
* their JDK equivalents whenever you are expecting to handle only
* IP address string literals -- there is no blocking DNS penalty for a
* malformed string.
*
* <p>This class hooks into the {@code sun.net.util.IPAddressUtil} class
* to make use of the {@code textToNumericFormatV4} and
* {@code textToNumericFormatV6} methods directly as a means to avoid
* accidentally traversing all nameservices (it can be vitally important
* to avoid, say, blocking on DNS at times).
*
* <p>When dealing with {@link Inet4Address} and {@link Inet6Address}
* objects as byte arrays (vis. {@code InetAddress.getAddress()}) they
* are 4 and 16 bytes in length, respectively, and represent the address
* in network byte order.
*
* <p>Examples of IP addresses and their byte representations:
* <ul>
* <li>The IPv4 loopback address, {@code "127.0.0.1"}.<br/>
* {@code 7f 00 00 01}
*
* <li>The IPv6 loopback address, {@code "::1"}.<br/>
* {@code 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01}
*
* <li>From the IPv6 reserved documentation prefix ({@code 2001:db8::/32}),
* {@code "2001:db8::1"}.<br/>
* {@code 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 01}
*
* <li>An IPv6 "IPv4 compatible" (or "compat") address,
* {@code "::192.168.0.1"}.<br/>
* {@code 00 00 00 00 00 00 00 00 00 00 00 00 c0 a8 00 01}
*
* <li>An IPv6 "IPv4 mapped" address, {@code "::ffff:192.168.0.1"}.<br/>
* {@code 00 00 00 00 00 00 00 00 00 00 ff ff c0 a8 00 01}
* </ul>
*
* <p>A few notes about IPv6 "IPv4 mapped" addresses and their observed
* use in Java.
* <br><br>
* "IPv4 mapped" addresses were originally a representation of IPv4
* addresses for use on an IPv6 socket that could receive both IPv4
* and IPv6 connections (by disabling the {@code IPV6_V6ONLY} socket
* option on an IPv6 socket). Yes, it's confusing. Nevertheless,
* these "mapped" addresses were never supposed to be seen on the
* wire. That assumption was dropped, some say mistakenly, in later
* RFCs with the apparent aim of making IPv4-to-IPv6 transition simpler.
*
* <p>Technically one <i>can</i> create a 128bit IPv6 address with the wire
* format of a "mapped" address, as shown above, and transmit it in an
* IPv6 packet header. However, Java's InetAddress creation methods
* appear to adhere doggedly to the original intent of the "mapped"
* address: all "mapped" addresses return {@link Inet4Address} objects.
*
* <p>For added safety, it is common for IPv6 network operators to filter
* all packets where either the source or destination address appears to
* be a "compat" or "mapped" address. Filtering suggestions usually
* recommend discarding any packets with source or destination addresses
* in the invalid range {@code ::/3}, which includes both of these bizarre
* address formats. For more information on "bogons", including lists
* of IPv6 bogon space, see:
*
* <ul>
* <li><a target="_parent"
* href="http://en.wikipedia.org/wiki/Bogon_filtering"
* >http://en.wikipedia.org/wiki/Bogon_filtering</a>
* <li><a target="_parent"
* href="http://www.cymru.com/Bogons/ipv6.txt"
* >http://www.cymru.com/Bogons/ipv6.txt</a>
* <li><a target="_parent"
* href="http://www.cymru.com/Bogons/v6bogon.html"
* >http://www.cymru.com/Bogons/v6bogon.html</a>
* <li><a target="_parent"
* href="http://www.space.net/~gert/RIPE/ipv6-filters.html"
* >http://www.space.net/~gert/RIPE/ipv6-filters.html</a>
* </ul>
*
* @author Erik Kline
* @since 5
*/
//@Beta
public final class ConvertInetAddresses {
private static final int IPV4_PART_COUNT = 4;
private static final int IPV6_PART_COUNT = 8;
private ConvertInetAddresses() {}
/**
* Returns the {@link InetAddress} having the given string
* representation.
*
* <p>This deliberately avoids all nameservice lookups (e.g. no DNS).
*
* @param ipString {@code String} containing an IPv4 or IPv6 string literal,
* e.g. {@code "192.168.0.1"} or {@code "2001:db8::1"}
* @return {@link InetAddress} representing the argument
* @throws IllegalArgumentException if the argument is not a valid
* IP string literal
*/
public static InetAddress forString(String ipString) {
byte[] addr = textToNumericFormatV4(ipString);
if (addr == null) {
// Scanning for IPv4 string literal failed; try IPv6.
addr = textToNumericFormatV6(ipString);
}
// The argument was malformed, i.e. not an IP string literal.
if (addr == null) {
throw new IllegalArgumentException(
String.format("'%s' is not an IP string literal.", ipString));
}
try {
return InetAddress.getByAddress(addr);
} catch (UnknownHostException e) {
/*
* This really shouldn't happen in practice since all our byte
* sequences should be valid IP addresses.
*
* However {@link InetAddress#getByAddress} is documented as
* potentially throwing this "if IP address is of illegal length".
*
* This is mapped to IllegalArgumentException since, presumably,
* the argument triggered some processing bug in either
* {@link IPAddressUtil#textToNumericFormatV4} or
* {@link IPAddressUtil#textToNumericFormatV6}.
*/
throw new IllegalArgumentException(
String.format("'%s' is extremely broken.", ipString), e);
}
}
/**
* Returns {@code true} if the supplied string is a valid IP string
* literal, {@code false} otherwise.
*
* @param ipString {@code String} to evaluated as an IP string literal
* @return {@code true} if the argument is a valid IP string literal
*/
public static boolean isInetAddress(String ipString) {
try {
forString(ipString);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
private static byte[] textToNumericFormatV4(String ipString) {
boolean isIpv6 = false;
// handle IPv6 forms of IPv4 addresses
// TODO: use Ascii.toUpperCase() when available
if (ipString.toUpperCase(Locale.US).startsWith("::FFFF:")) {
ipString = ipString.substring(7);
} else if (ipString.startsWith("::")) {
ipString = ipString.substring(2);
isIpv6 = true;
}
String[] address = ipString.split("\\.");
if (address.length != IPV4_PART_COUNT) {
return null;
}
try {
byte[] bytes = new byte[IPV4_PART_COUNT];
for (int i = 0; i < bytes.length; i++) {
int piece = Integer.parseInt(address[i]);
if (piece < 0 || piece > 255) {
return null;
}
// No leading zeroes are allowed. See
// http://tools.ietf.org/html/draft-main-ipaddr-text-rep-00
// section 2.1 for discussion.
if (address[i].startsWith("0") && address[i].length() != 1) {
return null;
}
bytes[i] = (byte) piece;
}
if (isIpv6) { // prepend with zeroes;
byte[] data = new byte[2 * IPV6_PART_COUNT]; // Java initializes arrays to zero
System.arraycopy(bytes, 0, data, 12, IPV4_PART_COUNT);
return data;
} else {
return bytes;
}
} catch (NumberFormatException ex) {
return null;
}
}
private static byte[] textToNumericFormatV6(String ipString) {
if (!ipString.contains(":")) {
return null;
}
if (ipString.contains(":::")) {
return null;
}
if (ipString.contains(".")) {
ipString = convertDottedQuadToHex(ipString);
if (ipString == null) {
return null;
}
}
ipString = padIpString(ipString);
try {
String[] address = ipString.split(":", IPV6_PART_COUNT);
if (address.length != IPV6_PART_COUNT) {
return null;
}
byte[] bytes = new byte[2 * IPV6_PART_COUNT];
for (int i = 0; i < IPV6_PART_COUNT; i++) {
int piece = address[i].equals("") ? 0 : Integer.parseInt(address[i], 16);
bytes[2 * i] = (byte) ((piece & 0xFF00) >>> 8);
bytes[2 * i + 1] = (byte) (piece & 0xFF);
}
return bytes;
} catch (NumberFormatException ex) {
return null;
}
}
// Fill in any omitted colons
private static String padIpString(String ipString) {
if (ipString.contains("::")) {
int count = numberOfColons(ipString);
StringBuilder buffer = new StringBuilder("::");
for (int i = 0; i + count < 7; i++) {
buffer.append(":");
}
ipString = ipString.replace("::", buffer);
}
return ipString;
}
private static int numberOfColons(String s) {
int count = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ':') {
count++;
}
}
return count;
}
private static String convertDottedQuadToHex(String ipString) {
int lastColon = ipString.lastIndexOf(':');
String initialPart = ipString.substring(0, lastColon + 1);
String dottedQuad = ipString.substring(lastColon + 1);
byte[] quad = textToNumericFormatV4(dottedQuad);
if (quad == null) {
return null;
}
String penultimate = Integer.toHexString(((quad[0] & 0xff) << 8) | (quad[1] & 0xff));
String ultimate = Integer.toHexString(((quad[2] & 0xff) << 8) | (quad[3] & 0xff));
return initialPart + penultimate + ":" + ultimate;
}
/**
* Returns the string representation of an {@link InetAddress} suitable
* for inclusion in a URI.
*
* <p>For IPv4 addresses, this is identical to
* {@link InetAddress#getHostAddress()}, but for IPv6 addresses it
* surrounds this text with square brackets; for example
* {@code "[2001:db8::1]"}.
*
* <p>Per section 3.2.2 of
* <a target="_parent"
* href="http://tools.ietf.org/html/rfc3986#section-3.2.2"
* >http://tools.ietf.org/html/rfc3986</a>,
* a URI containing an IPv6 string literal is of the form
* {@code "http://[2001:db8::1]:8888/index.html"}.
*
* <p>Use of either {@link InetAddress#getHostAddress()} or this
* method is recommended over {@link InetAddress#toString()} when an
* IP address string literal is desired. This is because
* {@link InetAddress#toString()} prints the hostname and the IP
* address string joined by a "/".
*
* @param ip {@link InetAddress} to be converted to URI string literal
* @return {@code String} containing URI-safe string literal
*/
public static String toUriString(InetAddress ip) {
if (ip instanceof Inet6Address) {
return "[" + ip.getHostAddress() + "]";
}
return ip.getHostAddress();
}
/**
* Returns an InetAddress representing the literal IPv4 or IPv6 host
* portion of a URL, encoded in the format specified by RFC 3986 section 3.2.2.
*
* <p>This function is similar to {@link ConvertInetAddresses#forString(String)},
* however, it requires that IPv6 addresses are surrounded by square brackets.
*
* <p>This function is the inverse of
* {@link ConvertInetAddresses#toUriString(java.net.InetAddress)}.
*
* @param hostAddr A RFC 3986 section 3.2.2 encoded IPv4 or IPv6 address
* @return an InetAddress representing the address in {@code hostAddr}
* @throws IllegalArgumentException if {@code hostAddr} is not a valid
* IPv4 address, or IPv6 address surrounded by square brackets
*/
public static InetAddress forUriString(String hostAddr) {
//Preconditions.checkNotNull(hostAddr);
//Preconditions.checkArgument(hostAddr.length() > 0, "host string is empty");
InetAddress retval = null;
// IPv4 address?
try {
retval = forString(hostAddr);
if (retval instanceof Inet4Address) {
return retval;
}
} catch (IllegalArgumentException e) {
// Not a valid IP address, fall through.
}
// IPv6 address
if (!(hostAddr.startsWith("[") && hostAddr.endsWith("]"))) {
throw new IllegalArgumentException("Not a valid address: \"" + hostAddr + '"');
}
retval = forString(hostAddr.substring(1, hostAddr.length() - 1));
if (retval instanceof Inet6Address) {
return retval;
}
throw new IllegalArgumentException("Not a valid address: \"" + hostAddr + '"');
}
}
@@ -1,22 +1,16 @@
package com.avaje.ebeaninternal.server.type;
import java.io.IOException;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.CompoundTypeProperty;
import com.avaje.ebean.text.json.JsonElement;
import com.avaje.ebean.text.json.JsonElementObject;
import com.avaje.ebeaninternal.server.text.json.ReadJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext.WriteBeanState;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
/**
* The internal representation of a Compound Type (Immutable Compound Value
* Object).
*
* @author rbygrave
* The internal representation of a Compound Type (Immutable Compound Value Object).
*
* @param <V>
* The Type of the "Immutable Compound Value Object".
@@ -168,47 +162,26 @@ public final class CtCompoundType<V> implements ScalarDataReader<V> {
return parent + "." + propName;
}
}
public Object jsonRead(ReadJsonContext ctx) {
if (!ctx.readObjectBegin()) {
// the object is null
return null;
}
JsonElementObject jsonObject = new JsonElementObject();
do {
if (!ctx.readKeyNext()){
break;
} else {
// we read a property key ...
String propName = ctx.getTokenKey();
JsonElement unmappedJson = ctx.readUnmappedJson(propName);
jsonObject.put(propName, unmappedJson);
if (!ctx.readValueNext()){
break;
}
}
} while(true);
return readJsonElementObject(ctx, jsonObject);
public Object jsonConvert(Map<String, Object> map) {
return readJsonElementObject(map);
}
private Object readJsonElementObject(ReadJsonContext ctx, JsonElementObject jsonObject){
@SuppressWarnings("unchecked")
private Object readJsonElementObject(Map<String,Object> jsonObject){
boolean nullValue = false;
Object[] values = new Object[propReaders.length];
for (int i = 0; i < propReaders.length; i++) {
String propName = properties[i].getName();
JsonElement jsonElement = jsonObject.get(propName);
Object jsonElement = jsonObject.get(propName);
if (propReaders[i] instanceof CtCompoundType<?>) {
values[i] = ((CtCompoundType<?>)propReaders[i]).readJsonElementObject(ctx, (JsonElementObject)jsonElement);
values[i] = ((CtCompoundType<?>)propReaders[i]).readJsonElementObject((Map<String,Object>)jsonElement);
} else {
values[i] = ((ScalarType<?>)propReaders[i]).jsonFromString(jsonElement.toPrimitiveString(), ctx.getValueAdapter());
//((ScalarType<?>)propReaders[i]).jsonFromString(jsonElement.toPrimitiveString(), ctx.getValueAdapter());
values[i] = ((ScalarType<?>)propReaders[i]).parse(jsonElement.toString());;
}
if (values[i] == null){
nullValue = true;
@@ -223,40 +196,34 @@ public final class CtCompoundType<V> implements ScalarDataReader<V> {
}
public void jsonWrite(WriteJsonContext ctx, Object valueObject, String propertyName) {
if (valueObject == null){
ctx.beginAssocOneIsNull(propertyName);
} else {
ctx.pushParentBean(valueObject);
ctx.beginAssocOne(propertyName);
jsonWriteProps(ctx, valueObject, propertyName);
ctx.endAssocOne();
ctx.popParentBean();
}
public void jsonWrite(WriteJson ctx, Object valueObject, String propertyName) throws IOException {
ctx.beginAssocOne(propertyName, valueObject);
jsonWriteProps(ctx, valueObject, propertyName);
ctx.endAssocOne();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void jsonWriteProps(WriteJson ctx, Object valueObject, String propertyName) throws IOException {
if (propertyName != null) {
ctx.gen().writeFieldName(propertyName);
}
ctx.gen().writeStartObject();
for (int i = 0; i < properties.length; i++) {
String propName = properties[i].getName();
Object value = properties[i].getValue((V) valueObject);
if (propReaders[i] instanceof CtCompoundType<?>) {
((CtCompoundType) propReaders[i]).jsonWrite(ctx, value, propName);
} else {
((ScalarType) propReaders[i]).jsonWrite(ctx.gen(), propName, value);
//ctx.appendNameValue(propName, (ScalarType) propReaders[i], value);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void jsonWriteProps(WriteJsonContext ctx, Object valueObject, String propertyName) {
ctx.appendObjectBegin();
WriteBeanState prevState = ctx.pushBeanState(valueObject);
for (int i = 0; i < properties.length; i++) {
String propName = properties[i].getName();
Object value = properties[i].getValue((V)valueObject);
if (propReaders[i] instanceof CtCompoundType<?>) {
((CtCompoundType)propReaders[i]).jsonWrite(ctx, value, propName);
} else {
ctx.appendNameValue(propName, (ScalarType)propReaders[i], value);
}
}
ctx.pushPreviousState(prevState);
ctx.appendObjectEnd();
}
ctx.gen().writeEndObject();
}
}
@@ -0,0 +1,34 @@
package com.avaje.ebeaninternal.server.type;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
public class DateTimeJsonParser {
private final SimpleDateFormat dateTimeProto;
public DateTimeJsonParser() {
this("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
}
public DateTimeJsonParser(String dateTimeFormat) {
this.dateTimeProto = new SimpleDateFormat(dateTimeFormat);
this.dateTimeProto.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private SimpleDateFormat dtFormat() {
return (SimpleDateFormat) dateTimeProto.clone();
}
public Timestamp parse(String jsonDateTime) {
try {
java.util.Date d = dtFormat().parse(jsonDateTime);
return new Timestamp(d.getTime());
} catch (ParseException e) {
throw new RuntimeException("Error parsing Datetime[" + jsonDateTime + "]", e);
}
}
}
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.type;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
import java.sql.Date;
@@ -103,6 +104,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
private final ScalarType<?> timestampType = new ScalarTypeTimestamp();
private final ScalarType<?> inetAddressType = new ScalarTypeInetAddress();
private final ScalarType<?> urlType = new ScalarTypeURL();
private final ScalarType<?> uriType = new ScalarTypeURI();
private final ScalarType<?> localeType = new ScalarTypeLocale();
@@ -650,6 +652,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
ScalarType<?> uuidType = (binaryUUID) ? new ScalarTypeUUIDBinary() : new ScalarTypeUUIDVarchar();
typeMap.put(UUID.class, uuidType);
typeMap.put(InetAddress.class, inetAddressType);
typeMap.put(Locale.class, localeType);
typeMap.put(Currency.class, currencyType);
typeMap.put(TimeZone.class, timeZoneType);
@@ -1,119 +0,0 @@
package com.avaje.ebeaninternal.server.type;
import java.io.IOException;
import com.avaje.ebean.text.TextException;
import com.avaje.ebean.util.StringHelper;
import com.avaje.ebeaninternal.server.text.json.WriteJsonBuffer;
public class EscapeJson {
/**
* Unescape the JSON escaped slash character.
*/
public static String unescapeSlash(String value) {
return StringHelper.replaceString(value, "\\/","/");
}
/**
* Escape and quote the string value.
*/
public static String escapeQuote(String value) {
if (value == null) {
return "null";
}
StringBuilder sb = new StringBuilder(value.length() + 2);
sb.append("\"");
escapeAppend(value, sb);
sb.append("\"");
return sb.toString();
}
/**
* Escape quotes, \, /, \r, \n, \b, \f, \t and characters (U+0000 through
* U+001F).
*/
public static String escape(String s) {
if (s == null) {
return null;
}
StringBuilder sb = new StringBuilder();
escapeAppend(s, sb);
return sb.toString();
}
public static void escape(String value, WriteJsonBuffer sb) {
if (value == null) {
sb.append("null");
} else {
escapeAppend(value, sb);
}
}
public static void escapeQuote(String value, WriteJsonBuffer sb) {
if (value == null) {
sb.append("null");
} else {
sb.append("\"");
escapeAppend(value, sb);
sb.append("\"");
}
}
/**
* Escape quotes, \, /, \r, \n, \b, \f, \t and characters (U+0000 through
* U+001F).
*/
public static void escapeAppend(String s, Appendable sb) {
try {
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
switch (ch) {
case '"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
case '\b':
sb.append("\\b");
break;
case '\f':
sb.append("\\f");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\t':
sb.append("\\t");
break;
case '/':
sb.append("\\/");
break;
default:
if ((ch >= '\u0000' && ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F')
|| (ch >= '\u2000' && ch <= '\u20FF')) {
String hs = Integer.toHexString(ch);
sb.append("\\u");
for (int j = 0; j < 4 - hs.length(); j++) {
sb.append('0');
}
sb.append(hs.toUpperCase());
} else {
sb.append(ch);
}
}
}
} catch (IOException e) {
throw new TextException(e);
}
}
}
@@ -4,8 +4,6 @@ import java.sql.SQLException;
/**
* Reads from and binds to database columns.
*
* @author rbygrave
*/
public interface ScalarDataReader<T> {
@@ -7,8 +7,9 @@ import java.sql.SQLException;
import com.avaje.ebean.text.StringFormatter;
import com.avaje.ebean.text.StringParser;
import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebeaninternal.server.text.json.WriteJsonBuffer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* Describes a scalar type.
@@ -183,14 +184,24 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
*/
public boolean isDateTimeCapable();
public void jsonWrite(WriteJsonBuffer buffer, T value, JsonValueAdapter ctx);
public String jsonToString(T value, JsonValueAdapter ctx);
/**
* Read the value from binary input.
*/
public Object readData(DataInput dataInput) throws IOException;
public T jsonFromString(String value, JsonValueAdapter ctx);
/**
* Write the value to binary output.
*/
public void writeData(DataOutput dataOutput, Object v) throws IOException;
public Object readData(DataInput dataInput) throws IOException;
/**
* Read the value from JsonParser.
*/
public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException;
public void writeData(DataOutput dataOutput, Object v) throws IOException;
/**
* Write the value to the JsonGenerator.
*/
public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException;
}
@@ -1,98 +1,82 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebeaninternal.server.text.json.WriteJsonBuffer;
/**
* Base ScalarType object.
*/
public abstract class ScalarTypeBase<T> implements ScalarType<T> {
protected final Class<T> type;
protected final boolean jdbcNative;
protected final int jdbcType;
public ScalarTypeBase(Class<T> type, boolean jdbcNative, int jdbcType) {
this.type = type;
this.jdbcNative = jdbcNative;
this.jdbcType = jdbcType;
}
/**
* Default implementation of mutable false.
*/
@Override
protected final Class<T> type;
protected final boolean jdbcNative;
protected final int jdbcType;
public ScalarTypeBase(Class<T> type, boolean jdbcNative, int jdbcType) {
this.type = type;
this.jdbcNative = jdbcNative;
this.jdbcType = jdbcType;
}
/**
* Default implementation of mutable false.
*/
@Override
public boolean isMutable() {
return false;
}
/**
* Default to true.
*/
/**
* Default to true.
*/
@Override
public boolean isDirty(Object value) {
return true;
}
/**
* Just return 0.
*/
public int getLength() {
return 0;
}
* Just return 0.
*/
public int getLength() {
return 0;
}
public boolean isJdbcNative() {
return jdbcNative;
}
public int getJdbcType() {
return jdbcType;
}
public Class<T> getType() {
return type;
}
public boolean isJdbcNative() {
return jdbcNative;
}
@SuppressWarnings("unchecked")
public String format(Object v) {
return formatValue((T)v);
}
public int getJdbcType() {
return jdbcType;
}
/**
* Return true if the value is null.
*/
public boolean isDbNull(Object value) {
return value == null;
}
public Class<T> getType() {
return type;
}
/**
* Returns the value that was passed in.
*/
public Object getDbNullValue(Object value) {
return value;
}
@SuppressWarnings("unchecked")
public String format(Object v) {
return formatValue((T) v);
}
public void loadIgnore(DataReader dataReader) {
dataReader.incrementPos(1);
}
public void accumulateScalarTypes(String propName, CtCompoundTypeScalarList list) {
list.addScalarType(propName, this);
}
/**
* Return true if the value is null.
*/
public boolean isDbNull(Object value) {
return value == null;
}
/**
* Returns the value that was passed in.
*/
public Object getDbNullValue(Object value) {
return value;
}
public void loadIgnore(DataReader dataReader) {
dataReader.incrementPos(1);
}
public void accumulateScalarTypes(String propName, CtCompoundTypeScalarList list) {
list.addScalarType(propName, this);
}
public void jsonWrite(WriteJsonBuffer buffer, T value, JsonValueAdapter ctx) {
String v = jsonToString(value, ctx);
buffer.append(v);
}
public String jsonToString(T value, JsonValueAdapter ctx) {
return formatValue(value);
}
public T jsonFromString(String value, JsonValueAdapter ctx) {
return parse(value);
}
}
@@ -7,99 +7,107 @@ import java.sql.Date;
import java.sql.SQLException;
import java.sql.Types;
import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebeaninternal.server.text.json.WriteJsonBuffer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* Base class for Date types.
*/
public abstract class ScalarTypeBaseDate<T> extends ScalarTypeBase<T> {
public ScalarTypeBaseDate(Class<T> type, boolean jdbcNative, int jdbcType) {
super(type, jdbcNative, jdbcType);
}
public abstract java.sql.Date convertToDate(T t);
public abstract T convertFromDate(java.sql.Date ts);
public void bind(DataBind b, T value) throws SQLException {
if (value == null){
b.setNull(Types.DATE);
} else {
Date date = convertToDate(value);
b.setDate(date);
}
}
public ScalarTypeBaseDate(Class<T> type, boolean jdbcNative, int jdbcType) {
super(type, jdbcNative, jdbcType);
}
public T read(DataReader dataReader) throws SQLException {
Date ts = dataReader.getDate();
if (ts == null){
return null;
} else {
return convertFromDate(ts);
}
}
public String formatValue(T t) {
Date date = convertToDate(t);
return date.toString();
}
/**
* Convert the target value to millis.
*/
public abstract long convertToMillis(Object value);
public T parse(String value) {
Date date = Date.valueOf(value);
return convertFromDate(date);
}
public T parseDateTime(long systemTimeMillis) {
Date ts = new Date(systemTimeMillis);
return convertFromDate(ts);
}
/**
* Convert to java.sql.Date from the target Date type.
*/
public abstract java.sql.Date convertToDate(T t);
public boolean isDateTimeCapable() {
return true;
}
@Override
public String jsonToString(T value, JsonValueAdapter ctx) {
Date date = convertToDate(value);
return ctx.jsonFromDate(date);
}
@Override
public void jsonWrite(WriteJsonBuffer buffer, T value, JsonValueAdapter ctx) {
String s = jsonToString(value, ctx);
buffer.append(s);
}
/**
* Convert from java.sql.Date to the target Date type.
*/
public abstract T convertFromDate(java.sql.Date ts);
@Override
public T jsonFromString(String value, JsonValueAdapter ctx) {
Date ts = ctx.jsonToDate(value);
return convertFromDate(ts);
public void bind(DataBind b, T value) throws SQLException {
if (value == null) {
b.setNull(Types.DATE);
} else {
Date date = convertToDate(value);
b.setDate(date);
}
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
long val = dataInput.readLong();
Date date = new Date(val);
return convertFromDate(date);
}
}
public T read(DataReader dataReader) throws SQLException {
@SuppressWarnings("unchecked")
public void writeData(DataOutput dataOutput, Object v) throws IOException {
T value = (T)v;
if (value == null){
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
Date date = convertToDate(value);
dataOutput.writeLong(date.getTime());
}
Date ts = dataReader.getDate();
if (ts == null) {
return null;
} else {
return convertFromDate(ts);
}
}
public String formatValue(T t) {
Date date = convertToDate(t);
return date.toString();
}
public T parse(String value) {
Date date = Date.valueOf(value);
return convertFromDate(date);
}
public T parseDateTime(long systemTimeMillis) {
Date ts = new Date(systemTimeMillis);
return convertFromDate(ts);
}
public boolean isDateTimeCapable() {
return true;
}
@Override
public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException {
if (JsonToken.VALUE_NUMBER_INT == event) {
return parseDateTime(ctx.getLongValue());
} else {
return convertFromDate(Date.valueOf(ctx.getText()));
}
}
public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException {
long millis = convertToMillis(value);
ctx.writeNumberField(name, millis);
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
long val = dataInput.readLong();
Date date = new Date(val);
return convertFromDate(date);
}
}
@SuppressWarnings("unchecked")
public void writeData(DataOutput dataOutput, Object v) throws IOException {
T value = (T) v;
if (value == null) {
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
Date date = convertToDate(value);
dataOutput.writeLong(date.getTime());
}
}
}
@@ -7,99 +7,105 @@ import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebeaninternal.server.text.json.WriteJsonBuffer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* Base type for DateTime types.
*/
public abstract class ScalarTypeBaseDateTime<T> extends ScalarTypeBase<T> {
public ScalarTypeBaseDateTime(Class<T> type, boolean jdbcNative, int jdbcType) {
super(type, jdbcNative, jdbcType);
}
public abstract Timestamp convertToTimestamp(T t);
public abstract T convertFromTimestamp(Timestamp ts);
public void bind(DataBind b, T value) throws SQLException {
if (value == null){
b.setNull(Types.TIMESTAMP);
} else {
Timestamp ts = convertToTimestamp(value);
b.setTimestamp(ts);
}
}
protected DateTimeJsonParser dateTimeParser = new DateTimeJsonParser();
public ScalarTypeBaseDateTime(Class<T> type, boolean jdbcNative, int jdbcType) {
super(type, jdbcNative, jdbcType);
}
public T read(DataReader dataReader) throws SQLException {
Timestamp ts = dataReader.getTimestamp();
if (ts == null){
return null;
} else {
return convertFromTimestamp(ts);
}
}
public String formatValue(T t) {
Timestamp ts = convertToTimestamp(t);
return ts.toString();
}
public abstract long convertToMillis(Object value);
public T parse(String value) {
Timestamp ts = Timestamp.valueOf(value);
return convertFromTimestamp(ts);
}
public T parseDateTime(long systemTimeMillis) {
Timestamp ts = new Timestamp(systemTimeMillis);
return convertFromTimestamp(ts);
}
public abstract Timestamp convertToTimestamp(T t);
public boolean isDateTimeCapable() {
return true;
}
@Override
public void jsonWrite(WriteJsonBuffer buffer, T value, JsonValueAdapter ctx) {
String v = jsonToString(value, ctx);
buffer.append(v);
}
public abstract T convertFromTimestamp(Timestamp ts);
@Override
public String jsonToString(T value, JsonValueAdapter ctx) {
Timestamp ts = convertToTimestamp(value);
return ctx.jsonFromTimestamp(ts);
}
@Override
public T jsonFromString(String value, JsonValueAdapter ctx) {
Timestamp ts = ctx.jsonToTimestamp(value);
return convertFromTimestamp(ts);
public void bind(DataBind b, T value) throws SQLException {
if (value == null) {
b.setNull(Types.TIMESTAMP);
} else {
Timestamp ts = convertToTimestamp(value);
b.setTimestamp(ts);
}
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
long val = dataInput.readLong();
Timestamp ts = new Timestamp(val);
return convertFromTimestamp(ts);
}
}
public T read(DataReader dataReader) throws SQLException {
@SuppressWarnings("unchecked")
public void writeData(DataOutput dataOutput, Object v) throws IOException {
T value = (T)v;
if (value == null){
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
Timestamp ts = convertToTimestamp(value);
dataOutput.writeLong(ts.getTime());
}
Timestamp ts = dataReader.getTimestamp();
if (ts == null) {
return null;
} else {
return convertFromTimestamp(ts);
}
}
@Override
public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException {
if (JsonToken.VALUE_NUMBER_INT == event) {
long millis = ctx.getLongValue();
return parseDateTime(millis);
} else {
String jsonDateTime = ctx.getText();
return convertFromTimestamp(dateTimeParser.parse(jsonDateTime));
}
}
@Override
public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException {
long millis = convertToMillis(value);
ctx.writeNumberField(name, millis);
}
public String formatValue(T t) {
Timestamp ts = convertToTimestamp(t);
return ts.toString();
}
public T parse(String value) {
Timestamp ts = Timestamp.valueOf(value);
return convertFromTimestamp(ts);
}
public T parseDateTime(long systemTimeMillis) {
Timestamp ts = new Timestamp(systemTimeMillis);
return convertFromTimestamp(ts);
}
public boolean isDateTimeCapable() {
return true;
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
long val = dataInput.readLong();
Timestamp ts = new Timestamp(val);
return convertFromTimestamp(ts);
}
}
@SuppressWarnings("unchecked")
public void writeData(DataOutput dataOutput, Object v) throws IOException {
T value = (T) v;
if (value == null) {
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
Timestamp ts = convertToTimestamp(value);
dataOutput.writeLong(ts.getTime());
}
}
}
@@ -7,8 +7,9 @@ import java.sql.SQLException;
import java.sql.Types;
import com.avaje.ebean.text.TextException;
import com.avaje.ebean.text.json.JsonValueAdapter;
import com.avaje.ebeaninternal.server.text.json.WriteJsonBuffer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* Base ScalarType for types which converts to and from a VARCHAR database
@@ -24,14 +25,27 @@ public abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
super(type, jdbcNative, jdbcType);
}
/**
* Format the target type to a string.
*/
public abstract String formatValue(T v);
/**
* Parse from a formatted string value.
*/
public abstract T parse(String value);
/**
* Convert from DB string value to the target type.
*/
public abstract T convertFromDbString(String dbValue);
/**
* Convert to DB string from the target type.
*/
public abstract String convertToDbString(T beanValue);
@Override
public void bind(DataBind b, T value) throws SQLException {
if (value == null) {
b.setNull(Types.VARCHAR);
@@ -41,6 +55,7 @@ public abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
}
}
@Override
public T read(DataReader dataReader) throws SQLException {
String s = dataReader.getString();
if (s == null) {
@@ -50,6 +65,7 @@ public abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
}
}
@Override
@SuppressWarnings("unchecked")
public T toBeanType(Object value) {
if (value == null) {
@@ -61,6 +77,7 @@ public abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
return (T) value;
}
@Override
public Object toJdbcType(Object value) {
if (value instanceof String) {
return parse((String) value);
@@ -68,32 +85,23 @@ public abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
return value;
}
@Override
public T parseDateTime(long systemTimeMillis) {
throw new TextException("Not Supported");
}
@Override
public boolean isDateTimeCapable() {
return false;
}
@Override
@SuppressWarnings("unchecked")
public String format(Object v) {
return formatValue((T) v);
}
public T jsonFromString(String value, JsonValueAdapter ctx) {
return parse(EscapeJson.unescapeSlash(value));
}
public String toJsonString(Object value, JsonValueAdapter ctx) {
return EscapeJson.escapeQuote(format(value));
}
@Override
public void jsonWrite(WriteJsonBuffer buffer, T value, JsonValueAdapter ctx) {
EscapeJson.escapeQuote(format(value), buffer);
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
@@ -115,4 +123,14 @@ public abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
dataOutput.writeUTF(s);
}
}
@Override
public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException {
return parse(ctx.getValueAsString());
}
@Override
public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException {
ctx.writeStringField(name, format(value));
}
}
@@ -8,6 +8,9 @@ import java.sql.SQLException;
import java.sql.Types;
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* ScalarType for BigDecimal.
@@ -74,5 +77,15 @@ public class ScalarTypeBigDecimal extends ScalarTypeBase<BigDecimal> {
public boolean isDateTimeCapable() {
return true;
}
@Override
public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException {
return ctx.getDecimalValue();
}
public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException {
ctx.writeNumberField(name, (BigDecimal)value);
}
}
@@ -8,284 +8,295 @@ import java.sql.Types;
import com.avaje.ebean.text.TextException;
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* ScalarType for Boolean and boolean.
* <p>
* This may or may not be a native jdbc type depending on the database and jdbc
* driver.
* This may or may not be a native jdbc type depending on the database and jdbc driver.
* </p>
*/
public class ScalarTypeBoolean {
public static class Native extends BooleanBase {
public static class Native extends BooleanBase {
/**
* Native Boolean database type.
*/
public Native() {
super(true, Types.BOOLEAN);
}
public Boolean toBeanType(Object value) {
return BasicTypeConverter.toBoolean(value);
}
public Object toJdbcType(Object value) {
return BasicTypeConverter.convert(value, jdbcType);
}
public void bind(DataBind b, Boolean value) throws SQLException {
if (value == null) {
b.setNull(Types.BOOLEAN);
} else {
b.setBoolean(value);
}
}
public Boolean read(DataReader dataReader) throws SQLException {
return dataReader.getBoolean();
}
}
/**
* The Class BitBoolean converts a JDBC type BIT to a java boolean
*
* <p>
* Sometimes booleans may be mapped to the JDBC type BIT. To use
* the BitBoolean specify type.boolean.dbtype="bit" in the ebean configuration
* </p>
*/
public static class BitBoolean extends BooleanBase {
/**
* Native Boolean database type.
*/
public BitBoolean() {
super(true, Types.BIT);
}
public Boolean toBeanType(Object value) {
return BasicTypeConverter.toBoolean(value);
}
public Object toJdbcType(Object value) {
// use JDBC driver to convert boolean to bit
return BasicTypeConverter.toBoolean(value);
}
public void bind(DataBind b, Boolean value) throws SQLException {
if (value == null) {
b.setNull(Types.BIT);
} else {
// use JDBC driver to convert boolean to bit
b.setBoolean(value);
}
}
public Boolean read(DataReader dataReader) throws SQLException {
return dataReader.getBoolean();
}
}
/**
* Converted to/from an Integer in the Database.
*/
public static class IntBoolean extends BooleanBase {
private final Integer trueValue;
private final Integer falseValue;
public IntBoolean(Integer trueValue, Integer falseValue) {
super(false, Types.INTEGER);
this.trueValue = trueValue;
this.falseValue = falseValue;
}
@Override
public int getLength() {
return 1;
}
public void bind(DataBind b, Boolean value) throws SQLException {
if (value == null) {
b.setNull(Types.INTEGER);
} else {
b.setInt(toInteger(value));
}
}
public Boolean read(DataReader dataReader) throws SQLException {
Integer i = dataReader.getInt();
if (i == null){
return null;
}
if (i.equals(trueValue)){
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
public Object toJdbcType(Object value) {
return toInteger(value);
}
/**
* Convert the Boolean value to the db value.
*/
public Integer toInteger(Object value) {
if (value == null) {
return null;
}
Boolean b = (Boolean) value;
if (b.booleanValue()) {
return trueValue;
} else {
return falseValue;
}
}
/**
* Convert the db value to the Boolean value.
*/
public Boolean toBeanType(Object value) {
if (value == null) {
return null;
}
if (value instanceof Boolean){
return (Boolean)value;
}
if (trueValue.equals(value)) {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
}
/**
* Converted to/from an Integer in the Database.
*/
public static class StringBoolean extends BooleanBase {
private final String trueValue;
private final String falseValue;
public StringBoolean(String trueValue, String falseValue) {
super(false, Types.VARCHAR);
this.trueValue = trueValue;
this.falseValue = falseValue;
}
@Override
public int getLength() {
// typically this will return 1
return Math.max(trueValue.length(), falseValue.length());
}
public void bind(DataBind b, Boolean value) throws SQLException {
if (value == null) {
b.setNull(Types.VARCHAR);
} else {
b.setString(toString(value));
}
}
public Boolean read(DataReader dataReader) throws SQLException {
String string = dataReader.getString();
if (string == null) {
return null;
}
if (string.equals(trueValue)){
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
public Object toJdbcType(Object value) {
return toString(value);
}
/**
* Convert the Boolean value to the db value.
*/
public String toString(Object value) {
if (value == null) {
return null;
}
Boolean b = (Boolean) value;
if (b.booleanValue()) {
return trueValue;
} else {
return falseValue;
}
}
/**
* Convert the db value to the Boolean value.
*/
public Boolean toBeanType(Object value) {
if (value == null) {
return null;
}
if (value instanceof Boolean){
return (Boolean)value;
}
if (trueValue.equals(value)) {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
}
public static abstract class BooleanBase extends ScalarTypeBase<Boolean> {
public BooleanBase(boolean jdbcNative, int jdbcType) {
super(Boolean.class, jdbcNative, jdbcType);
}
public String formatValue(Boolean t) {
return t.toString();
}
public Boolean parse(String value) {
return Boolean.valueOf(value);
}
public Boolean parseDateTime(long systemTimeMillis) {
throw new TextException("Not Supported");
}
public boolean isDateTimeCapable() {
return false;
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
boolean val = dataInput.readBoolean();
return Boolean.valueOf(val);
}
}
public void writeData(DataOutput dataOutput, Object v) throws IOException {
Boolean val = (Boolean) v;
if (val == null) {
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
dataOutput.writeBoolean(val.booleanValue());
}
}
/**
* Native Boolean database type.
*/
public Native() {
super(true, Types.BOOLEAN);
}
public Boolean toBeanType(Object value) {
return BasicTypeConverter.toBoolean(value);
}
public Object toJdbcType(Object value) {
return BasicTypeConverter.convert(value, jdbcType);
}
public void bind(DataBind b, Boolean value) throws SQLException {
if (value == null) {
b.setNull(Types.BOOLEAN);
} else {
b.setBoolean(value);
}
}
public Boolean read(DataReader dataReader) throws SQLException {
return dataReader.getBoolean();
}
}
/**
* The Class BitBoolean converts a JDBC type BIT to a java boolean
*
* <p>
* Sometimes booleans may be mapped to the JDBC type BIT. To use the BitBoolean specify
* type.boolean.dbtype="bit" in the ebean configuration
* </p>
*/
public static class BitBoolean extends BooleanBase {
/**
* Native Boolean database type.
*/
public BitBoolean() {
super(true, Types.BIT);
}
public Boolean toBeanType(Object value) {
return BasicTypeConverter.toBoolean(value);
}
public Object toJdbcType(Object value) {
// use JDBC driver to convert boolean to bit
return BasicTypeConverter.toBoolean(value);
}
public void bind(DataBind b, Boolean value) throws SQLException {
if (value == null) {
b.setNull(Types.BIT);
} else {
// use JDBC driver to convert boolean to bit
b.setBoolean(value);
}
}
public Boolean read(DataReader dataReader) throws SQLException {
return dataReader.getBoolean();
}
}
/**
* Converted to/from an Integer in the Database.
*/
public static class IntBoolean extends BooleanBase {
private final Integer trueValue;
private final Integer falseValue;
public IntBoolean(Integer trueValue, Integer falseValue) {
super(false, Types.INTEGER);
this.trueValue = trueValue;
this.falseValue = falseValue;
}
@Override
public int getLength() {
return 1;
}
public void bind(DataBind b, Boolean value) throws SQLException {
if (value == null) {
b.setNull(Types.INTEGER);
} else {
b.setInt(toInteger(value));
}
}
public Boolean read(DataReader dataReader) throws SQLException {
Integer i = dataReader.getInt();
if (i == null) {
return null;
}
if (i.equals(trueValue)) {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
public Object toJdbcType(Object value) {
return toInteger(value);
}
/**
* Convert the Boolean value to the db value.
*/
public Integer toInteger(Object value) {
if (value == null) {
return null;
}
Boolean b = (Boolean) value;
if (b.booleanValue()) {
return trueValue;
} else {
return falseValue;
}
}
/**
* Convert the db value to the Boolean value.
*/
public Boolean toBeanType(Object value) {
if (value == null) {
return null;
}
if (value instanceof Boolean) {
return (Boolean) value;
}
if (trueValue.equals(value)) {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
}
/**
* Converted to/from an Integer in the Database.
*/
public static class StringBoolean extends BooleanBase {
private final String trueValue;
private final String falseValue;
public StringBoolean(String trueValue, String falseValue) {
super(false, Types.VARCHAR);
this.trueValue = trueValue;
this.falseValue = falseValue;
}
@Override
public int getLength() {
// typically this will return 1
return Math.max(trueValue.length(), falseValue.length());
}
public void bind(DataBind b, Boolean value) throws SQLException {
if (value == null) {
b.setNull(Types.VARCHAR);
} else {
b.setString(toString(value));
}
}
public Boolean read(DataReader dataReader) throws SQLException {
String string = dataReader.getString();
if (string == null) {
return null;
}
if (string.equals(trueValue)) {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
public Object toJdbcType(Object value) {
return toString(value);
}
/**
* Convert the Boolean value to the db value.
*/
public String toString(Object value) {
if (value == null) {
return null;
}
Boolean b = (Boolean) value;
if (b.booleanValue()) {
return trueValue;
} else {
return falseValue;
}
}
/**
* Convert the db value to the Boolean value.
*/
public Boolean toBeanType(Object value) {
if (value == null) {
return null;
}
if (value instanceof Boolean) {
return (Boolean) value;
}
if (trueValue.equals(value)) {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
}
public static abstract class BooleanBase extends ScalarTypeBase<Boolean> {
public BooleanBase(boolean jdbcNative, int jdbcType) {
super(Boolean.class, jdbcNative, jdbcType);
}
public String formatValue(Boolean t) {
return t.toString();
}
public Boolean parse(String value) {
return Boolean.valueOf(value);
}
public Boolean parseDateTime(long systemTimeMillis) {
throw new TextException("Not Supported");
}
public boolean isDateTimeCapable() {
return false;
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
boolean val = dataInput.readBoolean();
return Boolean.valueOf(val);
}
}
public void writeData(DataOutput dataOutput, Object v) throws IOException {
Boolean val = (Boolean) v;
if (val == null) {
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
dataOutput.writeBoolean(val.booleanValue());
}
}
@Override
public Object jsonRead(JsonParser ctx, JsonToken event) {
return JsonToken.VALUE_TRUE == event ? Boolean.TRUE : Boolean.FALSE;
}
public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException {
ctx.writeBooleanField(name, (Boolean) value);
}
}
}
@@ -8,71 +8,83 @@ import java.sql.Types;
import com.avaje.ebean.text.TextException;
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* ScalarType for Byte.
*/
public class ScalarTypeByte extends ScalarTypeBase<Byte> {
public ScalarTypeByte() {
super(Byte.class, true,Types.TINYINT );
}
public void bind(DataBind b, Byte value) throws SQLException {
if (value == null){
b.setNull(Types.TINYINT);
} else {
b.setByte(value);
}
}
public ScalarTypeByte() {
super(Byte.class, true, Types.TINYINT);
}
public Byte read(DataReader dataReader) throws SQLException {
return dataReader.getByte();
}
public Object toJdbcType(Object value) {
return BasicTypeConverter.toByte(value);
}
public Byte toBeanType(Object value) {
return BasicTypeConverter.toByte(value);
}
public String formatValue(Byte t) {
return t.toString();
public void bind(DataBind b, Byte value) throws SQLException {
if (value == null) {
b.setNull(Types.TINYINT);
} else {
b.setByte(value);
}
}
public Byte parse(String value) {
throw new TextException("Not supported");
}
public Byte parseDateTime(long systemTimeMillis) {
throw new TextException("Not Supported");
}
public boolean isDateTimeCapable() {
return false;
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
byte val = dataInput.readByte();
return Byte.valueOf(val);
}
public Byte read(DataReader dataReader) throws SQLException {
return dataReader.getByte();
}
public Object toJdbcType(Object value) {
return BasicTypeConverter.toByte(value);
}
public Byte toBeanType(Object value) {
return BasicTypeConverter.toByte(value);
}
@Override
public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException {
throw new IOException("Not supported");
}
@Override
public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException {
throw new IOException("Not supported");
}
public String formatValue(Byte t) {
return t.toString();
}
public Byte parse(String value) {
throw new TextException("Not supported");
}
public Byte parseDateTime(long systemTimeMillis) {
throw new TextException("Not Supported");
}
public boolean isDateTimeCapable() {
return false;
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
byte val = dataInput.readByte();
return Byte.valueOf(val);
}
}
public void writeData(DataOutput dataOutput, Object v) throws IOException {
public void writeData(DataOutput dataOutput, Object v) throws IOException {
Byte val = (Byte) v;
if (val == null) {
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
dataOutput.writeByte(val);
}
Byte val = (Byte) v;
if (val == null) {
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
dataOutput.writeByte(val);
}
}
}
@@ -1,83 +1,96 @@
package com.avaje.ebeaninternal.server.type;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.sql.SQLException;
import com.avaje.ebean.text.TextException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
/**
* Base type for binary types.
*/
public abstract class ScalarTypeBytesBase extends ScalarTypeBase<byte[]> {
protected ScalarTypeBytesBase(boolean jdbcNative, int jdbcType) {
super(byte[].class, jdbcNative, jdbcType);
}
public Object convertFromBytes(byte[] bytes) {
return bytes;
protected ScalarTypeBytesBase(boolean jdbcNative, int jdbcType) {
super(byte[].class, jdbcNative, jdbcType);
}
public Object convertFromBytes(byte[] bytes) {
return bytes;
}
public byte[] convertToBytes(Object value) {
return (byte[]) value;
}
public void bind(DataBind b, byte[] value) throws SQLException {
if (value == null) {
b.setNull(jdbcType);
} else {
b.setBytes(value);
}
}
public byte[] convertToBytes(Object value) {
return (byte[]) value;
public Object toJdbcType(Object value) {
return value;
}
public byte[] toBeanType(Object value) {
return (byte[]) value;
}
@Override
public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException {
ctx.writeBinaryField(name, (byte[]) value);
}
@Override
public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream(500);
ctx.readBinaryValue(out);
return out.toByteArray();
}
public String formatValue(byte[] t) {
throw new TextException("Not supported");
}
public byte[] parse(String value) {
throw new TextException("Not supported");
}
public byte[] parseDateTime(long systemTimeMillis) {
throw new TextException("Not supported");
}
public boolean isDateTimeCapable() {
return false;
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
int len = dataInput.readInt();
byte[] buf = new byte[len];
dataInput.readFully(buf, 0, buf.length);
return buf;
}
public void bind(DataBind b, byte[] value) throws SQLException {
if (value == null) {
b.setNull(jdbcType);
} else {
b.setBytes(value);
}
}
}
public Object toJdbcType(Object value) {
return value;
}
public byte[] toBeanType(Object value) {
return (byte[])value;
}
public String formatValue(byte[] t) {
throw new TextException("Not supported");
public void writeData(DataOutput dataOutput, Object v) throws IOException {
if (v == null) {
dataOutput.writeBoolean(false);
} else {
byte[] bytes = convertToBytes(v);
dataOutput.writeInt(bytes.length);
dataOutput.write(bytes);
}
}
public byte[] parse(String value) {
throw new TextException("Not supported");
}
public byte[] parseDateTime(long systemTimeMillis) {
throw new TextException("Not supported");
}
public boolean isDateTimeCapable() {
return false;
}
public Object readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
int len = dataInput.readInt();
byte[] buf = new byte[len];
dataInput.readFully(buf, 0, buf.length);
return buf;
}
}
public void writeData(DataOutput dataOutput, Object v) throws IOException {
if (v == null){
dataOutput.writeBoolean(false);
} else {
byte[] bytes = convertToBytes(v);
dataOutput.writeInt(bytes.length);
dataOutput.write(bytes);
}
}
}

Some files were not shown because too many files have changed in this diff Show More