mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
No effective change - change newline char
This commit is contained in:
@@ -1,251 +1,251 @@
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* This is a Tree like structure of paths and properties that can be used for
|
||||
* defining which parts of an object graph to render in JSON or XML, and can
|
||||
* also be used to define which parts to select and fetch for an ORM query.
|
||||
* <p>
|
||||
* It provides a way of parsing a string representation of nested path
|
||||
* properties and applying that to both what to fetch (ORM query) and what to
|
||||
* render (JAX-RS JSON / XML).
|
||||
* </p>
|
||||
*/
|
||||
public class PathProperties {
|
||||
|
||||
private final Map<String, Props> pathMap;
|
||||
|
||||
private final Props rootProps;
|
||||
|
||||
/**
|
||||
* Parse and return a PathProperties from nested string format like
|
||||
* (a,b,c(d,e),f(g)) where "c" is a path containing "d" and "e" and "f" is a
|
||||
* path containing "g" and the root path contains "a","b","c" and "f".
|
||||
*/
|
||||
public static PathProperties parse(String source) {
|
||||
return PathPropertiesParser.parse(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an empty PathProperties.
|
||||
*/
|
||||
public PathProperties() {
|
||||
this.rootProps = new Props(this, null, null);
|
||||
this.pathMap = new LinkedHashMap<String, Props>();
|
||||
this.pathMap.put(null, rootProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for creating copy.
|
||||
*/
|
||||
private PathProperties(PathProperties orig) {
|
||||
this.rootProps = orig.rootProps.copy(this);
|
||||
this.pathMap = new LinkedHashMap<String, Props>(orig.pathMap.size());
|
||||
Set<Entry<String, Props>> entrySet = orig.pathMap.entrySet();
|
||||
for (Entry<String, Props> e : entrySet) {
|
||||
pathMap.put(e.getKey(), e.getValue().copy(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this instance so that it can be modified.
|
||||
* <p>
|
||||
* For example, you may want to create a copy to add extra properties to a
|
||||
* path so that they are fetching in a ORM query but perhaps not rendered by
|
||||
* default. That is, use a PathProperties for JSON or XML rendering, but
|
||||
* create a copy, add some extra properties and then use that copy to define
|
||||
* an ORM query.
|
||||
* </p>
|
||||
*/
|
||||
public PathProperties copy() {
|
||||
return new PathProperties(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no paths defined.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return pathMap.isEmpty();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return pathMap.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the path is defined and has properties.
|
||||
*/
|
||||
public boolean hasPath(String path) {
|
||||
Props props = pathMap.get(path);
|
||||
return props != null && !props.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the properties for a given path.
|
||||
*/
|
||||
public Set<String> get(String path) {
|
||||
Props props = pathMap.get(path);
|
||||
return props == null ? null : props.getProperties();
|
||||
}
|
||||
|
||||
public void addToPath(String path, String property) {
|
||||
Props props = pathMap.get(path);
|
||||
if (props == null) {
|
||||
props = new Props(this, null, path);
|
||||
pathMap.put(path, props);
|
||||
}
|
||||
props.getProperties().add(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the properties for a given path.
|
||||
*/
|
||||
public void put(String path, Set<String> properties) {
|
||||
pathMap.put(path, new Props(this, null, path, properties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a path returning the properties set for that path.
|
||||
*/
|
||||
public Set<String> remove(String path) {
|
||||
Props props = pathMap.remove(path);
|
||||
return props == null ? null : props.getProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a shallow copy of the paths.
|
||||
*/
|
||||
public Set<String> getPaths() {
|
||||
return new LinkedHashSet<String>(pathMap.keySet());
|
||||
}
|
||||
|
||||
public Collection<Props> getPathProps() {
|
||||
return pathMap.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply these path properties as fetch paths to the query.
|
||||
*/
|
||||
public void apply(Query<?> query) {
|
||||
|
||||
for (Entry<String, Props> entry : pathMap.entrySet()) {
|
||||
String path = entry.getKey();
|
||||
String props = entry.getValue().getPropertiesAsString();
|
||||
|
||||
if (path == null || path.length() == 0) {
|
||||
query.select(props);
|
||||
} else {
|
||||
query.fetch(path, props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Props getRootProperties() {
|
||||
return rootProps;
|
||||
}
|
||||
|
||||
public static class Props {
|
||||
|
||||
private final PathProperties owner;
|
||||
|
||||
private final String parentPath;
|
||||
private final String path;
|
||||
|
||||
private final Set<String> propSet;
|
||||
|
||||
private Props(PathProperties owner, String parentPath, String path, Set<String> propSet) {
|
||||
this.owner = owner;
|
||||
this.path = path;
|
||||
this.parentPath = parentPath;
|
||||
this.propSet = propSet;
|
||||
}
|
||||
|
||||
private Props(PathProperties owner, String parentPath, String path) {
|
||||
this(owner, parentPath, path, new LinkedHashSet<String>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a shallow copy of this Props instance.
|
||||
*/
|
||||
public Props copy(PathProperties newOwner) {
|
||||
return new Props(newOwner, parentPath, path, new LinkedHashSet<String>(propSet));
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return propSet.toString();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return propSet.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties for this property set.
|
||||
*/
|
||||
public Set<String> getProperties() {
|
||||
return propSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties as a comma delimited string.
|
||||
*/
|
||||
public String getPropertiesAsString() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
Iterator<String> it = propSet.iterator();
|
||||
boolean hasNext = it.hasNext();
|
||||
while (hasNext) {
|
||||
sb.append(it.next());
|
||||
hasNext = it.hasNext();
|
||||
if (hasNext) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent path
|
||||
*/
|
||||
protected Props getParent() {
|
||||
return owner.pathMap.get(parentPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a child Property set.
|
||||
*/
|
||||
protected Props addChild(String subpath) {
|
||||
|
||||
subpath = subpath.trim();
|
||||
addProperty(subpath);
|
||||
|
||||
// build the subpath
|
||||
String p = path == null ? subpath : path + "." + subpath;
|
||||
Props nested = new Props(owner, path, p);
|
||||
owner.pathMap.put(p, nested);
|
||||
return nested;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a properties to include for this path.
|
||||
*/
|
||||
protected void addProperty(String property) {
|
||||
propSet.add(property.trim());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* This is a Tree like structure of paths and properties that can be used for
|
||||
* defining which parts of an object graph to render in JSON or XML, and can
|
||||
* also be used to define which parts to select and fetch for an ORM query.
|
||||
* <p>
|
||||
* It provides a way of parsing a string representation of nested path
|
||||
* properties and applying that to both what to fetch (ORM query) and what to
|
||||
* render (JAX-RS JSON / XML).
|
||||
* </p>
|
||||
*/
|
||||
public class PathProperties {
|
||||
|
||||
private final Map<String, Props> pathMap;
|
||||
|
||||
private final Props rootProps;
|
||||
|
||||
/**
|
||||
* Parse and return a PathProperties from nested string format like
|
||||
* (a,b,c(d,e),f(g)) where "c" is a path containing "d" and "e" and "f" is a
|
||||
* path containing "g" and the root path contains "a","b","c" and "f".
|
||||
*/
|
||||
public static PathProperties parse(String source) {
|
||||
return PathPropertiesParser.parse(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an empty PathProperties.
|
||||
*/
|
||||
public PathProperties() {
|
||||
this.rootProps = new Props(this, null, null);
|
||||
this.pathMap = new LinkedHashMap<String, Props>();
|
||||
this.pathMap.put(null, rootProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for creating copy.
|
||||
*/
|
||||
private PathProperties(PathProperties orig) {
|
||||
this.rootProps = orig.rootProps.copy(this);
|
||||
this.pathMap = new LinkedHashMap<String, Props>(orig.pathMap.size());
|
||||
Set<Entry<String, Props>> entrySet = orig.pathMap.entrySet();
|
||||
for (Entry<String, Props> e : entrySet) {
|
||||
pathMap.put(e.getKey(), e.getValue().copy(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this instance so that it can be modified.
|
||||
* <p>
|
||||
* For example, you may want to create a copy to add extra properties to a
|
||||
* path so that they are fetching in a ORM query but perhaps not rendered by
|
||||
* default. That is, use a PathProperties for JSON or XML rendering, but
|
||||
* create a copy, add some extra properties and then use that copy to define
|
||||
* an ORM query.
|
||||
* </p>
|
||||
*/
|
||||
public PathProperties copy() {
|
||||
return new PathProperties(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no paths defined.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return pathMap.isEmpty();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return pathMap.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the path is defined and has properties.
|
||||
*/
|
||||
public boolean hasPath(String path) {
|
||||
Props props = pathMap.get(path);
|
||||
return props != null && !props.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the properties for a given path.
|
||||
*/
|
||||
public Set<String> get(String path) {
|
||||
Props props = pathMap.get(path);
|
||||
return props == null ? null : props.getProperties();
|
||||
}
|
||||
|
||||
public void addToPath(String path, String property) {
|
||||
Props props = pathMap.get(path);
|
||||
if (props == null) {
|
||||
props = new Props(this, null, path);
|
||||
pathMap.put(path, props);
|
||||
}
|
||||
props.getProperties().add(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the properties for a given path.
|
||||
*/
|
||||
public void put(String path, Set<String> properties) {
|
||||
pathMap.put(path, new Props(this, null, path, properties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a path returning the properties set for that path.
|
||||
*/
|
||||
public Set<String> remove(String path) {
|
||||
Props props = pathMap.remove(path);
|
||||
return props == null ? null : props.getProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a shallow copy of the paths.
|
||||
*/
|
||||
public Set<String> getPaths() {
|
||||
return new LinkedHashSet<String>(pathMap.keySet());
|
||||
}
|
||||
|
||||
public Collection<Props> getPathProps() {
|
||||
return pathMap.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply these path properties as fetch paths to the query.
|
||||
*/
|
||||
public void apply(Query<?> query) {
|
||||
|
||||
for (Entry<String, Props> entry : pathMap.entrySet()) {
|
||||
String path = entry.getKey();
|
||||
String props = entry.getValue().getPropertiesAsString();
|
||||
|
||||
if (path == null || path.length() == 0) {
|
||||
query.select(props);
|
||||
} else {
|
||||
query.fetch(path, props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Props getRootProperties() {
|
||||
return rootProps;
|
||||
}
|
||||
|
||||
public static class Props {
|
||||
|
||||
private final PathProperties owner;
|
||||
|
||||
private final String parentPath;
|
||||
private final String path;
|
||||
|
||||
private final Set<String> propSet;
|
||||
|
||||
private Props(PathProperties owner, String parentPath, String path, Set<String> propSet) {
|
||||
this.owner = owner;
|
||||
this.path = path;
|
||||
this.parentPath = parentPath;
|
||||
this.propSet = propSet;
|
||||
}
|
||||
|
||||
private Props(PathProperties owner, String parentPath, String path) {
|
||||
this(owner, parentPath, path, new LinkedHashSet<String>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a shallow copy of this Props instance.
|
||||
*/
|
||||
public Props copy(PathProperties newOwner) {
|
||||
return new Props(newOwner, parentPath, path, new LinkedHashSet<String>(propSet));
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return propSet.toString();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return propSet.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties for this property set.
|
||||
*/
|
||||
public Set<String> getProperties() {
|
||||
return propSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties as a comma delimited string.
|
||||
*/
|
||||
public String getPropertiesAsString() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
Iterator<String> it = propSet.iterator();
|
||||
boolean hasNext = it.hasNext();
|
||||
while (hasNext) {
|
||||
sb.append(it.next());
|
||||
hasNext = it.hasNext();
|
||||
if (hasNext) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent path
|
||||
*/
|
||||
protected Props getParent() {
|
||||
return owner.pathMap.get(parentPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a child Property set.
|
||||
*/
|
||||
protected Props addChild(String subpath) {
|
||||
|
||||
subpath = subpath.trim();
|
||||
addProperty(subpath);
|
||||
|
||||
// build the subpath
|
||||
String p = path == null ? subpath : path + "." + subpath;
|
||||
Props nested = new Props(owner, path, p);
|
||||
owner.pathMap.put(p, nested);
|
||||
return nested;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a properties to include for this path.
|
||||
*/
|
||||
protected void addProperty(String property) {
|
||||
propSet.add(property.trim());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,135 +1,135 @@
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
/**
|
||||
* Parses Uri segments like :(id,name,shippingAddress(*),contacts(*)) so that
|
||||
* the response can be customised for performance.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
class PathPropertiesParser {
|
||||
|
||||
// :(a,b,c(d,e,f))
|
||||
|
||||
private final PathProperties pathProps;
|
||||
|
||||
private final String source;
|
||||
|
||||
private final char[] chars;
|
||||
|
||||
private final int eof;
|
||||
|
||||
private int pos;
|
||||
private int startPos;
|
||||
|
||||
private PathProperties.Props currentPathProps;
|
||||
|
||||
/**
|
||||
* Use {@link PathProperties#parse(String)}.
|
||||
*/
|
||||
static PathProperties parse(String source) {
|
||||
return new PathPropertiesParser(source).pathProps;
|
||||
}
|
||||
|
||||
private PathPropertiesParser(String src) {
|
||||
|
||||
if (src.startsWith(":")) {
|
||||
src = src.substring(1);
|
||||
}
|
||||
this.pathProps = new PathProperties();
|
||||
this.source = src;
|
||||
this.chars = src.toCharArray();
|
||||
this.eof = chars.length;
|
||||
|
||||
if (eof > 0) {
|
||||
currentPathProps = pathProps.getRootProperties();
|
||||
parse();
|
||||
}
|
||||
}
|
||||
|
||||
private String getPath() {
|
||||
do {
|
||||
char c1 = chars[pos++];
|
||||
switch (c1) {
|
||||
case '(':
|
||||
return currentWord();
|
||||
default:
|
||||
if (pos == 1) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
} while (pos < eof);
|
||||
throw new RuntimeException("Hit EOF while reading sectionTitle from " + startPos);
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
|
||||
do {
|
||||
String path = getPath();
|
||||
pushPath(path);
|
||||
parseSection();
|
||||
|
||||
} while (pos < eof);
|
||||
}
|
||||
|
||||
private void parseSection() {
|
||||
do {
|
||||
char c1 = chars[pos++];
|
||||
switch (c1) {
|
||||
case '(':
|
||||
addSubpath();
|
||||
break;
|
||||
case ',':
|
||||
addCurrentProperty();
|
||||
break;
|
||||
case ':':
|
||||
// start new section
|
||||
startPos = pos;
|
||||
return;
|
||||
case ')':
|
||||
// end of section
|
||||
addCurrentProperty();
|
||||
popSubpath();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
} while (pos < eof);
|
||||
if (startPos < pos) {
|
||||
String currentWord = source.substring(startPos, pos);
|
||||
currentPathProps.addProperty(currentWord);
|
||||
}
|
||||
}
|
||||
|
||||
private void addSubpath() {
|
||||
pushPath(currentWord());
|
||||
}
|
||||
|
||||
private void addCurrentProperty() {
|
||||
String w = currentWord();
|
||||
if (w.length() > 0) {
|
||||
currentPathProps.addProperty(w);
|
||||
}
|
||||
}
|
||||
|
||||
private String currentWord() {
|
||||
if (startPos == pos) {
|
||||
return "";
|
||||
}
|
||||
String currentWord = source.substring(startPos, pos - 1);
|
||||
startPos = pos;
|
||||
return currentWord;
|
||||
}
|
||||
|
||||
private void pushPath(String title) {
|
||||
|
||||
if (!"".equals(title)) {
|
||||
currentPathProps = currentPathProps.addChild(title);
|
||||
}
|
||||
}
|
||||
|
||||
private void popSubpath() {
|
||||
|
||||
currentPathProps = currentPathProps.getParent();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
/**
|
||||
* Parses Uri segments like :(id,name,shippingAddress(*),contacts(*)) so that
|
||||
* the response can be customised for performance.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
class PathPropertiesParser {
|
||||
|
||||
// :(a,b,c(d,e,f))
|
||||
|
||||
private final PathProperties pathProps;
|
||||
|
||||
private final String source;
|
||||
|
||||
private final char[] chars;
|
||||
|
||||
private final int eof;
|
||||
|
||||
private int pos;
|
||||
private int startPos;
|
||||
|
||||
private PathProperties.Props currentPathProps;
|
||||
|
||||
/**
|
||||
* Use {@link PathProperties#parse(String)}.
|
||||
*/
|
||||
static PathProperties parse(String source) {
|
||||
return new PathPropertiesParser(source).pathProps;
|
||||
}
|
||||
|
||||
private PathPropertiesParser(String src) {
|
||||
|
||||
if (src.startsWith(":")) {
|
||||
src = src.substring(1);
|
||||
}
|
||||
this.pathProps = new PathProperties();
|
||||
this.source = src;
|
||||
this.chars = src.toCharArray();
|
||||
this.eof = chars.length;
|
||||
|
||||
if (eof > 0) {
|
||||
currentPathProps = pathProps.getRootProperties();
|
||||
parse();
|
||||
}
|
||||
}
|
||||
|
||||
private String getPath() {
|
||||
do {
|
||||
char c1 = chars[pos++];
|
||||
switch (c1) {
|
||||
case '(':
|
||||
return currentWord();
|
||||
default:
|
||||
if (pos == 1) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
} while (pos < eof);
|
||||
throw new RuntimeException("Hit EOF while reading sectionTitle from " + startPos);
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
|
||||
do {
|
||||
String path = getPath();
|
||||
pushPath(path);
|
||||
parseSection();
|
||||
|
||||
} while (pos < eof);
|
||||
}
|
||||
|
||||
private void parseSection() {
|
||||
do {
|
||||
char c1 = chars[pos++];
|
||||
switch (c1) {
|
||||
case '(':
|
||||
addSubpath();
|
||||
break;
|
||||
case ',':
|
||||
addCurrentProperty();
|
||||
break;
|
||||
case ':':
|
||||
// start new section
|
||||
startPos = pos;
|
||||
return;
|
||||
case ')':
|
||||
// end of section
|
||||
addCurrentProperty();
|
||||
popSubpath();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
} while (pos < eof);
|
||||
if (startPos < pos) {
|
||||
String currentWord = source.substring(startPos, pos);
|
||||
currentPathProps.addProperty(currentWord);
|
||||
}
|
||||
}
|
||||
|
||||
private void addSubpath() {
|
||||
pushPath(currentWord());
|
||||
}
|
||||
|
||||
private void addCurrentProperty() {
|
||||
String w = currentWord();
|
||||
if (w.length() > 0) {
|
||||
currentPathProps.addProperty(w);
|
||||
}
|
||||
}
|
||||
|
||||
private String currentWord() {
|
||||
if (startPos == pos) {
|
||||
return "";
|
||||
}
|
||||
String currentWord = source.substring(startPos, pos - 1);
|
||||
startPos = pos;
|
||||
return currentWord;
|
||||
}
|
||||
|
||||
private void pushPath(String title) {
|
||||
|
||||
if (!"".equals(title)) {
|
||||
currentPathProps = currentPathProps.addChild(title);
|
||||
}
|
||||
}
|
||||
|
||||
private void popSubpath() {
|
||||
|
||||
currentPathProps = currentPathProps.getParent();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
/**
|
||||
* Convert an Object value into a String value.
|
||||
* <p>
|
||||
* Basic interface to support CSV, JSON and XML processing.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface StringFormatter {
|
||||
|
||||
/**
|
||||
* Convert an Object value into a String value.
|
||||
*/
|
||||
String format(Object value);
|
||||
}
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
/**
|
||||
* Convert an Object value into a String value.
|
||||
* <p>
|
||||
* Basic interface to support CSV, JSON and XML processing.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface StringFormatter {
|
||||
|
||||
/**
|
||||
* Convert an Object value into a String value.
|
||||
*/
|
||||
String format(Object value);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
/**
|
||||
* Convert a String value into an Object value.
|
||||
* <p>
|
||||
* Basic interface to support CSV, JSON and XML processing.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface StringParser {
|
||||
|
||||
/**
|
||||
* Convert a String value into an Object value.
|
||||
*/
|
||||
Object parse(String value);
|
||||
}
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
/**
|
||||
* Convert a String value into an Object value.
|
||||
* <p>
|
||||
* Basic interface to support CSV, JSON and XML processing.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface StringParser {
|
||||
|
||||
/**
|
||||
* Convert a String value into an Object value.
|
||||
*/
|
||||
Object parse(String value);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
/**
|
||||
* An exception occurred typically in processing CSV, JSON or XML.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class TextException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1601310159486033148L;
|
||||
|
||||
/**
|
||||
* Construct with an error message.
|
||||
*/
|
||||
public TextException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a message and cause.
|
||||
*/
|
||||
public TextException(String msg, Exception e) {
|
||||
super(msg, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a cause.
|
||||
*/
|
||||
public TextException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
/**
|
||||
* An exception occurred typically in processing CSV, JSON or XML.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class TextException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1601310159486033148L;
|
||||
|
||||
/**
|
||||
* Construct with an error message.
|
||||
*/
|
||||
public TextException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a message and cause.
|
||||
*/
|
||||
public TextException(String msg, Exception e) {
|
||||
super(msg, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a cause.
|
||||
*/
|
||||
public TextException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
import java.sql.Time;
|
||||
|
||||
/**
|
||||
* Parser for TIME types that supports both HH:mm:ss and HH:mm.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public final class TimeStringParser implements StringParser {
|
||||
|
||||
private static final TimeStringParser SHARED = new TimeStringParser();
|
||||
|
||||
/**
|
||||
* Return a shared instance as this is thread safe.
|
||||
*/
|
||||
public static TimeStringParser get() {
|
||||
return SHARED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the String supporting both HH:mm:ss and HH:mm formats.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public Object parse(String value) {
|
||||
if (value == null || value.trim().length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String s = value.trim();
|
||||
int minute;
|
||||
int second;
|
||||
int firstColon = s.indexOf(':');
|
||||
int secondColon = s.indexOf(':', firstColon + 1);
|
||||
|
||||
if (firstColon == -1) {
|
||||
throw new java.lang.IllegalArgumentException("No ':' in value [" + s + "]");
|
||||
}
|
||||
try {
|
||||
int hour = Integer.parseInt(s.substring(0, firstColon));
|
||||
if (secondColon == -1) {
|
||||
minute = Integer.parseInt(s.substring(firstColon + 1, s.length()));
|
||||
second = 0;
|
||||
} else {
|
||||
minute = Integer.parseInt(s.substring(firstColon + 1, secondColon));
|
||||
second = Integer.parseInt(s.substring(secondColon + 1));
|
||||
}
|
||||
|
||||
return new Time(hour, minute, second);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
throw new java.lang.IllegalArgumentException("Number format Error parsing time [" + s + "] "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
import java.sql.Time;
|
||||
|
||||
/**
|
||||
* Parser for TIME types that supports both HH:mm:ss and HH:mm.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public final class TimeStringParser implements StringParser {
|
||||
|
||||
private static final TimeStringParser SHARED = new TimeStringParser();
|
||||
|
||||
/**
|
||||
* Return a shared instance as this is thread safe.
|
||||
*/
|
||||
public static TimeStringParser get() {
|
||||
return SHARED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the String supporting both HH:mm:ss and HH:mm formats.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public Object parse(String value) {
|
||||
if (value == null || value.trim().length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String s = value.trim();
|
||||
int minute;
|
||||
int second;
|
||||
int firstColon = s.indexOf(':');
|
||||
int secondColon = s.indexOf(':', firstColon + 1);
|
||||
|
||||
if (firstColon == -1) {
|
||||
throw new java.lang.IllegalArgumentException("No ':' in value [" + s + "]");
|
||||
}
|
||||
try {
|
||||
int hour = Integer.parseInt(s.substring(0, firstColon));
|
||||
if (secondColon == -1) {
|
||||
minute = Integer.parseInt(s.substring(firstColon + 1, s.length()));
|
||||
second = 0;
|
||||
} else {
|
||||
minute = Integer.parseInt(s.substring(firstColon + 1, secondColon));
|
||||
second = Integer.parseInt(s.substring(secondColon + 1));
|
||||
}
|
||||
|
||||
return new Time(hour, minute, second);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
throw new java.lang.IllegalArgumentException("Number format Error parsing time [" + s + "] "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +1,89 @@
|
||||
package com.avaje.ebean.text.csv;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* Provides callback methods for customisation of CSV processing.
|
||||
* <p>
|
||||
* You can provide your own CsvCallback implementation to customise the CSV
|
||||
* processing. It is expected that the DefaultCsvCallback provides a good base
|
||||
* class that you can extend.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public interface CsvCallback<T> {
|
||||
|
||||
/**
|
||||
* The processing is about to begin.
|
||||
* <p>
|
||||
* Typically the callback will create a transaction, set batch mode, batch
|
||||
* size etc.
|
||||
* </p>
|
||||
*/
|
||||
void begin(EbeanServer server);
|
||||
|
||||
/**
|
||||
* Read the header row.
|
||||
* <p>
|
||||
* This is only called if {@link CsvReader#setHasHeader(boolean,boolean)} has
|
||||
* been set to true.
|
||||
* </p>
|
||||
*
|
||||
* @param line
|
||||
* the header line content.
|
||||
*/
|
||||
void readHeader(String[] line);
|
||||
|
||||
/**
|
||||
* Check that the row should be processed - return true to process the row or
|
||||
* false to ignore the row. Gives ability to handle bad data... empty rows etc
|
||||
* and ignore it rather than fail.
|
||||
*/
|
||||
boolean processLine(int row, String[] line);
|
||||
|
||||
/**
|
||||
* Called for each bean after it has been loaded from the CSV content.
|
||||
* <p>
|
||||
* This allows you to process the bean however you like.
|
||||
* </p>
|
||||
* <p>
|
||||
* When you use a CsvCallback the CsvReader *WILL NOT* create a transaction
|
||||
* and will not save the bean for you. You have complete control and must do
|
||||
* these things yourself (if that is want you want).
|
||||
* </p>
|
||||
*
|
||||
* @param row
|
||||
* the index of the content being processed
|
||||
* @param line
|
||||
* the content that has been used to load the bean
|
||||
* @param bean
|
||||
* the entity bean after it has been loaded from the csv content
|
||||
*/
|
||||
void processBean(int row, String[] line, T bean);
|
||||
|
||||
/**
|
||||
* The processing has ended successfully.
|
||||
* <p>
|
||||
* Typically the callback will commit the transaction.
|
||||
* </p>
|
||||
*/
|
||||
void end(int row);
|
||||
|
||||
/**
|
||||
* The processing has ended due to an error.
|
||||
* <p>
|
||||
* This gives the callback the opportunity to rollback the transaction if one
|
||||
* was created.
|
||||
* </p>
|
||||
*
|
||||
* @param row
|
||||
* the row that the error has occured on
|
||||
* @param e
|
||||
* the error that occured
|
||||
*/
|
||||
void endWithError(int row, Exception e);
|
||||
|
||||
}
|
||||
package com.avaje.ebean.text.csv;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* Provides callback methods for customisation of CSV processing.
|
||||
* <p>
|
||||
* You can provide your own CsvCallback implementation to customise the CSV
|
||||
* processing. It is expected that the DefaultCsvCallback provides a good base
|
||||
* class that you can extend.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public interface CsvCallback<T> {
|
||||
|
||||
/**
|
||||
* The processing is about to begin.
|
||||
* <p>
|
||||
* Typically the callback will create a transaction, set batch mode, batch
|
||||
* size etc.
|
||||
* </p>
|
||||
*/
|
||||
void begin(EbeanServer server);
|
||||
|
||||
/**
|
||||
* Read the header row.
|
||||
* <p>
|
||||
* This is only called if {@link CsvReader#setHasHeader(boolean,boolean)} has
|
||||
* been set to true.
|
||||
* </p>
|
||||
*
|
||||
* @param line
|
||||
* the header line content.
|
||||
*/
|
||||
void readHeader(String[] line);
|
||||
|
||||
/**
|
||||
* Check that the row should be processed - return true to process the row or
|
||||
* false to ignore the row. Gives ability to handle bad data... empty rows etc
|
||||
* and ignore it rather than fail.
|
||||
*/
|
||||
boolean processLine(int row, String[] line);
|
||||
|
||||
/**
|
||||
* Called for each bean after it has been loaded from the CSV content.
|
||||
* <p>
|
||||
* This allows you to process the bean however you like.
|
||||
* </p>
|
||||
* <p>
|
||||
* When you use a CsvCallback the CsvReader *WILL NOT* create a transaction
|
||||
* and will not save the bean for you. You have complete control and must do
|
||||
* these things yourself (if that is want you want).
|
||||
* </p>
|
||||
*
|
||||
* @param row
|
||||
* the index of the content being processed
|
||||
* @param line
|
||||
* the content that has been used to load the bean
|
||||
* @param bean
|
||||
* the entity bean after it has been loaded from the csv content
|
||||
*/
|
||||
void processBean(int row, String[] line, T bean);
|
||||
|
||||
/**
|
||||
* The processing has ended successfully.
|
||||
* <p>
|
||||
* Typically the callback will commit the transaction.
|
||||
* </p>
|
||||
*/
|
||||
void end(int row);
|
||||
|
||||
/**
|
||||
* The processing has ended due to an error.
|
||||
* <p>
|
||||
* This gives the callback the opportunity to rollback the transaction if one
|
||||
* was created.
|
||||
* </p>
|
||||
*
|
||||
* @param row
|
||||
* the row that the error has occured on
|
||||
* @param e
|
||||
* the error that occured
|
||||
*/
|
||||
void endWithError(int row, Exception e);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,173 +1,173 @@
|
||||
package com.avaje.ebean.text.csv;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.avaje.ebean.text.StringParser;
|
||||
|
||||
/**
|
||||
* Reads CSV data turning it into object graphs that you can be saved (inserted)
|
||||
* or processed yourself.
|
||||
*
|
||||
* <p>
|
||||
* This first example doesn't use a {@link CsvCallback} and this means it will
|
||||
* automatically create a transaction, save the customers and commit the
|
||||
* transaction when successful.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* try {
|
||||
* File f = new File("src/test/resources/test1.csv");
|
||||
*
|
||||
* FileReader reader = new FileReader(f);
|
||||
*
|
||||
* CsvReader<Customer> csvReader = Ebean.createCsvReader(Customer.class);
|
||||
*
|
||||
* csvReader.setPersistBatchSize(20);
|
||||
*
|
||||
* csvReader.addProperty("status");
|
||||
* // ignore the next property
|
||||
* csvReader.addIgnore();
|
||||
* csvReader.addProperty("name");
|
||||
* csvReader.addDateTime("anniversary", "dd-MMM-yyyy");
|
||||
* csvReader.addProperty("billingAddress.line1");
|
||||
* csvReader.addProperty("billingAddress.city");
|
||||
*
|
||||
* csvReader.process(reader);
|
||||
*
|
||||
* } catch (Exception e) {
|
||||
* throw new RuntimeException(e);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the entity bean type
|
||||
*/
|
||||
public interface CsvReader<T> {
|
||||
|
||||
/**
|
||||
* Explicitly set the default Locale.
|
||||
*/
|
||||
void setDefaultLocale(Locale defaultLocale);
|
||||
|
||||
/**
|
||||
* Set the default format to use for Time types.
|
||||
*/
|
||||
void setDefaultTimeFormat(String defaultTimeFormat);
|
||||
|
||||
/**
|
||||
* Set the default format to use for Date types.
|
||||
*/
|
||||
void setDefaultDateFormat(String defaultDateFormat);
|
||||
|
||||
/**
|
||||
* Set the default format to use for Timestamp types.
|
||||
*/
|
||||
void setDefaultTimestampFormat(String defaultTimestampFormat);
|
||||
|
||||
/**
|
||||
* Set the batch size for using JDBC statement batching.
|
||||
* <p>
|
||||
* By default this is set to 20 and setting this to 1 will disable the use of
|
||||
* JDBC statement batching.
|
||||
* </p>
|
||||
*/
|
||||
void setPersistBatchSize(int persistBatchSize);
|
||||
|
||||
/**
|
||||
* Set to true if there is a header row that should be ignored.
|
||||
* <p>
|
||||
* If addPropertiesFromHeader is true then all the properties are added using
|
||||
* the default time,date and timestamp formats.
|
||||
* <p>
|
||||
* If you have a mix of dateTime formats you can not use this method and must
|
||||
* add the properties yourself.
|
||||
* </p>
|
||||
*/
|
||||
void setHasHeader(boolean hasHeader, boolean addPropertiesFromHeader);
|
||||
|
||||
/**
|
||||
* Same as setHasHeader(true,true);
|
||||
* <p>
|
||||
* This will use a header to define all the properties to load using the
|
||||
* default formats for time, date and datetime types.
|
||||
* </p>
|
||||
*/
|
||||
void setAddPropertiesFromHeader();
|
||||
|
||||
/**
|
||||
* Same as setHasHeader(true, false);
|
||||
* <p>
|
||||
* This indicates that there is a header but that it should be ignored.
|
||||
* </p>
|
||||
*/
|
||||
void setIgnoreHeader();
|
||||
|
||||
/**
|
||||
* Set the frequency with which a INFO message will be logged showing the
|
||||
* progress of the processing. You might set this to 1000 or 10000 etc.
|
||||
* <p>
|
||||
* If this is not set then no INFO messages will be logged.
|
||||
* </p>
|
||||
*/
|
||||
void setLogInfoFrequency(int logInfoFrequency);
|
||||
|
||||
/**
|
||||
* Ignore the next column of data.
|
||||
*/
|
||||
void addIgnore();
|
||||
|
||||
/**
|
||||
* Define the property which will be loaded from the next column of data.
|
||||
* <p>
|
||||
* This takes into account the data type of the property and handles the
|
||||
* String to object conversion automatically.
|
||||
* </p>
|
||||
*/
|
||||
void addProperty(String propertyName);
|
||||
|
||||
/**
|
||||
* Define the next property and use a custom StringParser to convert the
|
||||
* string content into the appropriate type for the property.
|
||||
*/
|
||||
void addProperty(String propertyName, StringParser parser);
|
||||
|
||||
/**
|
||||
* Add a property with a custom Date/Time/Timestamp format using the default
|
||||
* Locale. This will convert the string into the appropriate java type for the
|
||||
* given property (Date, Calendar, SQL Date, Time, Timestamp, JODA etc).
|
||||
*/
|
||||
void addDateTime(String propertyName, String dateTimeFormat);
|
||||
|
||||
/**
|
||||
* Add a property with a custom Date/Time/Timestamp format. This will convert
|
||||
* the string into the appropriate java type for the given property (Date,
|
||||
* Calendar, SQL Date, Time, Timestamp, JODA etc).
|
||||
*/
|
||||
void addDateTime(String propertyName, String dateTimeFormat, Locale locale);
|
||||
|
||||
/**
|
||||
* Automatically create a transaction if required to process all the CSV
|
||||
* content from the reader.
|
||||
* <p>
|
||||
* This will check for a current transaction. If there is no current
|
||||
* transaction then one is started and will commit (or rollback) at the end of
|
||||
* processing. This will also set the persistBatchSize on the transaction.
|
||||
* </p>
|
||||
*/
|
||||
void process(Reader reader) throws Exception;
|
||||
|
||||
/**
|
||||
* Process the CSV content passing the bean to the CsvCallback after each row.
|
||||
* <p>
|
||||
* This provides you with the ability to modify and process the bean.
|
||||
* </p>
|
||||
* <p>
|
||||
* When using a CsvCallback the reader WILL NOT create a transaction or save
|
||||
* the bean(s) for you. If you want to insert the processed beans you must
|
||||
* create your own transaction and save the bean(s) yourself.
|
||||
* </p>
|
||||
*/
|
||||
void process(Reader reader, CsvCallback<T> callback) throws Exception;
|
||||
|
||||
package com.avaje.ebean.text.csv;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.avaje.ebean.text.StringParser;
|
||||
|
||||
/**
|
||||
* Reads CSV data turning it into object graphs that you can be saved (inserted)
|
||||
* or processed yourself.
|
||||
*
|
||||
* <p>
|
||||
* This first example doesn't use a {@link CsvCallback} and this means it will
|
||||
* automatically create a transaction, save the customers and commit the
|
||||
* transaction when successful.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* try {
|
||||
* File f = new File("src/test/resources/test1.csv");
|
||||
*
|
||||
* FileReader reader = new FileReader(f);
|
||||
*
|
||||
* CsvReader<Customer> csvReader = Ebean.createCsvReader(Customer.class);
|
||||
*
|
||||
* csvReader.setPersistBatchSize(20);
|
||||
*
|
||||
* csvReader.addProperty("status");
|
||||
* // ignore the next property
|
||||
* csvReader.addIgnore();
|
||||
* csvReader.addProperty("name");
|
||||
* csvReader.addDateTime("anniversary", "dd-MMM-yyyy");
|
||||
* csvReader.addProperty("billingAddress.line1");
|
||||
* csvReader.addProperty("billingAddress.city");
|
||||
*
|
||||
* csvReader.process(reader);
|
||||
*
|
||||
* } catch (Exception e) {
|
||||
* throw new RuntimeException(e);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the entity bean type
|
||||
*/
|
||||
public interface CsvReader<T> {
|
||||
|
||||
/**
|
||||
* Explicitly set the default Locale.
|
||||
*/
|
||||
void setDefaultLocale(Locale defaultLocale);
|
||||
|
||||
/**
|
||||
* Set the default format to use for Time types.
|
||||
*/
|
||||
void setDefaultTimeFormat(String defaultTimeFormat);
|
||||
|
||||
/**
|
||||
* Set the default format to use for Date types.
|
||||
*/
|
||||
void setDefaultDateFormat(String defaultDateFormat);
|
||||
|
||||
/**
|
||||
* Set the default format to use for Timestamp types.
|
||||
*/
|
||||
void setDefaultTimestampFormat(String defaultTimestampFormat);
|
||||
|
||||
/**
|
||||
* Set the batch size for using JDBC statement batching.
|
||||
* <p>
|
||||
* By default this is set to 20 and setting this to 1 will disable the use of
|
||||
* JDBC statement batching.
|
||||
* </p>
|
||||
*/
|
||||
void setPersistBatchSize(int persistBatchSize);
|
||||
|
||||
/**
|
||||
* Set to true if there is a header row that should be ignored.
|
||||
* <p>
|
||||
* If addPropertiesFromHeader is true then all the properties are added using
|
||||
* the default time,date and timestamp formats.
|
||||
* <p>
|
||||
* If you have a mix of dateTime formats you can not use this method and must
|
||||
* add the properties yourself.
|
||||
* </p>
|
||||
*/
|
||||
void setHasHeader(boolean hasHeader, boolean addPropertiesFromHeader);
|
||||
|
||||
/**
|
||||
* Same as setHasHeader(true,true);
|
||||
* <p>
|
||||
* This will use a header to define all the properties to load using the
|
||||
* default formats for time, date and datetime types.
|
||||
* </p>
|
||||
*/
|
||||
void setAddPropertiesFromHeader();
|
||||
|
||||
/**
|
||||
* Same as setHasHeader(true, false);
|
||||
* <p>
|
||||
* This indicates that there is a header but that it should be ignored.
|
||||
* </p>
|
||||
*/
|
||||
void setIgnoreHeader();
|
||||
|
||||
/**
|
||||
* Set the frequency with which a INFO message will be logged showing the
|
||||
* progress of the processing. You might set this to 1000 or 10000 etc.
|
||||
* <p>
|
||||
* If this is not set then no INFO messages will be logged.
|
||||
* </p>
|
||||
*/
|
||||
void setLogInfoFrequency(int logInfoFrequency);
|
||||
|
||||
/**
|
||||
* Ignore the next column of data.
|
||||
*/
|
||||
void addIgnore();
|
||||
|
||||
/**
|
||||
* Define the property which will be loaded from the next column of data.
|
||||
* <p>
|
||||
* This takes into account the data type of the property and handles the
|
||||
* String to object conversion automatically.
|
||||
* </p>
|
||||
*/
|
||||
void addProperty(String propertyName);
|
||||
|
||||
/**
|
||||
* Define the next property and use a custom StringParser to convert the
|
||||
* string content into the appropriate type for the property.
|
||||
*/
|
||||
void addProperty(String propertyName, StringParser parser);
|
||||
|
||||
/**
|
||||
* Add a property with a custom Date/Time/Timestamp format using the default
|
||||
* Locale. This will convert the string into the appropriate java type for the
|
||||
* given property (Date, Calendar, SQL Date, Time, Timestamp, JODA etc).
|
||||
*/
|
||||
void addDateTime(String propertyName, String dateTimeFormat);
|
||||
|
||||
/**
|
||||
* Add a property with a custom Date/Time/Timestamp format. This will convert
|
||||
* the string into the appropriate java type for the given property (Date,
|
||||
* Calendar, SQL Date, Time, Timestamp, JODA etc).
|
||||
*/
|
||||
void addDateTime(String propertyName, String dateTimeFormat, Locale locale);
|
||||
|
||||
/**
|
||||
* Automatically create a transaction if required to process all the CSV
|
||||
* content from the reader.
|
||||
* <p>
|
||||
* This will check for a current transaction. If there is no current
|
||||
* transaction then one is started and will commit (or rollback) at the end of
|
||||
* processing. This will also set the persistBatchSize on the transaction.
|
||||
* </p>
|
||||
*/
|
||||
void process(Reader reader) throws Exception;
|
||||
|
||||
/**
|
||||
* Process the CSV content passing the bean to the CsvCallback after each row.
|
||||
* <p>
|
||||
* This provides you with the ability to modify and process the bean.
|
||||
* </p>
|
||||
* <p>
|
||||
* When using a CsvCallback the reader WILL NOT create a transaction or save
|
||||
* the bean(s) for you. If you want to insert the processed beans you must
|
||||
* create your own transaction and save the bean(s) yourself.
|
||||
* </p>
|
||||
*/
|
||||
void process(Reader reader, CsvCallback<T> callback) throws Exception;
|
||||
|
||||
}
|
||||
@@ -1,204 +1,204 @@
|
||||
package com.avaje.ebean.text.csv;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Provides the default implementation of CsvCallback.
|
||||
* <p>
|
||||
* This handles transaction creation (if no current transaction existed) and
|
||||
* transaction commit or rollback on error.
|
||||
* </p>
|
||||
* <p>
|
||||
* For customising the processing you can extend this object and override the
|
||||
* appropriate methods.
|
||||
* </p>
|
||||
*
|
||||
* @author rob
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class DefaultCsvCallback<T> implements CsvCallback<T> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultCsvCallback.class);
|
||||
|
||||
/**
|
||||
* The transaction to use (if not using CsvCallback).
|
||||
*/
|
||||
protected Transaction transaction;
|
||||
|
||||
/**
|
||||
* Flag set when we created the transaction.
|
||||
*/
|
||||
protected boolean createdTransaction;
|
||||
|
||||
/**
|
||||
* The EbeanServer used to save the beans.
|
||||
*/
|
||||
protected EbeanServer server;
|
||||
|
||||
/**
|
||||
* Used to log a message to indicate progress through large files.
|
||||
*/
|
||||
protected int logInfoFrequency;
|
||||
|
||||
/**
|
||||
* The batch size used when saving the beans.
|
||||
*/
|
||||
protected int persistBatchSize;
|
||||
|
||||
/**
|
||||
* The time the process started.
|
||||
*/
|
||||
protected long startTime;
|
||||
|
||||
/**
|
||||
* The execution time of the process.
|
||||
*/
|
||||
protected long exeTime;
|
||||
|
||||
/**
|
||||
* Construct with a default batch size of 30 and logging info messages every
|
||||
* 1000 rows.
|
||||
*/
|
||||
public DefaultCsvCallback() {
|
||||
this(30, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with explicit batch size and logging info frequency.
|
||||
*/
|
||||
public DefaultCsvCallback(int persistBatchSize, int logInfoFrequency) {
|
||||
|
||||
this.persistBatchSize = persistBatchSize;
|
||||
this.logInfoFrequency = logInfoFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if required.
|
||||
*/
|
||||
public void begin(EbeanServer server) {
|
||||
this.server = server;
|
||||
this.startTime = System.currentTimeMillis();
|
||||
|
||||
initTransactionIfRequired();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to read the heading line.
|
||||
* <p>
|
||||
* This is only called if {@link CsvReader#setHasHeader(boolean,boolean)} is
|
||||
* set to true.
|
||||
* </p>
|
||||
* <p>
|
||||
* By default this does nothing (effectively ignoring the heading).
|
||||
* </p>
|
||||
*/
|
||||
public void readHeader(String[] line) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the content is valid and return false if the row should be
|
||||
* ignored.
|
||||
* <p>
|
||||
* By default this just returns true.
|
||||
* </p>
|
||||
* <p>
|
||||
* Override this to add custom validation logic returning false if you want
|
||||
* the row to be ignored. For example, if all the content is empty return
|
||||
* false to ignore the row (rather than having the processing fail with some
|
||||
* error).
|
||||
* </p>
|
||||
*/
|
||||
public boolean processLine(int row, String[] line) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will save the bean.
|
||||
* <p>
|
||||
* Override this method to customise the bean (set additional properties etc)
|
||||
* or to control the saving of other related beans (when you can't/don't want
|
||||
* to use Cascade.PERSIST etc).
|
||||
* </p>
|
||||
*/
|
||||
public void processBean(int row, String[] line, T bean) {
|
||||
|
||||
// assumes single bean or Cascade.PERSIST will save any
|
||||
// related beans (e.g. customer -> customer.billingAddress
|
||||
server.save(bean, transaction);
|
||||
|
||||
if (logInfoFrequency > 0 && (row % logInfoFrequency == 0)) {
|
||||
logger.info("processed " + row + " rows");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the transaction if one was created.
|
||||
*/
|
||||
public void end(int row) {
|
||||
|
||||
commitTransactionIfCreated();
|
||||
|
||||
exeTime = System.currentTimeMillis() - startTime;
|
||||
logger.info("Csv finished, rows[" + row + "] exeMillis[" + exeTime + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if one was created.
|
||||
*/
|
||||
public void endWithError(int row, Exception e) {
|
||||
rollbackTransactionIfCreated(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if one is not already active and set its batch mode
|
||||
* and batch size.
|
||||
*/
|
||||
protected void initTransactionIfRequired() {
|
||||
|
||||
transaction = server.currentTransaction();
|
||||
if (transaction == null || !transaction.isActive()) {
|
||||
|
||||
transaction = server.beginTransaction();
|
||||
createdTransaction = true;
|
||||
if (persistBatchSize > 1) {
|
||||
logger.info("Creating transaction, batchSize[" + persistBatchSize + "]");
|
||||
transaction.setBatchMode(true);
|
||||
transaction.setBatchSize(persistBatchSize);
|
||||
|
||||
} else {
|
||||
// explicitly turn off JDBC batching in case
|
||||
// is has been turned on globally
|
||||
transaction.setBatchMode(false);
|
||||
logger.info("Creating transaction with no JDBC batching");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we created a transaction commit it. We have successfully processed all
|
||||
* the rows.
|
||||
*/
|
||||
protected void commitTransactionIfCreated() {
|
||||
if (createdTransaction) {
|
||||
transaction.commit();
|
||||
logger.info("Committed transaction");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if we where not successful in processing all the
|
||||
* rows.
|
||||
*/
|
||||
protected void rollbackTransactionIfCreated(Throwable e) {
|
||||
if (createdTransaction) {
|
||||
transaction.rollback(e);
|
||||
logger.info("Rolled back transaction");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.text.csv;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Provides the default implementation of CsvCallback.
|
||||
* <p>
|
||||
* This handles transaction creation (if no current transaction existed) and
|
||||
* transaction commit or rollback on error.
|
||||
* </p>
|
||||
* <p>
|
||||
* For customising the processing you can extend this object and override the
|
||||
* appropriate methods.
|
||||
* </p>
|
||||
*
|
||||
* @author rob
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class DefaultCsvCallback<T> implements CsvCallback<T> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultCsvCallback.class);
|
||||
|
||||
/**
|
||||
* The transaction to use (if not using CsvCallback).
|
||||
*/
|
||||
protected Transaction transaction;
|
||||
|
||||
/**
|
||||
* Flag set when we created the transaction.
|
||||
*/
|
||||
protected boolean createdTransaction;
|
||||
|
||||
/**
|
||||
* The EbeanServer used to save the beans.
|
||||
*/
|
||||
protected EbeanServer server;
|
||||
|
||||
/**
|
||||
* Used to log a message to indicate progress through large files.
|
||||
*/
|
||||
protected int logInfoFrequency;
|
||||
|
||||
/**
|
||||
* The batch size used when saving the beans.
|
||||
*/
|
||||
protected int persistBatchSize;
|
||||
|
||||
/**
|
||||
* The time the process started.
|
||||
*/
|
||||
protected long startTime;
|
||||
|
||||
/**
|
||||
* The execution time of the process.
|
||||
*/
|
||||
protected long exeTime;
|
||||
|
||||
/**
|
||||
* Construct with a default batch size of 30 and logging info messages every
|
||||
* 1000 rows.
|
||||
*/
|
||||
public DefaultCsvCallback() {
|
||||
this(30, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with explicit batch size and logging info frequency.
|
||||
*/
|
||||
public DefaultCsvCallback(int persistBatchSize, int logInfoFrequency) {
|
||||
|
||||
this.persistBatchSize = persistBatchSize;
|
||||
this.logInfoFrequency = logInfoFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if required.
|
||||
*/
|
||||
public void begin(EbeanServer server) {
|
||||
this.server = server;
|
||||
this.startTime = System.currentTimeMillis();
|
||||
|
||||
initTransactionIfRequired();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to read the heading line.
|
||||
* <p>
|
||||
* This is only called if {@link CsvReader#setHasHeader(boolean,boolean)} is
|
||||
* set to true.
|
||||
* </p>
|
||||
* <p>
|
||||
* By default this does nothing (effectively ignoring the heading).
|
||||
* </p>
|
||||
*/
|
||||
public void readHeader(String[] line) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the content is valid and return false if the row should be
|
||||
* ignored.
|
||||
* <p>
|
||||
* By default this just returns true.
|
||||
* </p>
|
||||
* <p>
|
||||
* Override this to add custom validation logic returning false if you want
|
||||
* the row to be ignored. For example, if all the content is empty return
|
||||
* false to ignore the row (rather than having the processing fail with some
|
||||
* error).
|
||||
* </p>
|
||||
*/
|
||||
public boolean processLine(int row, String[] line) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will save the bean.
|
||||
* <p>
|
||||
* Override this method to customise the bean (set additional properties etc)
|
||||
* or to control the saving of other related beans (when you can't/don't want
|
||||
* to use Cascade.PERSIST etc).
|
||||
* </p>
|
||||
*/
|
||||
public void processBean(int row, String[] line, T bean) {
|
||||
|
||||
// assumes single bean or Cascade.PERSIST will save any
|
||||
// related beans (e.g. customer -> customer.billingAddress
|
||||
server.save(bean, transaction);
|
||||
|
||||
if (logInfoFrequency > 0 && (row % logInfoFrequency == 0)) {
|
||||
logger.info("processed " + row + " rows");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the transaction if one was created.
|
||||
*/
|
||||
public void end(int row) {
|
||||
|
||||
commitTransactionIfCreated();
|
||||
|
||||
exeTime = System.currentTimeMillis() - startTime;
|
||||
logger.info("Csv finished, rows[" + row + "] exeMillis[" + exeTime + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if one was created.
|
||||
*/
|
||||
public void endWithError(int row, Exception e) {
|
||||
rollbackTransactionIfCreated(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if one is not already active and set its batch mode
|
||||
* and batch size.
|
||||
*/
|
||||
protected void initTransactionIfRequired() {
|
||||
|
||||
transaction = server.currentTransaction();
|
||||
if (transaction == null || !transaction.isActive()) {
|
||||
|
||||
transaction = server.beginTransaction();
|
||||
createdTransaction = true;
|
||||
if (persistBatchSize > 1) {
|
||||
logger.info("Creating transaction, batchSize[" + persistBatchSize + "]");
|
||||
transaction.setBatchMode(true);
|
||||
transaction.setBatchSize(persistBatchSize);
|
||||
|
||||
} else {
|
||||
// explicitly turn off JDBC batching in case
|
||||
// is has been turned on globally
|
||||
transaction.setBatchMode(false);
|
||||
logger.info("Creating transaction with no JDBC batching");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we created a transaction commit it. We have successfully processed all
|
||||
* the rows.
|
||||
*/
|
||||
protected void commitTransactionIfCreated() {
|
||||
if (createdTransaction) {
|
||||
transaction.commit();
|
||||
logger.info("Committed transaction");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if we where not successful in processing all the
|
||||
* rows.
|
||||
*/
|
||||
protected void rollbackTransactionIfCreated(Throwable e) {
|
||||
if (createdTransaction) {
|
||||
transaction.rollback(e);
|
||||
logger.info("Rolled back transaction");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,166 +1,166 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Converts objects to and from JSON format.
|
||||
*/
|
||||
public interface JsonContext {
|
||||
|
||||
/**
|
||||
* Convert json string input into a Bean of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> T toBean(Class<T> rootType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json reader input into a Bean of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> T toBean(Class<T> rootType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json parser input into a Bean of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> T toBean(Class<T> cls, JsonParser parser) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json string input into a list of beans of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> List<T> toList(Class<T> rootType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json reader input into a list of beans of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> List<T> toList(Class<T> rootType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json parser input into a list of beans of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> List<T> toList(Class<T> cls, JsonParser src) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Use the genericType to determine if this should be converted into a List or
|
||||
* bean.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
Object toObject(Type genericType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Use the genericType to determine if this should be converted into a List or
|
||||
* bean.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
Object toObject(Type genericType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Use the genericType to determine if this should be converted into a List or
|
||||
* bean.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
Object toObject(Type genericType, JsonParser jsonParser) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return the bean or collection as JSON string.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
String toJson(Object value) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection in JSON format to the writer.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
void toJson(Object value, Writer writer) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection to the JsonGenerator.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
void toJson(Object value, JsonGenerator generator) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return the bean or collection as JSON string using PathProperties.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
String toJson(Object value, PathProperties pathProperties) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection as json to the writer using the PathProperties.
|
||||
*/
|
||||
void toJson(Object value, Writer writer, PathProperties pathProperties) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection to the JsonGenerator using the PathProperties.
|
||||
*/
|
||||
void toJson(Object value, JsonGenerator generator, PathProperties pathProperties) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
* Write json to the JsonGenerator using the JsonWriteOptions.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
void toJson(Object value, JsonGenerator generator, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
* With additional options.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
* @deprecated
|
||||
*/
|
||||
void toJson(Object value, Writer writer, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
* Convert a bean or collection to json string.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
* @deprecated
|
||||
*/
|
||||
String toJson(Object value, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return true if the type is known as an Entity bean or a List Set or
|
||||
* Map of entity beans.
|
||||
*/
|
||||
boolean isSupportedType(Type genericType);
|
||||
|
||||
/**
|
||||
* Create and return a new JsonGenerator for the given writer.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
JsonGenerator createGenerator(Writer writer) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Create and return a new JsonParser for the given reader.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
JsonParser createParser(Reader reader) throws JsonIOException;
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Converts objects to and from JSON format.
|
||||
*/
|
||||
public interface JsonContext {
|
||||
|
||||
/**
|
||||
* Convert json string input into a Bean of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> T toBean(Class<T> rootType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json reader input into a Bean of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> T toBean(Class<T> rootType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json parser input into a Bean of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> T toBean(Class<T> cls, JsonParser parser) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json string input into a list of beans of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> List<T> toList(Class<T> rootType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json reader input into a list of beans of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> List<T> toList(Class<T> rootType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json parser input into a list of beans of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
<T> List<T> toList(Class<T> cls, JsonParser src) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Use the genericType to determine if this should be converted into a List or
|
||||
* bean.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
Object toObject(Type genericType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Use the genericType to determine if this should be converted into a List or
|
||||
* bean.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
Object toObject(Type genericType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Use the genericType to determine if this should be converted into a List or
|
||||
* bean.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
Object toObject(Type genericType, JsonParser jsonParser) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return the bean or collection as JSON string.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
String toJson(Object value) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection in JSON format to the writer.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
void toJson(Object value, Writer writer) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection to the JsonGenerator.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
void toJson(Object value, JsonGenerator generator) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return the bean or collection as JSON string using PathProperties.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
String toJson(Object value, PathProperties pathProperties) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection as json to the writer using the PathProperties.
|
||||
*/
|
||||
void toJson(Object value, Writer writer, PathProperties pathProperties) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection to the JsonGenerator using the PathProperties.
|
||||
*/
|
||||
void toJson(Object value, JsonGenerator generator, PathProperties pathProperties) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
* Write json to the JsonGenerator using the JsonWriteOptions.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
void toJson(Object value, JsonGenerator generator, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
* With additional options.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
* @deprecated
|
||||
*/
|
||||
void toJson(Object value, Writer writer, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
* Convert a bean or collection to json string.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
* @deprecated
|
||||
*/
|
||||
String toJson(Object value, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return true if the type is known as an Entity bean or a List Set or
|
||||
* Map of entity beans.
|
||||
*/
|
||||
boolean isSupportedType(Type genericType);
|
||||
|
||||
/**
|
||||
* Create and return a new JsonGenerator for the given writer.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
JsonGenerator createGenerator(Writer writer) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Create and return a new JsonParser for the given reader.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
JsonParser createParser(Reader reader) throws JsonIOException;
|
||||
}
|
||||
@@ -1,54 +1,54 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of just using PathProperties.
|
||||
*
|
||||
* Provides options for customising the JSON write process.
|
||||
* <p>
|
||||
* You can explicitly state which properties to include in the JSON output for
|
||||
* the root level and each path.
|
||||
* </p>
|
||||
* @deprecated
|
||||
*/
|
||||
public class JsonWriteOptions {
|
||||
|
||||
protected PathProperties pathProperties;
|
||||
|
||||
/**
|
||||
* Parse and return a PathProperties from nested string format like
|
||||
* (a,b,c(d,e),f(g)) where "c" is a path containing "d" and "e" and "f" is a
|
||||
* path containing "g" and the root path contains "a","b","c" and "f".
|
||||
*
|
||||
* @see com.avaje.ebean.text.PathProperties#parse(String)
|
||||
*/
|
||||
public static JsonWriteOptions parsePath(String pathProperties) {
|
||||
|
||||
return pathProperties(PathProperties.parse(pathProperties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct JsonWriteOptions with the given pathProperties.
|
||||
*/
|
||||
public static JsonWriteOptions pathProperties(PathProperties pathProperties) {
|
||||
JsonWriteOptions o = new JsonWriteOptions();
|
||||
o.setPathProperties(pathProperties);
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Map of properties to include by path.
|
||||
*/
|
||||
public void setPathProperties(PathProperties pathProperties) {
|
||||
this.pathProperties = pathProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties to include by path.
|
||||
*/
|
||||
public PathProperties getPathProperties() {
|
||||
return pathProperties;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of just using PathProperties.
|
||||
*
|
||||
* Provides options for customising the JSON write process.
|
||||
* <p>
|
||||
* You can explicitly state which properties to include in the JSON output for
|
||||
* the root level and each path.
|
||||
* </p>
|
||||
* @deprecated
|
||||
*/
|
||||
public class JsonWriteOptions {
|
||||
|
||||
protected PathProperties pathProperties;
|
||||
|
||||
/**
|
||||
* Parse and return a PathProperties from nested string format like
|
||||
* (a,b,c(d,e),f(g)) where "c" is a path containing "d" and "e" and "f" is a
|
||||
* path containing "g" and the root path contains "a","b","c" and "f".
|
||||
*
|
||||
* @see com.avaje.ebean.text.PathProperties#parse(String)
|
||||
*/
|
||||
public static JsonWriteOptions parsePath(String pathProperties) {
|
||||
|
||||
return pathProperties(PathProperties.parse(pathProperties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct JsonWriteOptions with the given pathProperties.
|
||||
*/
|
||||
public static JsonWriteOptions pathProperties(PathProperties pathProperties) {
|
||||
JsonWriteOptions o = new JsonWriteOptions();
|
||||
o.setPathProperties(pathProperties);
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Map of properties to include by path.
|
||||
*/
|
||||
public void setPathProperties(PathProperties pathProperties) {
|
||||
this.pathProperties = pathProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties to include by path.
|
||||
*/
|
||||
public PathProperties getPathProperties() {
|
||||
return pathProperties;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
package com.avaje.ebean.util;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Helper to find classes taking into account the context class loader.
|
||||
*/
|
||||
public class ClassUtil {
|
||||
|
||||
/**
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public static Object newInstance(String className) {
|
||||
try {
|
||||
Class<?> cls = Class.forName(className);
|
||||
return cls.newInstance();
|
||||
} catch (Exception e) {
|
||||
String msg = "Error constructing " + className;
|
||||
throw new IllegalArgumentException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the raw type for the 2nd generic parameter for a subclass.
|
||||
*/
|
||||
public static Class<?> getSecondArgumentType(Class<?> subclass) {
|
||||
Type[] typeArguments = getSuperclassTypeParameter(subclass);
|
||||
if (typeArguments.length != 2) {
|
||||
throw new IllegalArgumentException("Expected type with 2 generic argument types but got "
|
||||
+ typeArguments.length + " - " + Arrays.toString(typeArguments));
|
||||
}
|
||||
|
||||
return getRawType(typeArguments[1]);
|
||||
}
|
||||
|
||||
static Type[] getSuperclassTypeParameter(Class<?> subclass) {
|
||||
Type superclass = subclass.getGenericSuperclass();
|
||||
if (superclass instanceof Class) {
|
||||
throw new RuntimeException("Missing generics type parameters on subclass " + subclass);
|
||||
}
|
||||
return ((ParameterizedType) superclass).getActualTypeArguments();
|
||||
}
|
||||
|
||||
private static Class<?> getRawType(Type type) {
|
||||
|
||||
if (type instanceof Class<?>) {
|
||||
return (Class<?>) type;
|
||||
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
Type rawType = parameterizedType.getRawType();
|
||||
if (rawType instanceof Class<?>) {
|
||||
return (Class<?>) rawType;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Unable to obtain raw class type from " + type);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.util;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Helper to find classes taking into account the context class loader.
|
||||
*/
|
||||
public class ClassUtil {
|
||||
|
||||
/**
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public static Object newInstance(String className) {
|
||||
try {
|
||||
Class<?> cls = Class.forName(className);
|
||||
return cls.newInstance();
|
||||
} catch (Exception e) {
|
||||
String msg = "Error constructing " + className;
|
||||
throw new IllegalArgumentException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the raw type for the 2nd generic parameter for a subclass.
|
||||
*/
|
||||
public static Class<?> getSecondArgumentType(Class<?> subclass) {
|
||||
Type[] typeArguments = getSuperclassTypeParameter(subclass);
|
||||
if (typeArguments.length != 2) {
|
||||
throw new IllegalArgumentException("Expected type with 2 generic argument types but got "
|
||||
+ typeArguments.length + " - " + Arrays.toString(typeArguments));
|
||||
}
|
||||
|
||||
return getRawType(typeArguments[1]);
|
||||
}
|
||||
|
||||
static Type[] getSuperclassTypeParameter(Class<?> subclass) {
|
||||
Type superclass = subclass.getGenericSuperclass();
|
||||
if (superclass instanceof Class) {
|
||||
throw new RuntimeException("Missing generics type parameters on subclass " + subclass);
|
||||
}
|
||||
return ((ParameterizedType) superclass).getActualTypeArguments();
|
||||
}
|
||||
|
||||
private static Class<?> getRawType(Type type) {
|
||||
|
||||
if (type instanceof Class<?>) {
|
||||
return (Class<?>) type;
|
||||
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
Type rawType = parameterizedType.getRawType();
|
||||
if (rawType instanceof Class<?>) {
|
||||
return (Class<?>) rawType;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Unable to obtain raw class type from " + type);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user