No effective change - change newline char

This commit is contained in:
rbygrave
2015-05-09 01:01:45 +12:00
parent f306672c6c
commit 27a0e93fda
13 changed files with 1852 additions and 1852 deletions
@@ -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(&quot;src/test/resources/test1.csv&quot;);
*
* FileReader reader = new FileReader(f);
*
* CsvReader&lt;Customer&gt; csvReader = Ebean.createCsvReader(Customer.class);
*
* csvReader.setPersistBatchSize(20);
*
* csvReader.addProperty(&quot;status&quot;);
* // ignore the next property
* csvReader.addIgnore();
* csvReader.addProperty(&quot;name&quot;);
* csvReader.addDateTime(&quot;anniversary&quot;, &quot;dd-MMM-yyyy&quot;);
* csvReader.addProperty(&quot;billingAddress.line1&quot;);
* csvReader.addProperty(&quot;billingAddress.city&quot;);
*
* 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(&quot;src/test/resources/test1.csv&quot;);
*
* FileReader reader = new FileReader(f);
*
* CsvReader&lt;Customer&gt; csvReader = Ebean.createCsvReader(Customer.class);
*
* csvReader.setPersistBatchSize(20);
*
* csvReader.addProperty(&quot;status&quot;);
* // ignore the next property
* csvReader.addIgnore();
* csvReader.addProperty(&quot;name&quot;);
* csvReader.addDateTime(&quot;anniversary&quot;, &quot;dd-MMM-yyyy&quot;);
* csvReader.addProperty(&quot;billingAddress.line1&quot;);
* csvReader.addProperty(&quot;billingAddress.city&quot;);
*
* 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