Subversion Repositories bacoAlunos

Compare Revisions

Ignore whitespace Rev 1969 → Rev 1973

/branches/grupo4/impl/conf/berserk/sd.xml
4048,6 → 4048,20
</filterChains>
</service>
 
<service>
<name>CourseReportSave</name>
<implementationClass>pt.estgp.estgweb.services.courses.CourseReportServices</implementationClass>
<description>
@reportCourseDocumento faz save de um documento alterado
</description>
<isTransactional>true</isTransactional>
<defaultMethod>saveCourseReport</defaultMethod>
<filterChains>
<chain name="Logger"/>
<chain name="Session"/>
</filterChains>
</service>
 
 
 
</serviceDefinitions>
/branches/grupo4/impl/src/java/pt/estgp/estgweb/services/courses/CourseReportServices.java
60,8 → 60,8
* @param courseCode
* @param year
* @return
* @throws IOException
* @throws JSONException
* @throws java.io.IOException
* @throws org.json.JSONException
*/
public CourseReportDocument createNewCourseReportDocument(String courseCode,String year) throws IOException, JSONException
{
304,8 → 304,8
* @param courseCode
* @param year
* @return UnitsDtpTable
* @throws IOException
* @throws JSONException
* @throws java.io.IOException
* @throws org.json.JSONException
*/
public UnitsDtpTable updateDtpStatsTable4Course(CourseReportDocument reportCourseDocument, String courseCode, String year) throws IOException, JSONException
{
358,8 → 358,8
* @param courseCode
* @param year
* @param reportCourseDocument
* @throws JSONException
* @throws IOException
* @throws org.json.JSONException
* @throws java.io.IOException
* @return a list of CourseUnitSection
*/
public List<DocumentSection> updateCleanCourseUnitSections(String courseCode, String year, CourseReportDocument reportCourseDocument) throws JSONException, IOException {
412,10 → 412,9
* @param reportDocumentJson
* @param session
* @return
* @throws IOException
* @throws java.io.IOException
*/
public String generateGlobalLearningResultsChartImg(String reportDocumentJson,
UserSession session) throws IOException {
public String generateGlobalLearningResultsChartImg(String reportDocumentJson,UserSession session) throws IOException {
 
CourseReportDocument reportDocument = CourseReportDocument.fromJson(reportDocumentJson);
LearningResultsSection learningResultsSection = (LearningResultsSection) reportDocument.findDocumentSection(LearningResultsSection.class);
473,8 → 472,8
* @param courseCode
* @param year
* @return
* @throws JSONException
* @throws IOException
* @throws org.json.JSONException
* @throws java.io.IOException
*/
public String loadCourseUnitDtpStats(String courseCode,String year) throws JSONException, IOException {
 
635,18 → 634,21
}
}
 
//save
public String saveCourseReport(String reportDocumentJson,UserSession session){
 
CourseReportDocument reportDocument = CourseReportDocument.fromJson(reportDocumentJson);
 
 
 
return null;
 
}
 
 
 
 
 
 
 
public static void main(String[] args) throws IOException, JSONException {
AbstractDao.getCurrentSession().beginTransaction();
 
/branches/grupo4/impl/src/java/pt/estgp/estgweb/services/courses/CoursesService.java
66,7 → 66,7
* @param id
* @param initUnits
* @return
* @throws ServiceException
* @throws pt.estgp.estgweb.services.expceptions.ServiceException
*/
public CourseView loadCourse(long id, boolean initUnits)
throws ServiceException
96,7 → 96,7
* @param code
* @param initUnits
* @return
* @throws ServiceException
* @throws pt.estgp.estgweb.services.expceptions.ServiceException
*/
 
public CourseView loadCourseByCode(String code, boolean initUnits) throws ServiceException
292,7 → 292,7
* @param userSession
* @param c
* @return
* @throws JAXBException if XML is not weel formed
* @throws javax.xml.bind.JAXBException if XML is not weel formed
*/
private void generateXmlJaxbStudiesPlanVersionFromRepositoryOldPlanStream(UserSession userSession, Course c, boolean forceFichaCurricularUrlSet, String systemUrlForUnitPrograms) throws JAXBException
{
562,7 → 562,7
* @param school
* @param type
* @return
* @throws JSONException
* @throws org.json.JSONException
*/
public JSONObject getActiveCoursesForJsonApi(String school,String type) throws JSONException {
String institutionalCode = null;
611,9 → 611,9
* //TODO REVER
* @param code
* @return
* @throws JSONException
* @throws IOException
* @throws JAXBException
* @throws org.json.JSONException
* @throws java.io.IOException
* @throws javax.xml.bind.JAXBException
*/
public JSONObject getCourseDetailForJsonApi(String code) throws JSONException, IOException, JAXBException {
 
683,7 → 683,7
*
* @param code
* @return
* @throws JSONException
* @throws org.json.JSONException
*/
public String getCourseStudiesPlanXml(String code,String renew) throws JSONException {
 
717,9 → 717,9
* @param systemUrl
* @param setActive
* @return
* @throws IOException
* @throws JSONException
* @throws JAXBException
* @throws java.io.IOException
* @throws org.json.JSONException
* @throws javax.xml.bind.JAXBException
*/
 
public String sincronizeCoursesStudiesPlans(String systemUrl,boolean setActive,UserSession sess) throws IOException, JSONException, JAXBException {
814,8 → 814,8
* @param systemUrl
* @param code
* @param c
* @throws IOException
* @throws JSONException
* @throws java.io.IOException
* @throws org.json.JSONException
*/
private void updateCourseComissionMembersAndCourseInfo(String systemUrl, String code, Course c) throws IOException, JSONException
{
1267,8 → 1267,8
* chama o serviço tier1 UserRoleConfigService.createNewNormalizedRoleService
* @param session
* @return
* @throws IOException
* @throws AccessDeniedException
* @throws java.io.IOException
* @throws pt.estgp.estgweb.filters.exceptions.AccessDeniedException
*/
public CourseDepartmentImpl newDepartmentRolesFromJson(String json,UserSession session) throws IOException, AccessDeniedException {
CourseDepartmentImpl courseDepartment = CourseDepartmentImpl.loadFromJson(json);
/branches/grupo4/impl/src/java/pt/estgp/estgweb/services/courses/coursereport/documentmodel/learningresults/components/GlobalLearningResultsChartImg.java
27,7 → 27,7
*
* @param results
* @return the tmp path for generated chart
* @throws IOException
* @throws java.io.IOException
*/
public FileUploaded generateChart2tmp(UnitsLearningResultsTable results,CourseReportDocument courseReportDocument) throws IOException
{
/branches/grupo4/impl/src/java/pt/estgp/estgweb/services/users/UserRoleConfigService.java
62,7 → 62,7
* @param newRoleStr
* @param session
* @return
* @throws AccessDeniedException
* @throws pt.estgp.estgweb.filters.exceptions.AccessDeniedException
*/
public ReplaceRoleResult createNewNormalizedRoleService(String oldRole,String nomeRole,String newRoleStr,UserSession session) throws AccessDeniedException {
ReplaceRoleResult result;
/branches/grupo4/impl/src/java/pt/estgp/estgweb/web/controllers/SubServlet.java
File deleted
/branches/grupo4/impl/src/java/pt/estgp/estgweb/web/controllers/TesteEngSoftServlet.java
File deleted
/branches/grupo4/impl/src/java/pt/estgp/estgweb/web/controllers/courses/CoursesServicesController.java
2,7 → 2,6
 
import org.apache.struts.action.ActionForm;
import org.json.JSONObject;
import pt.estgp.estgweb.services.courses.coursereport.documentmodel.CourseReportDocument;
import pt.estgp.estgweb.web.controllers.utils.AbstractWidgetAjaxController;
import pt.estgp.estgweb.web.utils.RequestUtils;
import pt.utl.ist.berserk.logic.serviceManager.IServiceManager;
43,18 → 42,5
return new JSONObject(json);
}
 
public JSONObject save(ActionForm form,HttpServletRequest request, HttpServletResponse response) throws Throwable {
 
String courseReportDocument = request.getParameter("report");
 
CourseReportDocument reportDocument = CourseReportDocument.fromJson(courseReportDocument);
 
reportDocument.setCourseName("ASD");
 
 
 
return reportDocument.toJsonObject();
}
 
 
}
/branches/grupo4/impl/src/java/com/owlike/genson/convert/DefaultConverters.java
New file
0,0 → 1,1334
package com.owlike.genson.convert;
 
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
 
import com.owlike.genson.*;
import com.owlike.genson.annotation.*;
import com.owlike.genson.annotation.HandleBeanView;
import com.owlike.genson.reflect.BeanProperty;
import com.owlike.genson.reflect.TypeUtil;
import com.owlike.genson.stream.JsonType;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
import com.owlike.genson.stream.ValueType;
 
import static com.owlike.genson.reflect.TypeUtil.*;
 
/**
* This class contains all default converters and their factories. You can read the source code <a
* href=
* "http://code.google.com/p/genson/source/browse/src/main/java/com/owlike/genson/convert/DefaultConverters.java"
* >here</a> as example on how to implement custom converters and factories.
*
* @author eugen
*/
public final class DefaultConverters {
private DefaultConverters() {
}
 
@HandleClassMetadata
public static class SetConverter<E> extends CollectionConverter<E> {
 
public SetConverter(Class<E> eClass, Converter<E> elementConverter) {
super(eClass, elementConverter);
}
 
@Override
protected Collection<E> create() {
return new HashSet<E>();
}
}
 
@HandleClassMetadata
public static class LinkedListConverter<E> extends CollectionConverter<E> {
 
public LinkedListConverter(Class<E> eClass, Converter<E> elementConverter) {
super(eClass, elementConverter);
}
 
@Override
protected Collection<E> create() {
return new LinkedList<E>();
}
}
 
@HandleClassMetadata
public static class TreeSetConverter<E> extends CollectionConverter<E> {
 
public TreeSetConverter(Class<E> eClass, Converter<E> elementConverter) {
super(eClass, elementConverter);
}
 
@Override
public void serialize(Collection<E> array, ObjectWriter writer, Context ctx) throws Exception {
TreeSet<E> treeSet = (TreeSet<E>) array;
if (treeSet.comparator() != null) {
throw new UnsupportedOperationException("Serialization and deserialization of TreeSet with Comparator is not supported. " +
"You need to implement a custom Converter to handle it.");
}
super.serialize(array, writer, ctx);
}
 
@Override
protected Collection<E> create() {
return new TreeSet<E>();
}
}
 
@HandleClassMetadata
public static class LinkedHashSetConverter<E> extends CollectionConverter<E> {
 
public LinkedHashSetConverter(Class<E> eClass, Converter<E> elementConverter) {
super(eClass, elementConverter);
}
 
@Override
protected Collection<E> create() {
return new LinkedHashSet<E>();
}
}
 
@HandleClassMetadata
public static class ArrayDequeConverter<E> extends CollectionConverter<E> {
 
public ArrayDequeConverter(Class<E> eClass, Converter<E> elementConverter) {
super(eClass, elementConverter);
}
 
@Override
protected Collection<E> create() {
return new ArrayDeque<E>();
}
}
 
@HandleClassMetadata
public static class PriorityQueueConverter<E> extends CollectionConverter<E> {
 
public PriorityQueueConverter(Class<E> eClass, Converter<E> elementConverter) {
super(eClass, elementConverter);
}
 
@Override
public void serialize(Collection<E> array, ObjectWriter writer, Context ctx) throws Exception {
PriorityQueue<E> queue = (PriorityQueue<E>) array;
if (queue.comparator() != null) {
throw new UnsupportedOperationException("Serialization and deserialization of PriorityQueue with Comparator is not supported. " +
"You need to implement a custom Converter to handle it.");
}
super.serialize(array, writer, ctx);
}
 
@Override
protected Collection<E> create() {
return new PriorityQueue<E>();
}
}
 
@HandleClassMetadata
public static class EnumSetConverter<E> extends CollectionConverter<E> {
private final Class<E> eClass;
 
public EnumSetConverter(Class<E> eClass, Converter<E> elementConverter) {
super(eClass, elementConverter);
this.eClass = eClass;
}
 
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
protected Collection<E> create() {
return EnumSet.noneOf((Class) eClass);
}
}
 
@HandleClassMetadata
public static class CollectionConverter<E> implements Converter<Collection<E>> {
 
@SuppressWarnings("unused")
private final Class<E> eClass;
private final Converter<E> elementConverter;
 
public CollectionConverter(Class<E> eClass, Converter<E> elementConverter) {
this.eClass = eClass;
this.elementConverter = elementConverter;
}
 
public Collection<E> deserialize(ObjectReader reader, Context ctx) throws Exception {
reader.beginArray();
Collection<E> col = create();
for (; reader.hasNext(); ) {
reader.next();
E e = elementConverter.deserialize(reader, ctx);
col.add(e);
}
reader.endArray();
return col;
}
 
public void serialize(Collection<E> array, ObjectWriter writer, Context ctx) throws Exception {
writer.beginArray();
for (E e : array) {
elementConverter.serialize(e, writer, ctx);
}
writer.endArray();
}
 
public Converter<E> getElementConverter() {
return elementConverter;
}
 
protected Collection<E> create() {
return new ArrayList<E>();
}
}
 
public final static class SingleValueAsListFactory implements Factory<Converter<Collection<?>>> {
public final static SingleValueAsListFactory instance = new SingleValueAsListFactory();
 
Factory<Converter<Collection<?>>> defaultFactory = CollectionConverterFactory.instance;
 
private SingleValueAsListFactory() {}
 
@Override
public Converter<Collection<?>> create(Type type, Genson genson) {
final CollectionConverter defaultConverter = (CollectionConverter) defaultFactory.create(type, genson);
 
return new Converter<Collection<?>>() {
@Override
public void serialize(Collection object, ObjectWriter writer, Context ctx) throws Exception {
defaultConverter.serialize(object, writer, ctx);
}
 
@Override
public Collection deserialize(ObjectReader reader, Context ctx) throws Exception {
ValueType vt = reader.getValueType();
if (vt != ValueType.ARRAY && vt != ValueType.NULL ) {
Object object = defaultConverter.getElementConverter().deserialize(reader, ctx);
Collection result = defaultConverter.create();
result.add(object);
return result;
} else return defaultConverter.deserialize( reader, ctx );
}
};
}
}
 
public final static class CollectionConverterFactory implements Factory<Converter<Collection<?>>> {
public final static CollectionConverterFactory instance = new CollectionConverterFactory();
 
private CollectionConverterFactory() {
}
 
@SuppressWarnings({"rawtypes", "unchecked"})
public Converter<Collection<?>> create(Type forType, Genson genson) {
Converter<?> elementConverter = genson.provideConverter(TypeUtil.getCollectionType(forType));
 
Class<?> parameterRawClass = TypeUtil.getRawClass(TypeUtil.getCollectionType(forType));
Class<?> rawClass = getRawClass(forType);
 
if (EnumSet.class.isAssignableFrom(rawClass) && parameterRawClass.isEnum())
return new EnumSetConverter(parameterRawClass, elementConverter);
if (LinkedHashSet.class.isAssignableFrom(rawClass))
return new LinkedHashSetConverter(parameterRawClass, elementConverter);
if (TreeSet.class.isAssignableFrom(rawClass))
return new TreeSetConverter(parameterRawClass, elementConverter);
if (Set.class.isAssignableFrom(rawClass))
return new SetConverter(parameterRawClass, elementConverter);
if (LinkedList.class.isAssignableFrom(rawClass))
return new LinkedListConverter(parameterRawClass, elementConverter);
if (ArrayDeque.class.isAssignableFrom(rawClass))
return new ArrayDequeConverter(parameterRawClass, elementConverter);
if (PriorityQueue.class.isAssignableFrom(rawClass))
return new PriorityQueueConverter(parameterRawClass, elementConverter);
 
return new CollectionConverter(parameterRawClass, elementConverter);
}
}
 
@HandleClassMetadata
public static class ArrayConverter<E> implements Converter<Object> {
private final Class<E> eClass;
private final Converter<E> elementConverter;
 
public ArrayConverter(Class<E> eClass, Converter<E> elementConverter) {
this.eClass = eClass;
this.elementConverter = elementConverter;
}
 
public void serialize(Object array, ObjectWriter writer, Context ctx) throws Exception {
writer.beginArray();
int len = Array.getLength(array);
for (int i = 0; i < len; i++) {
@SuppressWarnings("unchecked")
E e = (E) Array.get(array, i);
elementConverter.serialize(e, writer, ctx);
}
writer.endArray();
}
 
public Object deserialize(ObjectReader reader, Context ctx) throws Exception {
reader.beginArray();
int size = 10;
Object array = Array.newInstance(eClass, size);
int idx = 0;
for (; reader.hasNext(); ) {
reader.next();
if (idx >= size) {
size = size * 2 + 1;
array = expandArray(array, idx, size);
}
Array.set(array, idx++, elementConverter.deserialize(reader, ctx));
}
reader.endArray();
if (idx < size) {
array = expandArray(array, idx, idx);
}
return array;
}
 
private Object expandArray(Object array, int len, int size) {
Object tmpArray = Array.newInstance(eClass, size);
System.arraycopy(array, 0, tmpArray, 0, len);
return tmpArray;
}
}
 
@HandleClassMetadata
public final static class ByteArrayConverter implements Converter<byte[]> {
public static final ByteArrayConverter instance = new ByteArrayConverter();
 
private ByteArrayConverter() {
}
 
@Override
public void serialize(byte[] object, ObjectWriter writer, Context ctx) {
writer.writeValue(object);
}
 
@Override
public byte[] deserialize(ObjectReader reader, Context ctx) {
return reader.valueAsByteArray();
}
}
 
@HandleClassMetadata
public static class ByteArrayAsIntArrayConverter implements Converter<byte[]> {
public static final ByteArrayAsIntArrayConverter instance = new ByteArrayAsIntArrayConverter();
 
private ByteArrayAsIntArrayConverter() {
}
 
@Override
public void serialize(byte[] object, ObjectWriter writer, Context ctx) throws Exception {
writer.beginArray();
for (int i = 0; i < object.length; i++) writer.writeValue(object[i]);
writer.endArray();
}
 
@Override
public byte[] deserialize(ObjectReader reader, Context ctx) throws Exception {
byte[] array = new byte[256];
reader.beginArray();
int i;
for (i = 0; reader.hasNext(); i++) {
reader.next();
Operations.expandArray(array, i, 2);
array[i] = (byte) reader.valueAsInt();
}
reader.endArray();
 
return Operations.truncateArray(array, i);
}
}
 
public final static class ArrayConverterFactory implements Factory<Converter<Object>> {
public final static ArrayConverterFactory instance = new ArrayConverterFactory();
 
private ArrayConverterFactory() {
}
 
@SuppressWarnings({"rawtypes", "unchecked"})
public Converter<Object> create(Type forType, Genson genson) {
if (forType instanceof GenericArrayType
|| (forType instanceof Class<?> && ((Class<?>) forType).isArray())) {
if (byte.class.equals(getCollectionType(forType))) {
return (Converter) ByteArrayConverter.instance;
} else {
Converter<?> elementConverter = genson.provideConverter(TypeUtil
.getCollectionType(forType));
return new ArrayConverter(TypeUtil.getRawClass(TypeUtil
.getCollectionType(forType)), elementConverter);
}
}
return null;
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class StringConverter implements Converter<String> {
public final static StringConverter instance = new StringConverter();
 
private StringConverter() {
}
 
public void serialize(String value, ObjectWriter writer, Context ctx) {
writer.writeValue(value);
}
 
public String deserialize(ObjectReader reader, Context ctx) {
return reader.valueAsString();
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class BooleanConverter implements Converter<Boolean> {
public final static BooleanConverter instance = new BooleanConverter();
 
private BooleanConverter() {
}
 
public void serialize(Boolean obj, ObjectWriter writer, Context ctx) {
writer.writeValue(obj.booleanValue());
}
 
public Boolean deserialize(ObjectReader reader, Context ctx) {
return reader.valueAsBoolean();
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class IntegerConverter implements Converter<Integer> {
public final static IntegerConverter instance = new IntegerConverter();
 
private IntegerConverter() {
}
 
public void serialize(Integer obj, ObjectWriter writer, Context ctx) {
writer.writeValue(obj.intValue());
}
 
public Integer deserialize(ObjectReader reader, Context ctx) {
return reader.valueAsInt();
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class LongConverter implements Converter<Long> {
public final static LongConverter instance = new LongConverter();
 
private LongConverter() {
}
 
public Long deserialize(ObjectReader reader, Context ctx) {
return reader.valueAsLong();
}
 
public void serialize(Long obj, ObjectWriter writer, Context ctx) {
writer.writeValue(obj.longValue());
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class ShortConverter implements Converter<Short> {
public final static ShortConverter instance = new ShortConverter();
 
private ShortConverter() {
}
 
public Short deserialize(ObjectReader reader, Context ctx) {
return reader.valueAsShort();
}
 
public void serialize(Short obj, ObjectWriter writer, Context ctx) {
writer.writeValue(obj.shortValue());
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class DoubleConverter implements Converter<Double> {
public final static DoubleConverter instance = new DoubleConverter();
 
private DoubleConverter() {
}
 
public Double deserialize(ObjectReader reader, Context ctx) {
return reader.valueAsDouble();
}
 
public void serialize(Double obj, ObjectWriter writer, Context ctx) {
if (obj.isNaN() || obj.isInfinite()) {
writer.writeUnsafeValue(obj.toString());
} else {
writer.writeValue(obj.doubleValue());
}
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class FloatConverter implements Converter<Float> {
public final static FloatConverter instance = new FloatConverter();
 
private FloatConverter() {
}
 
public Float deserialize(ObjectReader reader, Context ctx) {
return reader.valueAsFloat();
}
 
public void serialize(Float obj, ObjectWriter writer, Context ctx) {
if (obj.isNaN() || obj.isInfinite()) {
writer.writeUnsafeValue(obj.toString());
} else {
writer.writeValue(obj.floatValue());
}
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class NumberConverter implements Converter<Number> {
public final static NumberConverter instance = new NumberConverter();
 
private NumberConverter() {
}
 
public Number deserialize(ObjectReader reader, Context ctx) {
ValueType vt = reader.getValueType();
if (ValueType.INTEGER.equals(vt))
return reader.valueAsInt();
else if (ValueType.DOUBLE.equals(vt))
return reader.valueAsDouble();
else {
String value = reader.valueAsString();
return "".equals(value) ? null : parse(value, vt);
}
}
 
public void serialize(Number obj, ObjectWriter writer, Context ctx) {
if (isSpecialNumber(obj)) writer.writeUnsafeValue(obj.toString()); else writer.writeValue(obj);
}
 
private boolean isSpecialNumber(Number v) {
if (v instanceof Double || v instanceof Float) {
Double num = (Double) v;
return num.isInfinite() || num.isNaN();
} else {
return false;
}
}
 
private Number parse(String value, ValueType valueType) {
try {
if (value.indexOf('.') >= 0) {
return Double.parseDouble(value);
}
long longValue = Long.parseLong(value);
if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
return Integer.valueOf((int) longValue);
}
return Long.parseLong(value);
} catch (NumberFormatException nfe) {
throw new JsonBindingException("Could not convert input value " + value
+ " of type " + valueType.toClass() + " to a Number type.", nfe);
}
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class CharConverter implements Converter<Character> {
public final static CharConverter instance = new CharConverter();
 
private CharConverter() {
}
 
public void serialize(Character obj, ObjectWriter writer, Context ctx) {
writer.writeValue(obj.toString());
}
 
public Character deserialize(ObjectReader reader, Context ctx) {
String str = reader.valueAsString();
if (str.length() > 1) throw new JsonBindingException(
"Could not convert a string with length greater than 1 to a single char."
);
 
return str.charAt(0);
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class ByteConverter implements Converter<Byte> {
public final static ByteConverter instance = new ByteConverter();
 
private ByteConverter() {
}
 
public void serialize(Byte obj, ObjectWriter writer, Context ctx) {
writer.writeValue(obj.byteValue());
}
 
public Byte deserialize(ObjectReader reader, Context ctx) {
return (byte) reader.valueAsInt();
}
}
 
public final static class PrimitiveConverterFactory implements Factory<Converter<?>> {
public final static PrimitiveConverterFactory instance = new PrimitiveConverterFactory();
 
private PrimitiveConverterFactory() {
}
 
public Converter<?> create(Type type, Genson genson) {
Class<?> rawClass = TypeUtil.getRawClass(type);
 
if (rawClass == Boolean.class || rawClass == boolean.class) return BooleanConverter.instance;
if (rawClass == Integer.class || rawClass == int.class) return IntegerConverter.instance;
if (rawClass == Double.class || rawClass == double.class) return DoubleConverter.instance;
if (rawClass == Long.class || rawClass == long.class) return LongConverter.instance;
if (rawClass == Short.class || rawClass == short.class) return ShortConverter.instance;
if (rawClass == Float.class || rawClass == float.class) return FloatConverter.instance;
if (rawClass == Character.class || rawClass == char.class) return CharConverter.instance;
if (rawClass == Byte.class || rawClass == byte.class) return ByteConverter.instance;
 
return null;
}
}
 
@HandleClassMetadata
public static abstract class MapConverter<K, V> implements Converter<Map<K, V>> {
private final Converter<V> valueConverter;
private final KeyAdapter<K> keyAdapter;
 
public MapConverter(KeyAdapter<K> keyAdapter, Converter<V> valueConverter) {
this.keyAdapter = keyAdapter;
this.valueConverter = valueConverter;
}
 
public Map<K, V> deserialize(ObjectReader reader, Context ctx) throws Exception {
reader.beginObject();
Map<K, V> map = create();
for (; reader.hasNext(); ) {
reader.next();
map.put(keyAdapter.adapt(reader.name()), valueConverter.deserialize(reader, ctx));
}
reader.endObject();
return map;
}
 
public void serialize(Map<K, V> obj, ObjectWriter writer, Context ctx) throws Exception {
writer.beginObject();
for (Map.Entry<K, V> entry : obj.entrySet()) {
writer.writeName(keyAdapter.adapt(entry.getKey()));
valueConverter.serialize(entry.getValue(), writer, ctx);
}
writer.endObject();
}
 
protected abstract Map<K, V> create();
}
 
public final static class HashMapConverter<K, V> extends MapConverter<K, V> {
public HashMapConverter(KeyAdapter<K> keyAdapter, Converter<V> valueConverter) {
super(keyAdapter, valueConverter);
}
 
@Override
protected Map<K, V> create() {
return new HashMap<K, V>();
}
}
 
public final static class HashTableConverter<K, V> extends MapConverter<K, V> {
public HashTableConverter(KeyAdapter<K> keyAdapter, Converter<V> valueConverter) {
super(keyAdapter, valueConverter);
}
 
@Override
protected Map<K, V> create() {
return new Hashtable<K, V>();
}
}
 
@SuppressWarnings("rawtypes")
public final static class PropertiesConverter extends MapConverter {
@SuppressWarnings("unchecked")
public PropertiesConverter(KeyAdapter keyAdapter, Converter valueConverter) {
super(keyAdapter, valueConverter);
}
 
@Override
protected Map create() {
return new Properties();
}
}
 
public final static class TreeMapConverter<K, V> extends MapConverter<K, V> {
public TreeMapConverter(KeyAdapter<K> keyAdapter, Converter<V> valueConverter) {
super(keyAdapter, valueConverter);
}
 
@Override
public void serialize(Map<K, V> obj, ObjectWriter writer, Context ctx) throws Exception {
TreeMap<K, V> treeMap = (TreeMap<K, V>) obj;
if (((TreeMap<K, V>) obj).comparator() != null)
throw new UnsupportedOperationException("Serialization and deserialization of TreeMap with Comparator is not supported. " +
"You need to implement a custom Converter to handle it.");
 
super.serialize(obj, writer, ctx);
}
 
@Override
protected Map<K, V> create() {
return new TreeMap<K, V>();
}
}
 
public final static class LinkedHashMapConverter<K, V> extends MapConverter<K, V> {
public LinkedHashMapConverter(KeyAdapter<K> keyAdapter, Converter<V> valueConverter) {
super(keyAdapter, valueConverter);
}
 
@Override
protected Map<K, V> create() {
return new LinkedHashMap<K, V>();
}
}
 
public static abstract class KeyAdapter<K> {
public abstract K adapt(String str);
 
public abstract String adapt(K key);
 
public final static KeyAdapter<Object> runtimeAdapter = new KeyAdapter<Object>() {
@Override
public Object adapt(String str) {
return str;
}
 
@Override
public String adapt(Object key) {
return key.toString();
}
};
 
public final static KeyAdapter<String> strAdapter = new KeyAdapter<String>() {
@Override
public String adapt(String key) {
return key;
}
};
 
public final static KeyAdapter<Short> shortAdapter = new KeyAdapter<Short>() {
@Override
public Short adapt(String str) {
return Short.parseShort(str);
}
 
@Override
public String adapt(Short key) {
return key.toString();
}
};
 
public final static KeyAdapter<Integer> intAdapter = new KeyAdapter<Integer>() {
@Override
public Integer adapt(String str) {
return Integer.parseInt(str);
}
 
@Override
public String adapt(Integer key) {
return key.toString();
}
};
 
public final static KeyAdapter<Long> longAdapter = new KeyAdapter<Long>() {
@Override
public Long adapt(String str) {
return Long.parseLong(str);
}
 
@Override
public String adapt(Long key) {
return key.toString();
}
};
 
public final static KeyAdapter<Float> floatAdapter = new KeyAdapter<Float>() {
@Override
public Float adapt(String str) {
return Float.parseFloat(str);
}
 
@Override
public String adapt(Float key) {
return key.toString();
}
};
 
public final static KeyAdapter<Double> doubleAdapter = new KeyAdapter<Double>() {
@Override
public Double adapt(String str) {
return Double.parseDouble(str);
}
 
@Override
public String adapt(Double key) {
return key.toString();
}
};
}
 
@HandleClassMetadata
public static class ComplexMapConverter<K, V> implements Converter<Map<K, V>> {
private final Converter<K> keyConverter;
private final Converter<V> valueConverter;
 
private ComplexMapConverter(Converter<K> keyConverter, Converter<V> valueConverter) {
super();
this.keyConverter = keyConverter;
this.valueConverter = valueConverter;
}
 
@Override
public void serialize(Map<K, V> object, ObjectWriter writer, Context ctx) throws Exception {
writer.beginArray();
for (Map.Entry<K, V> entry : object.entrySet()) {
writer.beginObject().writeName("key");
keyConverter.serialize(entry.getKey(), writer, ctx);
writer.writeName("value");
valueConverter.serialize(entry.getValue(), writer, ctx);
writer.endObject();
}
writer.endArray();
}
 
@Override
public Map<K, V> deserialize(ObjectReader reader, Context ctx) throws Exception {
Map<K, V> map = new HashMap<K, V>();
reader.beginArray();
while (reader.hasNext()) {
reader.next();
reader.beginObject();
K key = null;
V value = null;
while (reader.hasNext()) {
reader.next();
if ("key".equals(reader.name())) {
key = keyConverter.deserialize(reader, ctx);
} else if ("value".equals(reader.name())) {
value = valueConverter.deserialize(reader, ctx);
}
}
map.put(key, value);
reader.endObject();
}
reader.endArray();
return map;
}
}
 
public final static class MapConverterFactory implements Factory<Converter<? extends Map<?, ?>>> {
public final static MapConverterFactory instance = new MapConverterFactory();
 
private MapConverterFactory() {
}
 
@SuppressWarnings({"rawtypes", "unchecked"})
public Converter<? extends Map<?, ?>> create(Type type, Genson genson) {
// ok this is a fix but not the cleanest one... we make sure it is a parameterized type
// otherwise we search for map impl in its hierarchy
Type expandedType = type;
if (getRawClass(type).getTypeParameters().length == 0) {
expandedType = expandType(lookupGenericType(Map.class, getRawClass(type)), type);
}
 
Type keyType = typeOf(0, expandedType);
Type valueType = typeOf(1, expandedType);
Class<?> keyRawClass = getRawClass(keyType);
KeyAdapter<?> keyAdapter = keyAdapter(keyRawClass);
 
if (keyAdapter != null)
return createConverter(getRawClass(type), keyAdapter, genson.provideConverter(valueType));
else
return new ComplexMapConverter(genson.provideConverter(keyType), genson.provideConverter(valueType));
}
 
public static KeyAdapter<?> keyAdapter(Class<?> keyRawClass) {
if (Object.class.equals(keyRawClass)) return KeyAdapter.runtimeAdapter;
else if (String.class.equals(keyRawClass)) return KeyAdapter.strAdapter;
else if (int.class.equals(keyRawClass) || Integer.class.equals(keyRawClass))
return KeyAdapter.intAdapter;
else if (double.class.equals(keyRawClass) || Double.class.equals(keyRawClass))
return KeyAdapter.doubleAdapter;
else if (long.class.equals(keyRawClass) || Long.class.equals(keyRawClass))
return KeyAdapter.longAdapter;
else if (float.class.equals(keyRawClass) || Float.class.equals(keyRawClass))
return KeyAdapter.floatAdapter;
else if (short.class.equals(keyRawClass) || Short.class.equals(keyRawClass))
return KeyAdapter.shortAdapter;
else return null;
}
 
@SuppressWarnings("unchecked")
private <K, V> MapConverter<K, V> createConverter(Class<?> typeOfMap,
KeyAdapter<K> keyAdapter, Converter<V> valueConverter) {
if (Properties.class.equals(typeOfMap))
return new PropertiesConverter(keyAdapter, valueConverter);
 
if (Hashtable.class.equals(typeOfMap))
return new HashTableConverter<K, V>(keyAdapter, valueConverter);
 
if (TreeMap.class.equals(typeOfMap))
return new TreeMapConverter<K, V>(keyAdapter, valueConverter);
 
if (LinkedHashMap.class.equals(typeOfMap))
return new LinkedHashMapConverter<K, V>(keyAdapter, valueConverter);
 
return new HashMapConverter<K, V>(keyAdapter, valueConverter);
}
}
 
@SuppressWarnings("rawtypes")
public static class DateContextualFactory implements ContextualFactory {
@Override
public Converter create(BeanProperty property, Genson genson) {
JsonDateFormat ann = property.getAnnotation(JsonDateFormat.class);
if (ann != null) {
Locale locale = ann.lang().isEmpty() ? Locale.getDefault() : new Locale(
ann.lang());
DateFormat dateFormat = ann.value() != null && !ann.value().isEmpty() ?
new SimpleDateFormat(ann.value(), locale) : SimpleDateFormat.getInstance();
 
if (Date.class.isAssignableFrom(property.getRawClass()))
return new DateConverter(dateFormat, ann.asTimeInMillis());
if (Calendar.class.isAssignableFrom(property.getRawClass()))
return new CalendarConverter(
new DateConverter(dateFormat, ann.asTimeInMillis()));
}
return null;
}
}
 
@HandleClassMetadata
@HandleBeanView
public static class DateConverter implements Converter<Date> {
private DateFormat dateFormat;
private final boolean asTimeInMillis;
 
public DateConverter() {
this(SimpleDateFormat.getDateTimeInstance(), true);
}
 
public DateConverter(DateFormat dateFormat, boolean asTimeInMillis) {
if (dateFormat == null) dateFormat = SimpleDateFormat.getDateTimeInstance();
this.dateFormat = dateFormat;
this.asTimeInMillis = asTimeInMillis;
}
 
public void serialize(Date obj, ObjectWriter writer, Context ctx) {
if (asTimeInMillis)
writer.writeValue(obj.getTime());
else
writer.writeUnsafeValue(format(obj));
}
 
protected synchronized String format(Date date) {
return dateFormat.format(date);
}
 
public Date deserialize(ObjectReader reader, Context ctx) {
try {
ValueType valueType = reader.getValueType();
if (valueType == ValueType.INTEGER)
return new Date(reader.valueAsLong());
else if (valueType == ValueType.STRING)
return read(reader.valueAsString());
else throw new JsonBindingException(String.format("Can not deserialize type %s to Date, " +
"only numeric and string accepted.", valueType));
} catch (ParseException e) {
throw new JsonBindingException("Could not parse date " + reader.valueAsString(),
e);
}
}
 
protected synchronized Date read(String dateString) throws ParseException {
return dateFormat.parse(dateString);
}
}
 
public final static class UntypedConverterFactory implements Factory<Converter<Object>> {
public final static UntypedConverterFactory instance = new UntypedConverterFactory();
 
private UntypedConverterFactory() {
}
 
public final static class UntypedConverter implements Converter<Object> {
final static UntypedConverter instance = new UntypedConverter();
 
private UntypedConverter() {
}
 
public Object deserialize(ObjectReader reader, Context ctx) {
return ctx.genson.deserialize(GenericType.of(reader.getValueType().toClass()),
reader, ctx);
}
 
public void serialize(Object obj, ObjectWriter writer, Context ctx) {
if (Object.class.equals(obj.getClass()))
throw new UnsupportedOperationException(
"Serialization of type Object is not supported by default serializers.");
ctx.genson.serialize(obj, obj.getClass(), writer, ctx);
}
}
 
public Converter<Object> create(Type type, Genson genson) {
if (TypeUtil.match(type, Object.class, true)) {
return UntypedConverter.instance;
}
return null;
}
}
 
@HandleClassMetadata
@HandleBeanView
public static class EnumConverter<T extends Enum<T>> implements Converter<T> {
private final Class<T> eClass;
private final Map<String, T> deserializationNames;
private final boolean caseSensitive;
 
public EnumConverter(Class<T> eClass, boolean caseSensitive) {
this.eClass = eClass;
this.caseSensitive = caseSensitive;
deserializationNames = new HashMap<String, T>();
for (Field f : eClass.getFields()) {
try {
if (!f.isEnumConstant()) {
continue;
}
String name = caseSensitive ? f.getName(): f.getName().toUpperCase();
deserializationNames.put(name, (T) f.get(null));
} catch (IllegalAccessException e) {
throw new JsonBindingException("Failed to get enum value " + f.getName(), e);
}
}
}
 
public void serialize(T obj, ObjectWriter writer, Context ctx) {
writer.writeUnsafeValue(obj.name());
}
 
public T deserialize(ObjectReader reader, Context ctx) {
String name = caseSensitive ? reader.valueAsString(): reader.valueAsString().toUpperCase();
T value = deserializationNames.get(name);
if (value == null) throw new JsonBindingException("No enum constant " + eClass.getCanonicalName() + "." + name);
return value;
}
}
 
public final static class EnumConverterFactory implements Factory<Converter<? extends Enum<?>>> {
public final static EnumConverterFactory instance = new EnumConverterFactory(true);
public final boolean caseSensitive;
 
public EnumConverterFactory(boolean caseSensitive) {
this.caseSensitive = caseSensitive;
}
 
@SuppressWarnings({"rawtypes", "unchecked"})
public Converter<Enum<?>> create(Type type, Genson genson) {
Class<?> rawClass = TypeUtil.getRawClass(type);
return rawClass.isEnum() || Enum.class.isAssignableFrom(rawClass) ? new EnumConverter(
rawClass, caseSensitive) : null;
}
}
 
@HandleClassMetadata
@HandleBeanView
public static class URLConverter implements Converter<URL> {
public final static URLConverter instance = new URLConverter();
 
private URLConverter() {
}
 
public URL deserialize(ObjectReader reader, Context ctx) {
try {
return new URL(reader.valueAsString());
} catch (MalformedURLException e) {
throw new JsonBindingException("Can not deserializer <" + reader.valueAsString() + "> to URL.");
}
}
 
public void serialize(URL object, ObjectWriter writer, Context ctx) {
writer.writeValue(object.toExternalForm());
}
}
 
@HandleClassMetadata
@HandleBeanView
public static class URIConverter implements Converter<URI> {
public final static URIConverter instance = new URIConverter();
 
private URIConverter() {
}
 
public void serialize(URI object, ObjectWriter writer, Context ctx) {
writer.writeUnsafeValue(object.toString());
}
 
public URI deserialize(ObjectReader reader, Context ctx) {
return URI.create(reader.valueAsString());
}
}
 
@HandleClassMetadata
@HandleBeanView
public static class BigDecimalConverter implements Converter<BigDecimal> {
public final static BigDecimalConverter instance = new BigDecimalConverter();
 
private BigDecimalConverter() {
}
 
@Override
public BigDecimal deserialize(ObjectReader reader, Context ctx) {
return new BigDecimal(reader.valueAsString());
}
 
@Override
public void serialize(BigDecimal object, ObjectWriter writer, Context ctx) {
writer.writeValue(object);
}
}
 
@HandleClassMetadata
@HandleBeanView
public static class BigIntegerConverter implements Converter<BigInteger> {
public final static BigIntegerConverter instance = new BigIntegerConverter();
 
private BigIntegerConverter() {
}
 
@Override
public BigInteger deserialize(ObjectReader reader, Context ctx) {
return new BigInteger(reader.valueAsString());
}
 
@Override
public void serialize(BigInteger object, ObjectWriter writer, Context ctx) {
writer.writeValue(object);
}
}
 
@HandleClassMetadata
@HandleBeanView
public static class TimestampConverter implements Converter<Timestamp> {
public final static TimestampConverter instance = new TimestampConverter();
 
private TimestampConverter() {
}
 
@Override
public Timestamp deserialize(ObjectReader reader, Context ctx) {
return Timestamp.valueOf(reader.valueAsString());
}
 
@Override
public void serialize(Timestamp object, ObjectWriter writer, Context ctx) {
writer.writeValue(object.toString());
}
}
 
@HandleClassMetadata
@HandleBeanView
public static class UUIDConverter implements Converter<UUID> {
public final static UUIDConverter instance = new UUIDConverter();
 
private UUIDConverter() {
}
 
@Override
public void serialize(UUID object, ObjectWriter writer, Context ctx) {
writer.writeValue(object.toString());
}
 
@Override
public UUID deserialize(ObjectReader reader, Context ctx) {
return UUID.fromString(reader.valueAsString());
}
 
}
 
public final static class CalendarConverterFactory implements Factory<Converter<Calendar>> {
private final CalendarConverter calendarConverter;
 
public CalendarConverterFactory(DateConverter dateConverter) {
this.calendarConverter = new CalendarConverter(dateConverter);
}
 
@Override
public Converter<Calendar> create(Type type, Genson genson) {
if (!Calendar.class.isAssignableFrom(TypeUtil.getRawClass(type)))
throw new IllegalStateException(
"CalendarConverterFactory create method can be called only for Calendar type and subtypes.");
return calendarConverter;
}
}
 
@HandleClassMetadata
@HandleBeanView
public static class CalendarConverter implements Converter<Calendar> {
private final DateConverter dateConverter;
 
CalendarConverter(final DateConverter dateConverter) {
this.dateConverter = dateConverter;
}
 
@Override
public void serialize(Calendar object, ObjectWriter writer, Context ctx) {
dateConverter.serialize(object.getTime(), writer, ctx);
}
 
@Override
public Calendar deserialize(ObjectReader reader, Context ctx) {
Calendar cal = null;
if (ValueType.NULL != reader.getValueType()) {
cal = new GregorianCalendar();
cal.setTime(dateConverter.deserialize(reader, ctx));
}
return cal;
}
}
 
@HandleClassMetadata
@HandleBeanView
public final static class FileConverter implements Converter<File> {
public final static FileConverter instance = new FileConverter();
 
private FileConverter() {
}
 
@Override
public void serialize(File object, ObjectWriter writer, Context ctx) {
writer.writeValue(object.getPath());
}
 
@Override
public File deserialize(ObjectReader reader, Context ctx) {
return new File(reader.valueAsString());
}
 
}
 
public final static class PropertyConverterFactory implements ContextualFactory<Object> {
 
@SuppressWarnings("unchecked")
@Override
public Converter<Object> create(BeanProperty property, Genson genson) {
JsonConverter ann = property.getAnnotation(JsonConverter.class);
if (ann != null) {
Type converterExpandedType = expandType(
lookupGenericType(Converter.class, ann.value()), ann.value());
Type converterPropertyType = typeOf(0, converterExpandedType);
 
Class<?> propertyClass = property.getRawClass();
if (propertyClass.isPrimitive()) propertyClass = wrap(propertyClass);
 
// checking type consistency
if (!match(propertyClass, converterPropertyType, false))
throw new ClassCastException("The type defined in " + ann.value().getName()
+ " is not assignale from property " + property.getName()
+ " declared in " + property.getDeclaringClass());
 
try {
Constructor<?> ctr = ann.value().getConstructor();
if (!ctr.isAccessible()) ctr.setAccessible(true);
return (Converter<Object>) ctr.newInstance();
 
// OMG...
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
return null;
}
}
 
public static class WrappedRootValueConverter<T> implements Converter<T> {
private final String inputName;
private final String outputName;
private final Converter<T> delegateConverter;
 
public WrappedRootValueConverter(String inputName, String outputName, Converter<T> delegateConverter) {
this.inputName = inputName;
this.outputName = outputName;
this.delegateConverter = delegateConverter;
}
 
@Override
public void serialize(T object, ObjectWriter writer, Context ctx) throws Exception {
if (writer.enclosingType() == JsonType.EMPTY) {
writer.beginObject().writeName(outputName);
delegateConverter.serialize(object, writer, ctx);
writer.endObject();
}
}
 
@Override
public T deserialize(ObjectReader reader, Context ctx) throws Exception {
T value = null;
if (reader.enclosingType() == JsonType.EMPTY) {
reader.beginObject();
// Lets accept the case where the key is missing
if (reader.hasNext()) {
reader.next();
 
if (!inputName.equalsIgnoreCase(reader.name())) {
throw new JsonBindingException(
String.format(
"Expected key %s for unwrapping the value, but encountered key %s",
inputName,
reader.name()
)
);
}
 
value = delegateConverter.deserialize(reader, ctx);
}
reader.endObject();
}
return value;
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/convert/ChainedFactory.java
New file
0,0 → 1,141
package com.owlike.genson.convert;
 
import java.lang.reflect.Type;
 
import com.owlike.genson.Converter;
import com.owlike.genson.Factory;
import com.owlike.genson.Genson;
 
/**
* A chained factory of Converters that gives the ability to implementations to decorate the
* converter created by the next factory.
* <p/>
* One of Genson big strengths is its extensive use of Decorator and Chain of Responsibility design
* patterns. Chain of responsibility is applied in chaining Factories that can build Decorated
* Converters. ChainedFactory is the base class for such factories. But as ChainedFactory next
* element is an instance of Factory, you are free to apply the chain principle for your custom
* factories differently if you want.
* <p/>
* The global idea behind this design is to provide great extensibility to the library by allowing
* to add new functionalities to existing converters in a non intrusive way (extension and source
* modification). This is achieved by applying the decorator pattern. Here is an example of a
* decorated converter that adds null handling support.
* <p/>
* <pre>
* public class NullConverter extends Wrapper&lt;Converter&lt;Object&gt;&gt; implements
* Converter&lt;Object&gt; {
* private final Converter&lt;Object&gt; converter;
*
* public NullConverter(Converter&lt;Object&gt; converter) {
* super(converter);
* this.converter = converter;
* }
*
* public void serialize(Object obj, ObjectWriter writer, Context ctx) {
* if (obj == null)
* writer.writeNull();
* else
* converter.serialize(obj, writer, ctx);
* }
*
* public Object deserialize(ObjectReader reader, Context ctx) {
* if (TypeValue.NULL == reader.getTypeValue()) {
* return null;
* } else
* return converter.deserialize(reader, ctx);
*
* }
* }
*
* // now we need a factory to create the nullconverter for type T and wire it with the existing
* // factories so we can get an instance of the converter for that type.
* public class NullConverterFactory extends ChainedFactory {
* public NullConverterFactory(Factory&lt;Converter&lt;?&gt;&gt; next) {
* super(next);
* }
*
* public Converter&lt;?&gt; create(Type type, Genson genson, Converter&lt;?&gt; nextConverter) {
* return new NullConverter(nextConverter);
* }
* }
* </pre>
* <p/>
* As you can see it is pretty simple but also powerful. Note that our NullConverter extends
* Wrapper class. When you encapsulate converters you should extend Wrapper
* class this way Genson can access the class information of wrapped converters. Imagine for example
* that you put some annotation on converter A and wrap it in converter B, now if you wrap B in C
* you wont be able to get class information of A (ex: its annotations). Wrapper class
* allows to merge class information of current implementation and the wrapped one.
*
* @author eugen
* @see com.owlike.genson.convert.NullConverter NullConverter
* @see com.owlike.genson.convert.BasicConvertersFactory BasicConvertersFactory
* @see com.owlike.genson.Wrapper Wrapper
*/
public abstract class ChainedFactory implements Factory<Converter<?>> {
private Factory<? extends Converter<?>> next;
 
protected ChainedFactory() {
}
 
protected ChainedFactory(Factory<Converter<?>> next) {
this.next = next;
}
 
public Converter<?> create(Type type, Genson genson) {
Converter<?> nextConverter = null;
if (next != null) {
nextConverter = next.create(type, genson);
}
Converter<?> converter = create(type, genson, nextConverter);
return converter == null ? nextConverter : converter;
}
 
/**
* This method will be called by {@link #create(Type, Genson)} with nextConverter being the
* converter created for current type by the next factory. This means that ChainedFactory will
* first create a converter with the next factory and then use it's own create method.
*
* @param type for which this factory must provide a converter
* @param genson instance that you can use when you need a converter for some other type (for
* example a converter of List&lt;Integer&gt; will need a converter for Integer type).
* @param nextConverter created by the next factory, may be null.
* @return null or a converter for this type
*/
protected abstract Converter<?> create(Type type, Genson genson, Converter<?> nextConverter);
 
/**
* Chains this factory with next and returns next (the tail) so you can do things like
* chain1.withNext(new chain2).withNext(new chain3); the resulting chain is
* chain1=>chain2=>chain3. Don't forget to keep a reference to the head (chain1).
*
* @param next factory
* @return the next factory passed as argument
*/
public final <T extends Factory<? extends Converter<?>>> T withNext(T next) {
if (this.next != null)
throw new IllegalStateException("next factory has already been set for " + getClass()
+ " you can not override it!");
this.next = next;
return next;
}
 
public final <T extends Factory<? extends Converter<?>>> T append(T next) {
ChainedFactory f = this;
while(f.next() != null) {
if (!(f.next() instanceof ChainedFactory)) {
throw new UnsupportedOperationException("Last element in the chain is not a ChainedFactory");
}
f = (ChainedFactory) f.next();
}
 
return f.withNext(next);
}
 
/**
* @return a reference to the next factory, may be null.
*/
public final Factory<? extends Converter<?>> next() {
return next;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/convert/BasicConvertersFactory.java
New file
0,0 → 1,167
package com.owlike.genson.convert;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
 
import com.owlike.genson.Context;
import com.owlike.genson.Converter;
import com.owlike.genson.Deserializer;
import com.owlike.genson.Factory;
import com.owlike.genson.Genson;
import com.owlike.genson.Operations;
import com.owlike.genson.Serializer;
import com.owlike.genson.Wrapper;
import com.owlike.genson.reflect.BeanDescriptorProvider;
import com.owlike.genson.reflect.TypeUtil;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
 
/**
* This is the base factory that will create converters based on the default ones and on custom
* Serializer, Deserializer and Converter. But it also uses factories (default and custom) and
* {@link com.owlike.genson.reflect.BeanDescriptorProvider BeanDescriptorProvider} that is
* responsible of creating bean converters.
* <p/>
* When you ask for a Converter it will
* <ul>
* <ol>
* <li>Lookup in the registered Serializers for one that is parameterized with the current type, if
* found we finished (it takes the first one, so the order matters).</li>
* <li>Else we will try the factories by searching the ones that can create and instance of
* Serializer&lt;CurrentType&gt; (again the order is very important). We continue while they return
* null.</li>
* <li>If no factory could create an instance we will use BeanDescriptorProvider.</li>
* </ol>
* </li>
* <li>We apply all the same logic a second time for Deserializer.</li>
* <li>If they are both an instance of Converter then we return one of them</li>
* <li>Otherwise we will wrap both into a Converter.</li>
* </ul>
* <p/>
* Note that the create method from the registered factories will only be called if the type with
* which they are parameterized is assignable from the current type. For example, if we look for a
* serializer of Integer then Factory&lt;Converter&lt;Integer>> and Factory&lt;Serializer&lt;Object>> match
* both, the first registered will be used.
*
* @author eugen
*/
public class BasicConvertersFactory implements Factory<Converter<?>> {
private final Map<Type, Serializer<?>> serializersMap;
private final Map<Type, Deserializer<?>> deserializersMap;
private final List<Factory<?>> factories;
private final BeanDescriptorProvider beanDescriptorProvider;
 
public BasicConvertersFactory(Map<Type, Serializer<?>> serializersMap,
Map<Type, Deserializer<?>> deserializersMap, List<Factory<?>> factories,
BeanDescriptorProvider beanDescriptorProvider) {
this.serializersMap = serializersMap;
this.deserializersMap = deserializersMap;
this.factories = factories;
this.beanDescriptorProvider = beanDescriptorProvider;
}
 
@SuppressWarnings({"unchecked", "rawtypes"})
public Converter<?> create(Type type, Genson genson) {
Converter<?> converter;
Serializer<?> serializer = provide(Serializer.class, type, serializersMap, genson);
Deserializer<?> deserializer = provide(Deserializer.class, type, deserializersMap, genson);
if (serializer instanceof Converter && deserializer instanceof Converter) {
converter = (Converter<?>) deserializer;
} else {
converter = new DelegatedConverter(serializer, deserializer);
}
return converter;
}
 
@SuppressWarnings("unchecked")
protected <T> T provide(Class<T> forClass, Type withParameterType,
Map<Type, ? extends T> fromTypeMap, Genson genson) {
if (fromTypeMap.containsKey(withParameterType)) return fromTypeMap.get(withParameterType);
 
Type wrappedParameterType = withParameterType;
if (withParameterType instanceof Class<?> && ((Class<?>) withParameterType).isPrimitive())
wrappedParameterType = TypeUtil.wrap((Class<?>) withParameterType);
 
for (Iterator<Factory<?>> it = factories.iterator(); it.hasNext(); ) {
Factory<?> factory = it.next();
Object object;
Type factoryType = TypeUtil.lookupGenericType(Factory.class, factory.getClass());
factoryType = TypeUtil.expandType(factoryType, factory.getClass());
// it is a parameterized type and we want the parameter corresponding to Serializer from
// Factory<Serializer<?>>
factoryType = TypeUtil.typeOf(0, factoryType);
Type factoryParameter = TypeUtil.typeOf(0, factoryType);
if (forClass.isAssignableFrom(TypeUtil.getRawClass(factoryType))
&& TypeUtil.match(wrappedParameterType, factoryParameter, false)
&& (object = factory.create(withParameterType, genson)) != null) {
return forClass.cast(object);
}
}
 
return (T) beanDescriptorProvider.provide(TypeUtil.getRawClass(withParameterType),
withParameterType, genson);
}
 
private class DelegatedConverter<T> extends Wrapper<Converter<T>> implements Converter<T> {
private final Serializer<T> serializer;
private final Deserializer<T> deserializer;
 
public DelegatedConverter(Serializer<T> serializer, Deserializer<T> deserializer) {
this.serializer = serializer;
this.deserializer = deserializer;
}
 
public void serialize(T obj, ObjectWriter writer, Context ctx) throws Exception {
serializer.serialize(obj, writer, ctx);
}
 
public T deserialize(ObjectReader reader, Context ctx) throws Exception {
return deserializer.deserialize(reader, ctx);
}
 
@Override
public <A extends Annotation> A getAnnotation(Class<A> aClass) {
A a = null;
if (serializer != null) a = toAnnotatedElement(serializer).getAnnotation(aClass);
if (deserializer != null && a == null)
a = toAnnotatedElement(deserializer).getAnnotation(aClass);
return a;
}
 
@Override
public Annotation[] getAnnotations() {
if (serializer != null && deserializer != null)
return Operations.union(Annotation[].class, toAnnotatedElement(serializer)
.getAnnotations(), toAnnotatedElement(deserializer).getAnnotations());
if (serializer != null) return toAnnotatedElement(serializer).getAnnotations();
if (deserializer != null) return toAnnotatedElement(deserializer).getAnnotations();
 
return new Annotation[0];
}
 
@Override
public Annotation[] getDeclaredAnnotations() {
if (serializer != null && deserializer != null)
return Operations.union(Annotation[].class, toAnnotatedElement(serializer)
.getDeclaredAnnotations(), toAnnotatedElement(deserializer)
.getDeclaredAnnotations());
if (serializer != null) return toAnnotatedElement(serializer).getDeclaredAnnotations();
if (deserializer != null)
return toAnnotatedElement(deserializer).getDeclaredAnnotations();
 
return new Annotation[0];
}
 
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
if (serializer != null)
return toAnnotatedElement(serializer).isAnnotationPresent(annotationClass);
if (deserializer != null)
return toAnnotatedElement(deserializer).isAnnotationPresent(annotationClass);
return false;
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/convert/package-info.java
New file
0,0 → 1,7
/**
* This package provides some default {@link com.owlike.genson.Converter Converter} implementations and
* the chained factory and converter decorator mechanisms.
* @see com.owlike.genson.convert.ChainedFactory
* @see com.owlike.genson.Wrapper
*/
package com.owlike.genson.convert;
/branches/grupo4/impl/src/java/com/owlike/genson/convert/BeanViewConverter.java
New file
0,0 → 1,104
package com.owlike.genson.convert;
 
import java.lang.reflect.Type;
import java.util.List;
 
import com.owlike.genson.BeanView;
import com.owlike.genson.Context;
import com.owlike.genson.Converter;
import com.owlike.genson.Genson;
import com.owlike.genson.Wrapper;
import com.owlike.genson.annotation.HandleBeanView;
import com.owlike.genson.reflect.BeanDescriptor;
import com.owlike.genson.reflect.BeanViewDescriptorProvider;
import com.owlike.genson.reflect.TypeUtil;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
 
/**
* Converter responsible of applying the BeanView mechanism.
*
* @param <T> type of objects this BeanViewConverter can handle.
* @author eugen
* @see com.owlike.genson.reflect.BeanViewDescriptorProvider BeanViewDescriptorProvider
* @see com.owlike.genson.BeanView BeanView
*/
public class BeanViewConverter<T> extends Wrapper<Converter<T>> implements Converter<T> {
 
public static class BeanViewConverterFactory extends ChainedFactory {
private final BeanViewDescriptorProvider provider;
 
public BeanViewConverterFactory(BeanViewDescriptorProvider provider) {
this.provider = provider;
}
 
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
protected Converter<?> create(Type type, Genson genson, Converter<?> nextConverter) {
if (!Wrapper.toAnnotatedElement(nextConverter).isAnnotationPresent(
HandleBeanView.class))
// TODO as we link an instance to a type, we may optimize things, but for the moment it is okay
// lets see if this feature is used
return new BeanViewConverter(type, provider, nextConverter);
return nextConverter;
}
}
 
private final BeanViewDescriptorProvider provider;
private final Type type;
 
public BeanViewConverter(Type type, BeanViewDescriptorProvider provider, Converter<T> next) {
super(next);
this.provider = provider;
this.type = type;
}
 
@SuppressWarnings("unchecked")
protected Class<? extends BeanView<T>> findViewFor(Type type,
List<Class<? extends BeanView<?>>> views) {
for (Class<? extends BeanView<?>> v : views) {
Type searchedType = TypeUtil.lookupGenericType(BeanView.class, v);
searchedType = TypeUtil.expandType(searchedType, v);
searchedType = TypeUtil.typeOf(0, searchedType);
if (TypeUtil.match(type, searchedType, false)) {
return (Class<? extends BeanView<T>>) v;
}
}
return null;
}
 
public void serialize(T obj, ObjectWriter writer, Context ctx) throws Exception {
boolean handled = false;
List<Class<? extends BeanView<?>>> views = ctx.views();
if (views != null && views.size() > 0) {
Class<? extends BeanView<T>> viewClass = findViewFor(type, views);
if (viewClass != null) {
Type viewForType = TypeUtil.expandType(BeanView.class.getTypeParameters()[0],
viewClass);
@SuppressWarnings("unchecked")
Class<T> viewForClass = (Class<T>) TypeUtil.getRawClass(viewForType);
BeanDescriptor<T> descriptor = provider
.provide(viewForClass, viewClass, ctx.genson);
descriptor.serialize(obj, writer, ctx);
handled = true;
}
}
if (!handled) wrapped.serialize(obj, writer, ctx);
}
 
public T deserialize(ObjectReader reader, Context ctx) throws Exception {
if (ctx.hasViews()) {
Class<? extends BeanView<T>> viewClass = findViewFor(type, ctx.views());
if (viewClass != null) {
Type viewForType = TypeUtil.expandType(BeanView.class.getTypeParameters()[0],
viewClass);
@SuppressWarnings("unchecked")
Class<T> viewForClass = (Class<T>) TypeUtil.getRawClass(viewForType);
BeanDescriptor<T> descriptor = provider
.provide(viewForClass, viewClass, ctx.genson);
return descriptor.deserialize(reader, ctx);
}
}
return wrapped.deserialize(reader, ctx);
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/convert/CircularClassReferenceConverterFactory.java
New file
0,0 → 1,68
package com.owlike.genson.convert;
 
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
 
import com.owlike.genson.Context;
import com.owlike.genson.Converter;
import com.owlike.genson.Genson;
import com.owlike.genson.Wrapper;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
 
/**
* ChainedFactory that handles circular class references.
*
* @author eugen
*/
public class CircularClassReferenceConverterFactory extends ChainedFactory {
private final static class CircularConverter<T> extends Wrapper<Converter<T>> implements Converter<T> {
protected CircularConverter() {
super();
}
 
public void serialize(T obj, ObjectWriter writer, Context ctx) throws Exception {
wrapped.serialize(obj, writer, ctx);
}
 
public T deserialize(ObjectReader reader, Context ctx) throws Exception {
return wrapped.deserialize(reader, ctx);
}
 
void setDelegateConverter(Converter<T> delegate) {
decorate(delegate);
}
}
 
private final ThreadLocal<Map<Type, CircularConverter<?>>> _circularConverters = new ThreadLocal<Map<Type, CircularConverter<?>>>();
 
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public Converter<?> create(Type type, Genson genson) {
Map<Type, CircularConverter<?>> map = _circularConverters.get();
if (map == null) {
map = new HashMap<Type, CircularConverter<?>>();
_circularConverters.set(map);
}
 
if (_circularConverters.get().containsKey(type)) {
return _circularConverters.get().get(type);
} else {
try {
CircularConverter circularConverter = new CircularConverter();
_circularConverters.get().put(type, circularConverter);
Converter converter = next().create(type, genson);
circularConverter.setDelegateConverter(converter);
return converter;
} finally {
_circularConverters.get().remove(type);
}
}
}
 
@Override
protected Converter<?> create(Type type, Genson genson, Converter<?> nextConverter) {
throw new UnsupportedOperationException();
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/convert/NullConverterFactory.java
New file
0,0 → 1,96
package com.owlike.genson.convert;
 
import java.lang.reflect.Type;
 
import com.owlike.genson.Context;
import com.owlike.genson.Converter;
import com.owlike.genson.Genson;
import com.owlike.genson.JsonBindingException;
import com.owlike.genson.Serializer;
import com.owlike.genson.Wrapper;
import com.owlike.genson.annotation.HandleNull;
import com.owlike.genson.reflect.TypeUtil;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
import com.owlike.genson.stream.ValueType;
 
/**
* The default implementation handles null values by returning the predefined default value if any or null during
* deserialization and by calling writer.writeNull() during serialization.
* <p/>
*
* @author eugen
*/
public class NullConverterFactory extends ChainedFactory {
private final boolean failOnNullPrimitive;
 
public NullConverterFactory(boolean failOnNullPrimitive) {
this.failOnNullPrimitive = failOnNullPrimitive;
}
 
private class FailIfNullConverter<T> extends Wrapper<Converter<T>> implements Converter<T> {
public FailIfNullConverter(Converter<T> delegate) {
super(delegate);
}
 
@Override
public void serialize(T object, ObjectWriter writer, Context ctx) throws Exception {
if (object == null) {
throw new JsonBindingException("Serialization of null primitives is forbidden");
} else {
wrapped.serialize(object, writer, ctx);
}
}
 
@Override
public T deserialize(ObjectReader reader, Context ctx) throws Exception {
if (ValueType.NULL == reader.getValueType()) {
throw new JsonBindingException("Can not deserialize null to a primitive type");
} else {
return wrapped.deserialize(reader, ctx);
}
}
}
 
// TODO check if making the delegate instance final would improve perfs
private class NullConverterWrapper<T> extends Wrapper<Converter<T>> implements
Converter<T> {
private final T defaultValue;
 
public NullConverterWrapper(T defaultValue, Converter<T> converter) {
super(converter);
this.defaultValue = defaultValue;
}
 
public void serialize(T obj, ObjectWriter writer, Context ctx) throws Exception {
if (obj == null) {
writer.writeNull();
} else {
wrapped.serialize(obj, writer, ctx);
}
}
 
public T deserialize(ObjectReader reader, Context ctx) throws Exception {
if (ValueType.NULL == reader.getValueType()) {
return defaultValue;
} else {
return wrapped.deserialize(reader, ctx);
}
}
}
 
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
protected Converter<?> create(Type type, Genson genson, Converter<?> nextConverter) {
if (Wrapper.toAnnotatedElement(nextConverter).isAnnotationPresent(HandleNull.class)) {
return nextConverter;
} else {
Class<?> rawClass = TypeUtil.getRawClass(type);
if (failOnNullPrimitive && rawClass.isPrimitive()) {
return new FailIfNullConverter(nextConverter);
} else {
return new NullConverterWrapper(genson.defaultValue(rawClass), nextConverter);
}
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/convert/RuntimeTypeConverter.java
New file
0,0 → 1,50
package com.owlike.genson.convert;
 
import java.lang.reflect.Type;
 
import com.owlike.genson.Context;
import com.owlike.genson.Converter;
import com.owlike.genson.Genson;
import com.owlike.genson.Wrapper;
import com.owlike.genson.reflect.TypeUtil;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
 
/**
* This converter will use the runtime type of objects during serialization.
*
* @param <T> the type this converter is handling.
* @author eugen
*/
public class RuntimeTypeConverter<T> extends Wrapper<Converter<T>> implements Converter<T> {
public static class RuntimeTypeConverterFactory extends ChainedFactory {
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
protected Converter<?> create(Type type, Genson genson, Converter<?> nextConverter) {
if (nextConverter == null)
throw new IllegalArgumentException(
"RuntimeTypeConverter can not be last Converter in the chain.");
return (Converter<?>) new RuntimeTypeConverter(TypeUtil.getRawClass(type),
nextConverter);
}
}
 
private final Class<T> tClass;
 
public RuntimeTypeConverter(Class<T> tClass, Converter<T> next) {
super(next);
this.tClass = tClass;
}
 
public void serialize(T obj, ObjectWriter writer, Context ctx) throws Exception {
if (obj != null && !tClass.equals(obj.getClass()))
ctx.genson.serialize(obj, obj.getClass(), writer, ctx);
else
wrapped.serialize(obj, writer, ctx);
}
 
public T deserialize(ObjectReader reader, Context ctx) throws Exception {
return wrapped.deserialize(reader, ctx);
}
 
}
/branches/grupo4/impl/src/java/com/owlike/genson/convert/ClassMetadataConverter.java
New file
0,0 → 1,104
package com.owlike.genson.convert;
 
import java.lang.reflect.Type;
 
import com.owlike.genson.*;
import com.owlike.genson.annotation.HandleClassMetadata;
import com.owlike.genson.convert.DefaultConverters.UntypedConverterFactory.UntypedConverter;
import com.owlike.genson.reflect.TypeUtil;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
import com.owlike.genson.stream.ValueType;
 
/**
* Converter responsible of writing and reading @class metadata. This is useful if you want to be
* able to deserialize all serialized objects without knowing their concrete type. Metadata is
* written only in objects (never in arrays or literals) and is always the first element in the
* object. Most default converters are annotated with @HandleClassMetada indicating that they will
* not have class metadata written nor use it during deserialization. This feature is disabled by
* default, to enable it use {@link com.owlike.genson.GensonBuilder#useClassMetadata(boolean)}.
* Genson provides also a aliases mechanism that will replace the class name with the value of your alias
* in the generated stream. You should use it as it is more "secure" and provides you more flexibility.
* Indeed if you change the name or package of your class you will still be able to deserialize to it.
* An example allowing to serialize a object and then deserialize it back without knowing its type would be:
* <p/>
* <pre>
* class Foo {
* }
*
* Genson genson = new GensonBuilder().useClassMetadata(true).addAlias("foo", Foo.class).create();
* String json = genson.serialize(new Foo());
* // json value will be {&quot;@class&quot;:&quot;Foo&quot;}
* Foo foo = (Foo) genson.deserialize(json, Object.class);
* </pre>
*
* @param <T>
* @author eugen
* @see com.owlike.genson.stream.ObjectWriter#writeMetadata(String, String) ObjectWriter.metadata(key, value)
* @see com.owlike.genson.stream.ObjectReader#metadata(String) ObjectReader.metadata("class")
* @see com.owlike.genson.Genson#aliasFor(Class) Genson.aliasFor(Class)
*/
public class ClassMetadataConverter<T> extends Wrapper<Converter<T>> implements Converter<T> {
public static class ClassMetadataConverterFactory extends ChainedFactory {
private final boolean classMetadataWithStaticType;
 
public ClassMetadataConverterFactory(boolean classMetadataWithStaticType) {
this.classMetadataWithStaticType = classMetadataWithStaticType;
}
 
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
protected Converter<?> create(Type type, Genson genson, Converter<?> nextConverter) {
if (nextConverter == null)
throw new IllegalArgumentException(
"nextConverter must be not null for ClassMetadataConverter, "
+ "as ClassMetadataConverter can not be the last converter in the chain!");
 
Class<?> rawClass = TypeUtil.getRawClass(type);
if (genson.isWithClassMetadata()
&& !Wrapper.toAnnotatedElement(nextConverter).isAnnotationPresent(HandleClassMetadata.class))
return new ClassMetadataConverter(rawClass, nextConverter, classMetadataWithStaticType);
else
return nextConverter;
}
}
 
private final boolean classMetadataWithStaticType;
private final Class<T> tClass;
private final boolean skipMetadataSerialization;
 
public ClassMetadataConverter(Class<T> tClass, Converter<T> delegate, boolean classMetadataWithStaticType) {
super(delegate);
this.tClass = tClass;
this.classMetadataWithStaticType = classMetadataWithStaticType;
skipMetadataSerialization = Wrapper.isOfType(delegate, UntypedConverter.class);
}
 
public void serialize(T obj, ObjectWriter writer, Context ctx) throws Exception {
if (!skipMetadataSerialization && obj != null &&
(classMetadataWithStaticType || (!classMetadataWithStaticType && !tClass.equals(obj.getClass())))) {
writer.beginNextObjectMetadata()
.writeMetadata("class", ctx.genson.aliasFor(obj.getClass()));
}
wrapped.serialize(obj, writer, ctx);
}
 
public T deserialize(ObjectReader reader, Context ctx) throws Exception {
if (ValueType.OBJECT.equals(reader.getValueType())) {
String className = reader.nextObjectMetadata().metadata("class");
if (className != null) {
try {
Class<?> classFromMetadata = ctx.genson.classFor(className);
if (!classFromMetadata.equals(tClass)) {
Converter<T> deser = ctx.genson.provideConverter(classFromMetadata);
return deser.deserialize(reader, ctx);
}
} catch (ClassNotFoundException e) {
throw new JsonBindingException(
"Could not use @class metadata, no such class: " + className);
}
}
}
return wrapped.deserialize(reader, ctx);
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/convert/ContextualFactory.java
New file
0,0 → 1,24
package com.owlike.genson.convert;
 
import com.owlike.genson.Converter;
import com.owlike.genson.Genson;
import com.owlike.genson.reflect.BeanProperty;
 
/**
* <b>Beta feature</b>
* <br/>
* Create method signature and BeanProperty might change in the future.
* Allows to create a converter for some type T based on bean property available at compile time
* (ex: you can not use it with map keys because they exist only at runtime). This feature works
* only for POJO databinding, in could be improved implying some refactoring.
*
* @param <T> the type of objects handled by Converters built by this factory
* @author eugen
*/
public interface ContextualFactory<T> {
/**
* Return an instance of a converter working with objects of type T based on property argument
* or null.
*/
public Converter<T> create(BeanProperty property, Genson genson);
}
/branches/grupo4/impl/src/java/com/owlike/genson/BeanView.java
New file
0,0 → 1,117
package com.owlike.genson;
 
/**
* Interface to be implemented by classes who want to act as a view on objects of type T during
* serialization and deserializaiton.
* <p/>
* To understand what a BeanView is we must first understand one of the problems it is intended to
* solve. Imagine you store some business objects in a cache and you have internal and external
* webservices that all return a different json representation of those objects (filtered properties
* and even transformed properties). The external webservices can't return the same representation
* as the internal ones as the object may contain some confidential data.
* <ul>
* Usually you have two choices :
* <li>Use a different instance of the json library for each different json representation and
* configure it with custom Serializers/Deserializers (you can use annotations to filter properties
* but not to change its name if you have multiple names and nor to transform the data).</li>
* <li>Use data transfer objects that will act as a "View of your Model". You will have to copy the
* data from the cached objects to the DTOs and serialize them. As a result your cache has lost some
* of its interest (you will create new instances of DTOs).</li>
* </ul>
* <p/>
* The BeanView tries to solve this kind of problem by taking the second approach. Indeed
* implementations of BeanView will act as a stateless bean that will extract data (and could apply
* transformations) during serialization and as a factory and data aggregator during
* deserialization. The parameterized type T will correspond to the type of the objects on which
* this view can be applied. All the methods from the view respecting the conventional JavaBean
* structure will be used (getters to extract data, setters to aggregate and static methods
* annotated with {@link com.owlike.genson.annotation.JsonCreator JsonCreator} as factory methods). Except that the
* getters will take an argument of type T (from which to extract the data), and the setter two
* arguments, the value (can be a complex object, in that case Genson will try to deserialize the
* current value into that type) and T object in which to set the data. Parameters order matters,
* for setters the first parameter is the value to deserialize and the second is the object that you
* are building (of type T). By default the beanview functionality is disabled, to enable it use
* method {@link com.owlike.genson.GensonBuilder#useBeanViews(boolean)}
* setWithBeanViewConverter(true)} from Genson.Builder. Lets have a look at this example to better
* understand how it works.
* <p/>
* <pre>
* public static class Person {
* private String lastName;
* String name;
* int birthYear;
* String thisFieldWontBeSerialized;
*
* Person(String lastName) {
* this.lastName = lastName;
* }
*
* public String getLastName() {
* return lastName;
* }
*
* // instead of serializing and deserializing Person based on the fields and methods it contains those
* // and only those from the BeanView will be used
* public static class ViewOfPerson implements BeanView&lt;Person&gt; {
* public ViewOfPerson() {
* }
*
* // This method will be called to create an instance of Person instead of using the constructor
* // or annotated @Creator method from Person
* &#064;JsonCreator
* public static Person createNewPerson(String lastName) {
* return new Person(lastName);
* }
*
* public String getLastName(Person p) {
* return p.getLastName();
* }
*
* public @JsonProperty(&quot;name&quot;)
* String getNameOf(Person p) {
* return p.name;
* }
*
* // here we will transform the birth year of the person into its age and change the serialized
* // name from &quot;birthYear&quot; to &quot;age&quot;
* public int getAge(Person p) {
* return GregorianCalendar.getInstance().get(Calendar.YEAR) - p.birthYear;
* }
*
* public void setName(String name, Person p) {
* p.name = name;
* }
*
* // here it will match the property named &quot;age&quot; from the json stream and transform it into birth
* // year of Person
* &#064;JsonProperty(&quot;age&quot;)
* public void setBirthYear(int personBirthYear, Person p) {
* p.birthYear = GregorianCalendar.getInstance().get(Calendar.YEAR) - personBirthYear;
* }
* }
*
* public static void main(String[] args) {
* Genson genson = new Genson.Builder().setWithBeanViewConverter(true).create();
* genson.serialize(new Person("eugen"), ViewOfPerson.class);
* }
* </pre>
* <p/>
* <p/>
* Implementations of BeanView must be stateless, thread safe and have a default no arg constructor.
* BeanViews will be applied at <u>runtime before the standard Converter</u>. If a view for the
* current type is present in the context it will be used instead of the corresponding Converter. If
* you want to understand how it works behind the scene you can have a look at <a href=
* "http://code.google.com/p/genson/source/browse/src/main/java/com/owlike/genson/convert/BeanViewConverter.java"
* >BeanViewConverter</a> and <a href=
* "http://code.google.com/p/genson/source/browse/src/main/java/com/owlike/genson/reflect/BeanViewDescriptorProvider.java"
* >BeanViewDescriptorProvider</a>.
*
* @param <T> the type of objects on which this view will be applied.
* @see com.owlike.genson.convert.BeanViewConverter BeanViewConverter
* @see com.owlike.genson.reflect.BeanViewDescriptorProvider BeanViewDescriptorProvider
* @see com.owlike.genson.annotation.JsonCreator JsonCreator
* @see com.owlike.genson.annotation.JsonProperty JsonProperty
*/
public interface BeanView<T> {
 
}
/branches/grupo4/impl/src/java/com/owlike/genson/GensonBuilder.java
New file
0,0 → 1,1014
package com.owlike.genson;
 
import com.owlike.genson.convert.*;
import com.owlike.genson.ext.GensonBundle;
import com.owlike.genson.reflect.*;
import com.owlike.genson.reflect.BeanDescriptorProvider.CompositeBeanDescriptorProvider;
import com.owlike.genson.reflect.AbstractBeanDescriptorProvider.ContextualFactoryDecorator;
import com.owlike.genson.reflect.AbstractBeanDescriptorProvider.ContextualConverterFactory;
 
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
 
/**
* Use the GensonBuilder class when you want to create a custom Genson instance. This class allows you
* for example to register custom converters/serializers/deserializers
* {@link #withConverters(Converter...)} or custom converter Factories
* {@link #withConverterFactory(Factory)}.
* <p/>
* This class combines the GensonBuilder design pattern with template pattern providing handy
* configuration and extensibility. All its public methods are intended to be used in the
* GensonBuilder "style" and its protected methods are part of the template. When you call
* {@link #create()} method, it will start assembling all the configuration and build all the
* required components by using the protected methods. For example if you wish to use in your
* projects a GensonBuilder that will always create some custom
* {@link com.owlike.genson.reflect.BeanDescriptorProvider BeanDescriptorProvider} you have to
* extend {@link #createBeanDescriptorProvider()}, or imagine that you implemented some
* Converters that you always want to register then override {@link #getDefaultConverters()}.
*
* @author eugen
*/
public class GensonBuilder {
private final Map<Type, Serializer<?>> serializersMap = new HashMap<Type, Serializer<?>>();
private final Map<Type, Deserializer<?>> deserializersMap = new HashMap<Type, Deserializer<?>>();
private final List<Factory<?>> converterFactories = new ArrayList<Factory<?>>();
private final List<ContextualFactory<?>> contextualFactories = new ArrayList<ContextualFactory<?>>();
private final List<BeanPropertyFactory> beanPropertyFactories = new ArrayList<BeanPropertyFactory>();
 
private boolean skipNull = false;
private boolean htmlSafe = false;
private boolean withClassMetadata = false;
private boolean throwExcOnNoDebugInfo = false;
private boolean useGettersAndSetters = true;
private boolean useFields = true;
private boolean withBeanViewConverter = false;
private boolean useRuntimeTypeForSerialization = false;
private boolean withDebugInfoPropertyNameResolver = false;
private boolean strictDoubleParse = false;
private boolean indent = false;
private boolean metadata = false;
private boolean failOnMissingProperty = false;
 
private List<GensonBundle> _bundles = new ArrayList<GensonBundle>();
 
private PropertyNameResolver propertyNameResolver;
private BeanMutatorAccessorResolver mutatorAccessorResolver;
private VisibilityFilter propertyFilter = VisibilityFilter.PACKAGE_PUBLIC;
private VisibilityFilter methodFilter = VisibilityFilter.PACKAGE_PUBLIC;
private VisibilityFilter constructorFilter = VisibilityFilter.PACKAGE_PUBLIC;
 
private ClassLoader classLoader = getClass().getClassLoader();
private BeanDescriptorProvider beanDescriptorProvider;
private DateFormat dateFormat = SimpleDateFormat.getDateTimeInstance();
private boolean useDateAsTimestamp = true;
private boolean classMetadataWithStaticType = true;
 
// for the moment we don't allow to override
private BeanViewDescriptorProvider beanViewDescriptorProvider;
 
private final Map<String, Class<?>> withClassAliases = new HashMap<String, Class<?>>();
private final Map<Class<?>, BeanView<?>> registeredViews = new HashMap<Class<?>, BeanView<?>>();
 
private ChainedFactory customFactoryChain;
 
private final Map<Class<?>, Object> defaultValues = new HashMap<Class<?>, Object>();
private boolean failOnNullPrimitive = false;
private RuntimePropertyFilter runtimePropertyFilter = RuntimePropertyFilter.noFilter;
 
public GensonBuilder() {
defaultValues.put(int.class, 0);
defaultValues.put(long.class, 0l);
defaultValues.put(short.class, (short) 0);
defaultValues.put(double.class, 0d);
defaultValues.put(float.class, 0f);
defaultValues.put(boolean.class, false);
defaultValues.put(byte.class, (byte) 0);
defaultValues.put(char.class, '\u0000');
}
 
/**
* Alias used in serialized class metadata instead of the full class name. See
* {@link com.owlike.genson.convert.ClassMetadataConverter ClassMetadataConverter} for more
* metadata. If you add an alias, it will automatically enable the class metadata feature,
* as if you used {@link #useClassMetadata(boolean)}.
*
* @param alias
* @param forClass
* @return a reference to this builder.
*/
public GensonBuilder addAlias(String alias, Class<?> forClass) {
withClassMetadata = true;
withClassAliases.put(alias, forClass);
return this;
}
 
/**
* Registers converters mapping them to their corresponding parameterized type.
*
* @param converter
* @return a reference to this builder.
*/
public GensonBuilder withConverters(Converter<?>... converter) {
for (Converter<?> c : converter) {
Type typeOfConverter = TypeUtil.typeOf(0,
TypeUtil.lookupGenericType(Converter.class, c.getClass()));
typeOfConverter = TypeUtil.expandType(typeOfConverter, c.getClass());
registerConverter(c, typeOfConverter);
}
return this;
}
 
/**
* Register converter by mapping it to type argument.
*
* @param converter to register
* @param type of objects this converter handles
* @return a reference to this builder.
*/
public <T> GensonBuilder withConverter(Converter<T> converter, Class<? extends T> type) {
registerConverter(converter, type);
return this;
}
 
/**
* Register converter by mapping it to the parameterized type of type argument.
*
* @param converter to register
* @param type of objects this converter handles
* @return a reference to this builder.
*/
public <T> GensonBuilder withConverter(Converter<T> converter, GenericType<? extends T> type) {
registerConverter(converter, type.getType());
return this;
}
 
private <T> void registerConverter(Converter<T> converter, Type type) {
if (serializersMap.containsKey(type))
throw new IllegalStateException("Can not register converter "
+ converter.getClass()
+ ". A custom serializer is already registered for type " + type);
if (deserializersMap.containsKey(type))
throw new IllegalStateException("Can not register converter "
+ converter.getClass()
+ ". A custom deserializer is already registered for type " + type);
serializersMap.put(type, converter);
deserializersMap.put(type, converter);
}
 
public GensonBuilder withSerializers(Serializer<?>... serializer) {
for (Serializer<?> s : serializer) {
Type typeOfConverter = TypeUtil.typeOf(0,
TypeUtil.lookupGenericType(Serializer.class, s.getClass()));
typeOfConverter = TypeUtil.expandType(typeOfConverter, s.getClass());
registerSerializer(s, typeOfConverter);
}
return this;
}
 
public <T> GensonBuilder withSerializer(Serializer<T> serializer, Class<? extends T> type) {
registerSerializer(serializer, type);
return this;
}
 
public <T> GensonBuilder withSerializer(Serializer<T> serializer, GenericType<? extends T> type) {
registerSerializer(serializer, type.getType());
return this;
}
 
private <T> void registerSerializer(Serializer<T> serializer, Type type) {
if (serializersMap.containsKey(type))
throw new IllegalStateException("Can not register serializer "
+ serializer.getClass()
+ ". A custom serializer is already registered for type " + type);
serializersMap.put(type, serializer);
}
 
public GensonBuilder withDeserializers(Deserializer<?>... deserializer) {
for (Deserializer<?> d : deserializer) {
Type typeOfConverter = TypeUtil.typeOf(0,
TypeUtil.lookupGenericType(Deserializer.class, d.getClass()));
typeOfConverter = TypeUtil.expandType(typeOfConverter, d.getClass());
registerDeserializer(d, typeOfConverter);
}
return this;
}
 
public <T> GensonBuilder withDeserializer(Deserializer<T> deserializer, Class<? extends T> type) {
registerDeserializer(deserializer, type);
return this;
}
 
public <T> GensonBuilder withDeserializer(Deserializer<T> deserializer,
GenericType<? extends T> type) {
registerDeserializer(deserializer, type.getType());
return this;
}
 
private <T> void registerDeserializer(Deserializer<T> deserializer, Type type) {
if (deserializersMap.containsKey(type))
throw new IllegalStateException("Can not register deserializer "
+ deserializer.getClass()
+ ". A custom deserializer is already registered for type " + type);
deserializersMap.put(type, deserializer);
}
 
/**
* Registers converter factories.
*
* @param factory to register
* @return a reference to this builder.
*/
public GensonBuilder withConverterFactory(Factory<? extends Converter<?>> factory) {
converterFactories.add(factory);
return this;
}
 
/**
* Registers serializer factories.
*
* @param factory to register
* @return a reference to this builder.
*/
public GensonBuilder withSerializerFactory(Factory<? extends Serializer<?>> factory) {
converterFactories.add(factory);
return this;
}
 
/**
* Registers deserializer factories.
*
* @param factory to register
* @return a reference to this builder.
*/
public GensonBuilder withDeserializerFactory(Factory<? extends Deserializer<?>> factory) {
converterFactories.add(factory);
return this;
}
 
/**
* ContextualFactory is actually in a beta status, it will not be removed, but might be
* refactored.
*/
public GensonBuilder withContextualFactory(ContextualFactory<?>... factories) {
contextualFactories.addAll(Arrays.asList(factories));
return this;
}
 
/**
* A ChainedFactory provides a way to use custom Converters that have access to the default Converters.
* An example of use is to wrap incoming/outgoing json in a root object and delegate then the ser/de to the default
* Converter.
*
* This mechanism is internally used by Genson to decorate the different Converters with additional behaviour
* (null handling, ser/de of polymorphic types with class info, runtime type based ser/de, etc).
*
* Note that you can't use it in situations where you want to start reading/writing some partial infos and want to
* delegate the rest to the default Converter.
*/
public GensonBuilder withConverterFactory(ChainedFactory chainedFactory) {
if (customFactoryChain == null) customFactoryChain = chainedFactory;
else {
customFactoryChain.append(chainedFactory);
}
return this;
}
 
/**
* Allows you to register new BeanPropertyFactory responsible of creating BeanProperty
* accessors, mutators and BeanCreators. This is a very low level feature, you probably
* don't need it.
*/
public GensonBuilder withBeanPropertyFactory(BeanPropertyFactory... factories) {
beanPropertyFactories.addAll(Arrays.asList(factories));
return this;
}
 
/**
* Register some genson bundles. For example to enable JAXB support:
* <p/>
* <pre>
* builder.withBundle(new JAXBExtension());
* </pre>
*
* <b>All bundles should be registered before any other customization.</b>
*
* @see GensonBundle
*/
public GensonBuilder withBundle(GensonBundle... bundles) {
for (GensonBundle bundle : bundles) {
bundle.configure(this);
_bundles.add(bundle);
}
return this;
}
 
/**
* Override the default classloader
*
* @param loader classloader which will be used to load classes while deserializing
* @return a reference to this builder
*/
public GensonBuilder withClassLoader(ClassLoader loader) {
classLoader = loader;
return this;
}
 
 
/**
* Replaces default {@link com.owlike.genson.reflect.BeanMutatorAccessorResolver
* BeanMutatorAccessorResolver} by the specified one.
*
* @param resolver
* @return a reference to this builder.
*/
public GensonBuilder set(BeanMutatorAccessorResolver resolver) {
mutatorAccessorResolver = resolver;
return this;
}
 
/**
* Replaces default {@link com.owlike.genson.reflect.PropertyNameResolver
* PropertyNameResolver} by the specified one.
*
* @param resolver
* @return a reference to this builder.
*/
public GensonBuilder set(PropertyNameResolver resolver) {
propertyNameResolver = resolver;
return this;
}
 
/**
* Register additional BeanMutatorAccessorResolver that will be used before the standard
* ones.
*
* @param resolvers
* @return a reference to this builder.
*/
public GensonBuilder with(BeanMutatorAccessorResolver... resolvers) {
if (mutatorAccessorResolver == null)
mutatorAccessorResolver = createBeanMutatorAccessorResolver();
if (mutatorAccessorResolver instanceof BeanMutatorAccessorResolver.CompositeResolver)
((BeanMutatorAccessorResolver.CompositeResolver) mutatorAccessorResolver).add(resolvers);
else
throw new IllegalStateException(
"You can not add multiple resolvers if the base resolver is not of type "
+ BeanMutatorAccessorResolver.CompositeResolver.class.getName());
return this;
}
 
public Map<Type, Serializer<?>> getSerializersMap() {
return Collections.unmodifiableMap(serializersMap);
}
 
public Map<Type, Deserializer<?>> getDeserializersMap() {
return Collections.unmodifiableMap(deserializersMap);
}
 
public ClassLoader getClassLoader() {
return classLoader;
}
 
/**
* Registers the specified resolvers in the order they were defined and before the standard
* ones.
*
* @param resolvers
* @return a reference to this builder.
*/
public GensonBuilder with(PropertyNameResolver... resolvers) {
if (propertyNameResolver == null) propertyNameResolver = createPropertyNameResolver();
if (propertyNameResolver instanceof PropertyNameResolver.CompositePropertyNameResolver)
((PropertyNameResolver.CompositePropertyNameResolver) propertyNameResolver).add(resolvers);
else
throw new IllegalStateException(
"You can not add multiple resolvers if the base resolver is not of type "
+ PropertyNameResolver.CompositePropertyNameResolver.class.getName());
return this;
}
 
/**
* Renames all fields named field to toName.
*/
public GensonBuilder rename(String field, String toName) {
return rename(field, null, toName, null);
}
 
/**
* Renames all fields of type fieldOfType to toName.
*/
public GensonBuilder rename(Class<?> fieldOfType, String toName) {
return rename(null, null, toName, fieldOfType);
}
 
/**
* Renames all fields named field declared in class fromClass to toName.
*/
public GensonBuilder rename(String field, Class<?> fromClass, String toName) {
return rename(field, fromClass, toName, null);
}
 
/**
* Renames all fields named field and of type fieldOfType to toName.
*/
public GensonBuilder rename(String field, String toName, Class<?> fieldOfType) {
return rename(field, null, toName, fieldOfType);
}
 
/**
* Renames all fields named field, of type fieldOfType and declared in fromClass to toName.
*/
public GensonBuilder rename(final String field, final Class<?> fromClass, final String toName,
final Class<?> ofType) {
return with(new RenamingPropertyNameResolver(field, fromClass, ofType, toName));
}
 
public GensonBuilder exclude(String field) {
return filter(field, null, null, true);
}
 
public GensonBuilder exclude(Class<?> fieldOfType) {
return filter(null, null, fieldOfType, true);
}
 
public GensonBuilder exclude(String field, Class<?> fromClass) {
return filter(field, fromClass, null, true);
}
 
public GensonBuilder exclude(String field, Class<?> fromClass, Class<?> ofType) {
return filter(field, fromClass, ofType, true);
}
 
public GensonBuilder include(String field) {
return filter(field, null, null, false);
}
 
public GensonBuilder include(Class<?> fieldOfType) {
return filter(null, null, fieldOfType, false);
}
 
public GensonBuilder include(String field, Class<?> fromClass) {
return filter(field, fromClass, null, false);
}
 
public GensonBuilder include(String field, Class<?> fromClass, Class<?> ofType) {
return filter(field, fromClass, ofType, false);
}
 
private GensonBuilder filter(final String field, final Class<?> declaringClass,
final Class<?> ofType, final boolean exclude) {
return with(new PropertyFilter(exclude, field, declaringClass, ofType));
}
 
/**
* If true will not serialize null values
*
* @param skipNull indicates whether null values should be serialized or not.
* @return a reference to this builder.
*/
public GensonBuilder setSkipNull(boolean skipNull) {
this.skipNull = skipNull;
return this;
}
 
public boolean isSkipNull() {
return skipNull;
}
 
/**
* If true \,<,>,&,= characters will be replaced by \u0027, \u003c, \u003e, \u0026, \u003d
*
* @param htmlSafe indicates whether serialized data should be html safe.
* @return a reference to this builder.
*/
public GensonBuilder setHtmlSafe(boolean htmlSafe) {
this.htmlSafe = htmlSafe;
return this;
}
 
public boolean isHtmlSafe() {
return htmlSafe;
}
 
/**
* Indicates whether class metadata should be serialized and used during deserialization.
*
* @see com.owlike.genson.convert.ClassMetadataConverter ClassMetadataConverter
*/
public GensonBuilder useClassMetadata(boolean enabled) {
this.withClassMetadata = enabled;
this.metadata = true;
return this;
}
 
/**
* Specifies the data format that should be used for java.util.Date serialization and
* deserialization.
*
* @param dateFormat
* @return a reference to this builder.
*/
public GensonBuilder useDateFormat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
return this;
}
 
public boolean isThrowExceptionOnNoDebugInfo() {
return throwExcOnNoDebugInfo;
}
 
/**
* Used in conjunction with {@link #useConstructorWithArguments(boolean)}. If true
* an exception will be thrown when a class has been compiled without debug informations.
*
* @param throwExcOnNoDebugInfo
* @return a reference to this builder.
 
* ASMCreatorParameterNameResolver
*/
public GensonBuilder setThrowExceptionIfNoDebugInfo(boolean throwExcOnNoDebugInfo) {
this.throwExcOnNoDebugInfo = throwExcOnNoDebugInfo;
return this;
}
 
/**
* If true, getters and setters would be used during serialization/deserialization in favor
* of fields. If there is not getter/setter for a field then the field will be used, except
* if you specified that fields should not be used with {@link #useFields(boolean)}. By
* default getters, setters and fields will be used.
*/
public GensonBuilder useMethods(boolean enabled) {
this.useGettersAndSetters = enabled;
return this;
}
 
public GensonBuilder useMethods(boolean enabled, VisibilityFilter visibility) {
useMethods(enabled);
return setMethodFilter(visibility);
}
 
/**
* If true, fields will be used when no getter/setter is available, except if you specified
* that no getter/setter should be used with {@link #useMethods(boolean)}, in
* that case only fields will be used. By default getters, setters and fields will be used.
*/
public GensonBuilder useFields(boolean enabled) {
this.useFields = enabled;
return this;
}
 
public GensonBuilder useFields(boolean enabled, VisibilityFilter visibility) {
useFields(enabled);
return setFieldFilter(visibility);
}
 
/**
* If true {@link BeanView} mechanism will be enabled.
*/
public GensonBuilder useBeanViews(boolean enabled) {
this.withBeanViewConverter = enabled;
return this;
}
 
/**
* If true the concrete type of the serialized object will always be used. So if you have
* List<Number> type it will not use the Number serializer but the one for the concrete type
* of the current value.
*
* @param enabled
* @return a reference to this builder.
*/
public GensonBuilder useRuntimeType(boolean enabled) {
this.useRuntimeTypeForSerialization = enabled;
return this;
}
 
/**
* If true constructor and method arguments name will be resolved from the generated debug
* symbols during compilation. It is a very powerful feature from Genson, you should have a
 
* ASMCreatorParameterNameResolver}.
*
* @param enabled
* @return a reference to this builder.
* @see #setThrowExceptionIfNoDebugInfo(boolean)
*/
public GensonBuilder useConstructorWithArguments(boolean enabled) {
this.withDebugInfoPropertyNameResolver = enabled;
return this;
}
 
public GensonBuilder setFieldFilter(VisibilityFilter propertyFilter) {
this.propertyFilter = propertyFilter;
return this;
}
 
public GensonBuilder setMethodFilter(VisibilityFilter methodFilter) {
this.methodFilter = methodFilter;
return this;
}
 
public GensonBuilder setConstructorFilter(VisibilityFilter constructorFilter) {
this.constructorFilter = constructorFilter;
return this;
}
 
public GensonBuilder useStrictDoubleParse(boolean strictDoubleParse) {
this.strictDoubleParse = strictDoubleParse;
return this;
}
 
/**
* If true outputed json will be indented using two spaces, otherwise (by default) all is
* printed on same line.
*/
public GensonBuilder useIndentation(boolean indent) {
this.indent = indent;
return this;
}
 
public GensonBuilder useDateAsTimestamp(boolean enabled) {
this.useDateAsTimestamp = enabled;
return this;
}
 
public GensonBuilder useMetadata(boolean metadata) {
this.metadata = metadata;
return this;
}
 
public GensonBuilder useByteAsInt(boolean enable) {
if (enable) {
withConverters(DefaultConverters.ByteArrayAsIntArrayConverter.instance);
}
return this;
}
 
/**
* If set to true, Genson will throw a JsonBindingException when it encounters a property in the incoming json that does not match
* a property in the class.
* False by default.
* @param enable
* @return
*/
public GensonBuilder failOnMissingProperty(boolean enable) {
this.failOnMissingProperty = enable;
return this;
}
 
/**
* If set to false, during serialization class metadata will be serialized only for types where the runtime type differs from the static one.
* Ex:
*
* <pre>
* class Person {
* public Address address;
* }
* </pre>
*
* Here if the concrete instance of address is Address then this type will not be serialized as metadata, but if they differ then
* it is serialized. By default this option is true, all types are serialized.
* @param enable
* @return
*/
public GensonBuilder useClassMetadataWithStaticType(boolean enable) {
this.classMetadataWithStaticType = enable;
return this;
}
 
/**
* Wrap a single value into a list when a list is expected. Useful when dealing with APIs that unwrap
* arrays containing a single value. Disabled by default.
*/
public GensonBuilder acceptSingleValueAsList(boolean enable) {
if (enable) withConverterFactory(DefaultConverters.SingleValueAsListFactory.instance);
return this;
}
 
/**
* Uses the passed value as the default value for this type.
*/
public GensonBuilder useDefaultValue(Object value, Class<?> targetType) {
defaultValues.put(targetType, value);
return this;
}
 
/**
* Will wrap all the root objects under outputKey during serializaiton and unwrap the content under
* inputKey during deserializaiton. For example:
*
* <code>
* Genson genson = new GensonBuilder().wrapRootValues("request", "response").create();
*
* // would produce: {"response": {... person properties ...}}
* genson.serialize(person);
*
* Person p = genson.deserialize("{\"request\":{...}}", Person.class);
* </code>
*
* If you need this mechanism only for some types or using different root keys, then you can register JaxbBundle with
* wrapRootValues(true) and annotate the specific classes with XmlRootElement.
*/
public GensonBuilder wrapRootValues(final String inputKey, final String outputKey) {
return withConverterFactory(new ChainedFactory() {
@Override
protected Converter<?> create(Type type, Genson genson, Converter<?> nextConverter) {
 
return new DefaultConverters.WrappedRootValueConverter<Object>(
inputKey,
outputKey,
(Converter<Object>) nextConverter
);
}
});
}
 
/**
* False by default. When enabled a JsonBindingException will be thrown if null is encountered during serialization
* (should never happen) or deserialization for a primitive type.
*/
public GensonBuilder failOnNullPrimitive(boolean enabled) {
this.failOnNullPrimitive = enabled;
return this;
}
 
public GensonBuilder useRuntimePropertyFilter(RuntimePropertyFilter filter) {
this.runtimePropertyFilter = filter;
return this;
}
 
/**
* Creates an instance of Genson. You may use this method as many times you want. It wont
* change the state of the builder, in sense that the returned instance will have always the
* same configuration.
*
* @return a new instance of Genson built for the current configuration.
*/
public Genson create() {
if (propertyNameResolver == null) propertyNameResolver = createPropertyNameResolver();
if (mutatorAccessorResolver == null)
mutatorAccessorResolver = createBeanMutatorAccessorResolver();
 
List<Converter<?>> converters = getDefaultConverters();
addDefaultSerializers(converters);
addDefaultDeserializers(converters);
addDefaultSerializers(getDefaultSerializers());
addDefaultDeserializers(getDefaultDeserializers());
 
List<Factory<? extends Converter<?>>> convFactories = new ArrayList<Factory<? extends Converter<?>>>();
addDefaultConverterFactories(convFactories);
converterFactories.addAll(convFactories);
 
List<Factory<? extends Serializer<?>>> serializerFactories = new ArrayList<Factory<? extends Serializer<?>>>();
addDefaultSerializerFactories(serializerFactories);
converterFactories.addAll(serializerFactories);
 
List<Factory<? extends Deserializer<?>>> deserializerFactories = new ArrayList<Factory<? extends Deserializer<?>>>();
addDefaultDeserializerFactories(deserializerFactories);
converterFactories.addAll(deserializerFactories);
 
List<ContextualFactory<?>> defaultContextualFactories = new ArrayList<ContextualFactory<?>>();
addDefaultContextualFactories(defaultContextualFactories);
contextualFactories.addAll(defaultContextualFactories);
 
beanDescriptorProvider = createBeanDescriptorProvider();
 
if (withBeanViewConverter) {
List<BeanMutatorAccessorResolver> resolvers = new ArrayList<BeanMutatorAccessorResolver>();
resolvers.add(new BeanViewDescriptorProvider.BeanViewMutatorAccessorResolver());
resolvers.add(mutatorAccessorResolver);
beanViewDescriptorProvider = new BeanViewDescriptorProvider(
new AbstractBeanDescriptorProvider.ContextualConverterFactory(contextualFactories), registeredViews,
createBeanPropertyFactory(),
new BeanMutatorAccessorResolver.CompositeResolver(resolvers), getPropertyNameResolver()
);
}
 
return create(createConverterFactory(), withClassAliases);
}
 
private void addDefaultSerializers(List<? extends Serializer<?>> serializers) {
if (serializers != null) {
for (Serializer<?> serializer : serializers) {
Type typeOfConverter = TypeUtil.typeOf(0,
TypeUtil.lookupGenericType(Serializer.class, serializer.getClass()));
typeOfConverter = TypeUtil.expandType(typeOfConverter, serializer.getClass());
if (!serializersMap.containsKey(typeOfConverter))
serializersMap.put(typeOfConverter, serializer);
}
}
}
 
private void addDefaultDeserializers(List<? extends Deserializer<?>> deserializers) {
if (deserializers != null) {
for (Deserializer<?> deserializer : deserializers) {
Type typeOfConverter = TypeUtil.typeOf(0, TypeUtil.lookupGenericType(Deserializer.class, deserializer.getClass()));
typeOfConverter = TypeUtil.expandType(typeOfConverter, deserializer.getClass());
if (!deserializersMap.containsKey(typeOfConverter))
deserializersMap.put(typeOfConverter, deserializer);
}
}
}
 
/**
* In theory this allows you to extend Genson class and to instantiate it, but actually you
* can not do it as Genson class is final. If some uses cases are discovered it may change.
*
* @param converterFactory
* @param classAliases
* @return a new Genson instance.
*/
protected Genson create(Factory<Converter<?>> converterFactory,
Map<String, Class<?>> classAliases) {
return new Genson(converterFactory, getBeanDescriptorProvider(),
isSkipNull(), isHtmlSafe(), classAliases, withClassMetadata,
strictDoubleParse, indent, metadata, failOnMissingProperty, defaultValues, runtimePropertyFilter);
}
 
/**
* You should override this method if you want to add custom
* {@link com.owlike.genson.convert.ChainedFactory ChainedFactory} or if you need to chain
* them differently.
*
* @return the converter <u>factory instance that will be used to resolve
* <strong>ALL</strong> converters</u>.
*/
protected Factory<Converter<?>> createConverterFactory() {
ChainedFactory chainHead = new CircularClassReferenceConverterFactory();
 
chainHead.append(new NullConverterFactory(failOnNullPrimitive));
 
if (useRuntimeTypeForSerialization) chainHead.append(new RuntimeTypeConverter.RuntimeTypeConverterFactory());
 
chainHead.append(new ClassMetadataConverter.ClassMetadataConverterFactory(classMetadataWithStaticType));
 
if (customFactoryChain != null) chainHead.append(customFactoryChain);
 
if (withBeanViewConverter) chainHead.append(new BeanViewConverter.BeanViewConverterFactory(
getBeanViewDescriptorProvider()));
 
ContextualFactoryDecorator ctxFactoryDecorator = new ContextualFactoryDecorator(
new BasicConvertersFactory(getSerializersMap(), getDeserializersMap(),
getFactories(), getBeanDescriptorProvider()));
 
chainHead.append(ctxFactoryDecorator);
 
return chainHead;
}
 
protected BeanMutatorAccessorResolver createBeanMutatorAccessorResolver() {
List<BeanMutatorAccessorResolver> resolvers = new ArrayList<BeanMutatorAccessorResolver>();
resolvers.add(new BeanMutatorAccessorResolver.GensonAnnotationsResolver());
 
resolvers.add(new BeanMutatorAccessorResolver.StandardMutaAccessorResolver(propertyFilter,
methodFilter, constructorFilter));
 
return new BeanMutatorAccessorResolver.CompositeResolver(resolvers);
}
 
/**
* You can override this method if you want to change the
* {@link com.owlike.genson.reflect.PropertyNameResolver PropertyNameResolver} that are
* registered by default. You can also simply replace the default PropertyNameResolver by
* setting another one with {@link #set(PropertyNameResolver)}.
*
* @return the property name resolver to be used. It should be an instance of
* {@link com.owlike.genson.reflect.PropertyNameResolver.CompositePropertyNameResolver
* PropertyNameResolver.CompositePropertyNameResolver}, otherwise you will not be
* able to add others PropertyNameResolvers using
* {@link #with(PropertyNameResolver...)} method.
*/
protected PropertyNameResolver createPropertyNameResolver() {
List<PropertyNameResolver> resolvers = new ArrayList<PropertyNameResolver>();
resolvers.add(new PropertyNameResolver.AnnotationPropertyNameResolver());
resolvers.add(new PropertyNameResolver.ConventionalBeanPropertyNameResolver());
 
 
return new PropertyNameResolver.CompositePropertyNameResolver(resolvers);
}
 
/**
* You can override this methods if you want to change the default converters (remove some,
* change the order, etc).
*
* @return the default converters list, must be not null.
*/
protected List<Converter<?>> getDefaultConverters() {
List<Converter<?>> converters = new ArrayList<Converter<?>>();
converters.add(DefaultConverters.StringConverter.instance);
converters.add(DefaultConverters.NumberConverter.instance);
converters.add(new DefaultConverters.DateConverter(dateFormat, useDateAsTimestamp));
converters.add(DefaultConverters.URLConverter.instance);
converters.add(DefaultConverters.URIConverter.instance);
converters.add(DefaultConverters.TimestampConverter.instance);
converters.add(DefaultConverters.BigDecimalConverter.instance);
converters.add(DefaultConverters.BigIntegerConverter.instance);
converters.add(DefaultConverters.UUIDConverter.instance);
converters.add(DefaultConverters.FileConverter.instance);
return converters;
}
 
/**
* Override this method if you want to change the default converter factories.
*
* @param factories list, is not null.
*/
protected void addDefaultConverterFactories(List<Factory<? extends Converter<?>>> factories) {
factories.add(DefaultConverters.ArrayConverterFactory.instance);
factories.add(DefaultConverters.CollectionConverterFactory.instance);
factories.add(DefaultConverters.MapConverterFactory.instance);
factories.add(DefaultConverters.EnumConverterFactory.instance);
factories.add(DefaultConverters.PrimitiveConverterFactory.instance);
factories.add(DefaultConverters.UntypedConverterFactory.instance);
factories.add(new DefaultConverters.CalendarConverterFactory(
new DefaultConverters.DateConverter(dateFormat, useDateAsTimestamp)
));
}
 
protected void addDefaultContextualFactories(List<ContextualFactory<?>> factories) {
factories.add(new DefaultConverters.DateContextualFactory());
factories.add(new DefaultConverters.PropertyConverterFactory());
}
 
protected List<Serializer<?>> getDefaultSerializers() {
return null;
}
 
protected void addDefaultSerializerFactories(
List<Factory<? extends Serializer<?>>> serializerFactories) {
}
 
protected List<Deserializer<?>> getDefaultDeserializers() {
return null;
}
 
protected void addDefaultDeserializerFactories(
List<Factory<? extends Deserializer<?>>> deserializerFactories) {
}
 
/**
* Creates the standard BeanDescriptorProvider that will be used to provide
* {@link com.owlike.genson.reflect.BeanDescriptor BeanDescriptor} instances for
* serialization/deserialization of all types that couldn't be handled by standard and
* custom converters and converter factories.
*
* @return the BeanDescriptorProvider instance.
*/
protected BeanDescriptorProvider createBeanDescriptorProvider() {
 
ContextualConverterFactory contextualConverterFactory = new ContextualConverterFactory(contextualFactories);
BeanPropertyFactory beanPropertyFactory = createBeanPropertyFactory();
 
List<BeanDescriptorProvider> providers = new ArrayList<BeanDescriptorProvider>();
for (GensonBundle bundle : _bundles) {
BeanDescriptorProvider provider = bundle.createBeanDescriptorProvider(contextualConverterFactory,
beanPropertyFactory,
getMutatorAccessorResolver(),
getPropertyNameResolver(), this);
 
if (provider != null) providers.add(provider);
}
 
providers.add(new BaseBeanDescriptorProvider(
new AbstractBeanDescriptorProvider.ContextualConverterFactory(contextualFactories),
createBeanPropertyFactory(), getMutatorAccessorResolver(), getPropertyNameResolver(),
useGettersAndSetters, useFields, true
));
 
return new CompositeBeanDescriptorProvider(providers);
}
 
protected BeanPropertyFactory createBeanPropertyFactory() {
if (withBeanViewConverter)
beanPropertyFactories.add(new BeanViewDescriptorProvider.BeanViewPropertyFactory(
registeredViews));
beanPropertyFactories.add(new BeanPropertyFactory.StandardFactory());
return new BeanPropertyFactory.CompositeFactory(beanPropertyFactories);
}
 
protected final PropertyNameResolver getPropertyNameResolver() {
return propertyNameResolver;
}
 
protected final BeanMutatorAccessorResolver getMutatorAccessorResolver() {
return mutatorAccessorResolver;
}
 
protected final BeanDescriptorProvider getBeanDescriptorProvider() {
return beanDescriptorProvider;
}
 
protected final BeanViewDescriptorProvider getBeanViewDescriptorProvider() {
return beanViewDescriptorProvider;
}
 
public final List<Factory<?>> getFactories() {
return Collections.unmodifiableList(converterFactories);
}
 
public final boolean isDateAsTimestamp() {
return useDateAsTimestamp;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/PropertyMutator.java
New file
0,0 → 1,120
package com.owlike.genson.reflect;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
 
import com.owlike.genson.*;
import com.owlike.genson.stream.ObjectReader;
 
public abstract class PropertyMutator extends BeanProperty implements Comparable<PropertyMutator> {
Deserializer<Object> propertyDeserializer;
 
protected PropertyMutator(String name, Type type, Class<?> declaringClass, Class<?> concreteClass,
Annotation[] annotations, int modifiers) {
super(name, type, declaringClass, concreteClass, annotations, modifiers);
}
 
public Object deserialize(ObjectReader reader, Context ctx) {
try {
return propertyDeserializer.deserialize(reader, ctx);
} catch (Throwable th) {
throw couldNotDeserialize(th);
}
}
 
public void deserialize(Object into, ObjectReader reader, Context ctx) {
Object propValue = null;
try {
propValue = propertyDeserializer.deserialize(reader, ctx);
} catch (Throwable th) {
throw couldNotDeserialize(th);
}
mutate(into, propValue);
}
 
public abstract void mutate(Object target, Object value);
 
public int compareTo(PropertyMutator o) {
return o.priority() - priority();
}
 
protected JsonBindingException couldNotMutate(Exception e) {
return new JsonBindingException("Could not mutate value of property named '"
+ name + "' using mutator " + signature(), e);
}
 
protected JsonBindingException couldNotDeserialize(Throwable e) {
return new JsonBindingException("Could not deserialize to property '" + name + "' of class " + declaringClass, e);
}
 
public static class MethodMutator extends PropertyMutator {
protected final Method _setter;
 
public MethodMutator(String name, Method setter, Type type, Class<?> concreteClass) {
super(name, type, setter.getDeclaringClass(), concreteClass, setter.getAnnotations(), setter.getModifiers());
this._setter = setter;
if (!_setter.isAccessible()) {
_setter.setAccessible(true);
}
}
 
@Override
public void mutate(Object target, Object value) {
try {
_setter.invoke(target, value);
} catch (IllegalArgumentException e) {
throw couldNotMutate(e);
} catch (IllegalAccessException e) {
throw couldNotMutate(e);
} catch (InvocationTargetException e) {
throw couldNotMutate(e);
}
}
 
@Override
public String signature() {
return _setter.toGenericString();
}
 
@Override
public int priority() {
return 100;
}
}
 
public static class FieldMutator extends PropertyMutator {
protected final Field _field;
 
public FieldMutator(String name, Field field, Type type, Class<?> concreteClass) {
super(name, type, field.getDeclaringClass(), concreteClass, field.getAnnotations(), field.getModifiers());
this._field = field;
if (!_field.isAccessible()) {
_field.setAccessible(true);
}
}
 
@Override
public void mutate(Object target, Object value) {
try {
_field.set(target, value);
} catch (IllegalArgumentException e) {
throw couldNotMutate(e);
} catch (IllegalAccessException e) {
throw couldNotMutate(e);
}
}
 
@Override
public String signature() {
return _field.toGenericString();
}
 
@Override
public int priority() {
return 0;
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/BeanPropertyFactory.java
New file
0,0 → 1,142
package com.owlike.genson.reflect;
 
import static com.owlike.genson.reflect.TypeUtil.getRawClass;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
 
import com.owlike.genson.Genson;
 
public interface BeanPropertyFactory {
PropertyAccessor createAccessor(String name, Field field, Type ofType, Genson genson);
 
PropertyAccessor createAccessor(String name, Method method, Type ofType, Genson genson);
 
BeanCreator createCreator(Type ofType, Constructor<?> ctr, String[] resolvedNames,
Genson genson);
 
BeanCreator createCreator(Type ofType, Method method, String[] resolvedNames,
Genson genson);
 
PropertyMutator createMutator(String name, Field field, Type ofType, Genson genson);
 
PropertyMutator createMutator(String name, Method method, Type ofType, Genson genson);
 
class CompositeFactory implements BeanPropertyFactory {
private final List<BeanPropertyFactory> factories;
 
public CompositeFactory(List<? extends BeanPropertyFactory> factories) {
this.factories = new ArrayList<BeanPropertyFactory>(factories);
}
 
@Override
public PropertyAccessor createAccessor(String name, Field field, Type ofType, Genson genson) {
for (BeanPropertyFactory factory : factories) {
PropertyAccessor accessor = factory.createAccessor(name, field, ofType, genson);
if (accessor != null) return accessor;
}
throw new RuntimeException("Failed to create a accessor for field " + field);
}
 
@Override
public PropertyAccessor createAccessor(String name, Method method, Type ofType,
Genson genson) {
for (BeanPropertyFactory factory : factories) {
PropertyAccessor accessor = factory.createAccessor(name, method, ofType, genson);
if (accessor != null) return accessor;
}
throw new RuntimeException("Failed to create a accessor for method " + method);
}
 
@Override
public BeanCreator createCreator(Type ofType, Constructor<?> ctr, String[] resolvedNames,
Genson genson) {
for (BeanPropertyFactory factory : factories) {
BeanCreator creator = factory.createCreator(ofType, ctr, resolvedNames, genson);
if (creator != null) return creator;
}
throw new RuntimeException("Failed to create a BeanCreator for constructor " + ctr);
}
 
@Override
public BeanCreator createCreator(Type ofType, Method method, String[] resolvedNames,
Genson genson) {
for (BeanPropertyFactory factory : factories) {
BeanCreator creator = factory.createCreator(ofType, method, resolvedNames, genson);
if (creator != null) return creator;
}
throw new RuntimeException("Failed to create a BeanCreator for method " + method);
}
 
@Override
public PropertyMutator createMutator(String name, Field field, Type ofType, Genson genson) {
for (BeanPropertyFactory factory : factories) {
PropertyMutator mutator = factory.createMutator(name, field, ofType, genson);
if (mutator != null) return mutator;
}
throw new RuntimeException("Failed to create a mutator for field " + field);
}
 
@Override
public PropertyMutator createMutator(String name, Method method, Type ofType, Genson genson) {
for (BeanPropertyFactory factory : factories) {
PropertyMutator mutator = factory.createMutator(name, method, ofType, genson);
if (mutator != null) return mutator;
}
throw new RuntimeException("Failed to create a mutator for method " + method);
}
}
 
class StandardFactory implements BeanPropertyFactory {
public PropertyAccessor createAccessor(String name, Field field, Type ofType, Genson genson) {
Class<?> ofClass = getRawClass(ofType);
Type expandedType = TypeUtil.expandType(field.getGenericType(), ofType);
return new PropertyAccessor.FieldAccessor(name, field, expandedType, ofClass);
}
 
public PropertyAccessor createAccessor(String name, Method method, Type ofType,
Genson genson) {
Type expandedType = TypeUtil.expandType(method.getGenericReturnType(), ofType);
return new PropertyAccessor.MethodAccessor(name, method, expandedType,
getRawClass(ofType));
}
 
public PropertyMutator createMutator(String name, Field field, Type ofType, Genson genson) {
Class<?> ofClass = getRawClass(ofType);
Type expandedType = TypeUtil.expandType(field.getGenericType(), ofType);
return new PropertyMutator.FieldMutator(name, field, expandedType, ofClass);
}
 
public PropertyMutator createMutator(String name, Method method, Type ofType, Genson genson) {
Type expandedType = TypeUtil.expandType(method.getGenericParameterTypes()[0], ofType);
return new PropertyMutator.MethodMutator(name, method, expandedType,
getRawClass(ofType));
}
 
// ofClass is not necessarily of same type as method return type, as ofClass corresponds to
// the declaring class!
public BeanCreator createCreator(Type ofType, Method method, String[] resolvedNames,
Genson genson) {
return new BeanCreator.MethodBeanCreator(method, resolvedNames, expandTypes(
method.getGenericParameterTypes(), ofType), getRawClass(ofType));
}
 
public BeanCreator createCreator(Type ofType, Constructor<?> ctr, String[] resolvedNames,
Genson genson) {
return new BeanCreator.ConstructorBeanCreator(getRawClass(ofType), ctr, resolvedNames,
expandTypes(ctr.getGenericParameterTypes(), ofType));
}
 
public Type[] expandTypes(Type[] typesToExpand, Type inContext) {
Type[] expandedTypes = new Type[typesToExpand.length];
for (int i = 0; i < typesToExpand.length; i++) {
expandedTypes[i] = TypeUtil.expandType(typesToExpand[i], inContext);
}
return expandedTypes;
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/AbstractBeanDescriptorProvider.java
New file
0,0 → 1,272
package com.owlike.genson.reflect;
 
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
 
import com.owlike.genson.Converter;
import com.owlike.genson.Factory;
import com.owlike.genson.Genson;
import com.owlike.genson.ThreadLocalHolder;
import com.owlike.genson.convert.ContextualFactory;
 
import static com.owlike.genson.reflect.TypeUtil.*;
 
/**
* Abstract implementation of {@link BeanDescriptorProvider} applying the template pattern.
* <p/>
* If you wonder how to implement the different abstract methods defined in this class have a look
* at the <a href=
* "http://code.google.com/p/genson/source/browse/src/main/java/com/owlike/genson/reflect/BaseBeanDescriptorProvider.java"
* >BaseBeanDescriptorProvider</a>.
*
* @author eugen
*/
public abstract class AbstractBeanDescriptorProvider implements BeanDescriptorProvider {
final static String CONTEXT_KEY = "__GENSON$CREATION_CONTEXT";
final static String DO_NOT_CACHE_CONVERTER_KEY = "__GENSON$DO_NOT_CACHE_CONVERTER";
 
public final static class ContextualConverterFactory {
private final List<? extends ContextualFactory<?>> contextualFactories;
 
public ContextualConverterFactory(List<? extends ContextualFactory<?>> contextualFactories) {
this.contextualFactories = contextualFactories != null ? new ArrayList<ContextualFactory<?>>(
contextualFactories) : new ArrayList<ContextualFactory<?>>();
}
 
Converter<?> provide(BeanProperty property, Genson genson) {
Type type = property.getType();
for (Iterator<? extends ContextualFactory<?>> it = contextualFactories.iterator(); it
.hasNext(); ) {
ContextualFactory<?> factory = it.next();
Converter<?> object = null;
Type factoryType = lookupGenericType(ContextualFactory.class, factory.getClass());
factoryType = expandType(factoryType, factory.getClass());
Type factoryParameter = typeOf(0, factoryType);
 
if (type instanceof Class<?> && ((Class<?>) type).isPrimitive())
type = wrap((Class<?>) type);
 
if (match(type, factoryParameter, false)
&& (object = factory.create(property, genson)) != null) {
return object;
}
}
return null;
}
}
 
public final static class ContextualFactoryDecorator implements Factory<Converter<?>> {
private final Factory<Converter<?>> delegatedFactory;
 
public ContextualFactoryDecorator(Factory<Converter<?>> delegatedFactory) {
this.delegatedFactory = delegatedFactory;
}
 
@Override
public Converter<?> create(Type type, Genson genson) {
Converter<?> converter = ThreadLocalHolder.get(CONTEXT_KEY, Converter.class);
if (converter != null) return converter;
return delegatedFactory.create(type, genson);
}
}
 
private final ContextualConverterFactory contextualConverterFactory;
 
protected AbstractBeanDescriptorProvider(ContextualConverterFactory contextualConverterFactory) {
this.contextualConverterFactory = contextualConverterFactory;
}
 
@Override
public <T> BeanDescriptor<T> provide(Class<T> type, Genson genson) {
return provide(type, type, genson);
}
 
@Override
public <T> BeanDescriptor<T> provide(Class<T> ofClass, Type ofType, Genson genson) {
Map<String, LinkedList<PropertyMutator>> mutatorsMap = new LinkedHashMap<String, LinkedList<PropertyMutator>>();
Map<String, LinkedList<PropertyAccessor>> accessorsMap = new LinkedHashMap<String, LinkedList<PropertyAccessor>>();
 
List<BeanCreator> creators = provideBeanCreators(ofType, genson);
 
provideBeanPropertyAccessors(ofType, accessorsMap, genson);
provideBeanPropertyMutators(ofType, mutatorsMap, genson);
 
List<PropertyAccessor> accessors = new ArrayList<PropertyAccessor>(accessorsMap.size());
for (Map.Entry<String, LinkedList<PropertyAccessor>> entry : accessorsMap.entrySet()) {
PropertyAccessor accessor = checkAndMergeAccessors(entry.getKey(), entry.getValue());
// in case of...
if (accessor != null) accessors.add(accessor);
}
 
Map<String, PropertyMutator> mutators = new HashMap<String, PropertyMutator>(mutatorsMap.size());
for (Map.Entry<String, LinkedList<PropertyMutator>> entry : mutatorsMap.entrySet()) {
PropertyMutator mutator = checkAndMergeMutators(entry.getKey(), entry.getValue());
if (mutator != null) mutators.put(mutator.name, mutator);
}
 
BeanCreator ctr = checkAndMerge(ofType, creators);
if (ctr != null) mergeAccessorsWithCreatorProperties(ofType, accessors, ctr);
if (ctr != null) mergeMutatorsWithCreatorProperties(ofType, mutators, ctr);
 
// 1 - prepare the converters for the accessors
for (PropertyAccessor accessor : accessors) {
accessor.propertySerializer = provide(accessor, genson);
}
 
// 2 - prepare the mutators
for (PropertyMutator mutator : mutators.values()) {
mutator.propertyDeserializer = provide(mutator, genson);
}
 
// 3 - prepare the converters for creator parameters
if (ctr != null) {
for (PropertyMutator mutator : ctr.parameters.values()) {
mutator.propertyDeserializer = provide(mutator, genson);
}
}
 
for (PropertyMutator p : mutators.values()) {
for (String alias : p.aliases()) mutators.put(alias, p);
}
 
// lets fail fast if the BeanDescriptor has been built for the wrong type.
// another option could be to pass in all the methods an additional parameter Class<T> that
// would not necessarily correspond to the rawClass of ofType. In fact we authorize that
// ofType rawClass is different from Class<T>, but the BeanDescriptor must match!
BeanDescriptor<T> descriptor = create(ofClass, ofType, ctr, accessors, mutators, genson);
if (!ofClass.isAssignableFrom(descriptor.getOfClass()))
throw new ClassCastException("Actual implementation of BeanDescriptorProvider "
+ getClass()
+ " seems to do something wrong. Expected BeanDescriptor for type " + ofClass
+ " but provided BeanDescriptor for type " + descriptor.getOfClass());
return descriptor;
}
 
private Converter<Object> provide(BeanProperty property, Genson genson) {
// contextual converters must not be retrieved from cache nor stored in cache, by first
// trying to create it and reusing it during the
// call to genson.provideConverter we avoid retrieving it from cache, and by setting
// DO_NOT_CACHE_CONVERTER to true we tell genson not to store
// this converter in cache
 
@SuppressWarnings("unchecked")
Converter<Object> converter = (Converter<Object>) contextualConverterFactory.provide(
property, genson);
if (converter != null) {
ThreadLocalHolder.store(DO_NOT_CACHE_CONVERTER_KEY, true);
ThreadLocalHolder.store(CONTEXT_KEY, converter);
}
try {
return genson.provideConverter(property.type);
} finally {
if (converter != null) {
ThreadLocalHolder.remove(DO_NOT_CACHE_CONVERTER_KEY, Boolean.class);
ThreadLocalHolder.remove(CONTEXT_KEY, Converter.class);
}
}
}
 
/**
* Creates an instance of BeanDescriptor based on the passed arguments. Subclasses can override
* this method to create their own BeanDescriptors.
*
* @param forClass
* @param ofType
* @param creator
* @param accessors
* @param mutators
* @return a instance
*/
protected <T> BeanDescriptor<T> create(Class<T> forClass, Type ofType, BeanCreator creator,
List<PropertyAccessor> accessors, Map<String, PropertyMutator> mutators,
Genson genson) {
return new BeanDescriptor<T>(forClass, getRawClass(ofType), accessors, mutators, creator, genson.failOnMissingProperty());
}
 
/**
* Provides a list of {@link BeanCreator} for type ofType.
*
* @param ofType
* @param genson
* @return a list of resolved bean creators
*/
protected abstract List<BeanCreator> provideBeanCreators(Type ofType, Genson genson);
 
/**
* Adds resolved {@link PropertyMutator} to mutatorsMap.
*
* @param ofType
* @param mutatorsMap
* @param genson
*/
protected abstract void provideBeanPropertyMutators(Type ofType,
Map<String, LinkedList<PropertyMutator>> mutatorsMap, Genson genson);
 
/**
* Adds resolved {@link PropertyAccessor} to accessorsMap.
*
* @param ofType
* @param accessorsMap
* @param genson
*/
protected abstract void provideBeanPropertyAccessors(Type ofType,
Map<String, LinkedList<PropertyAccessor>> accessorsMap, Genson genson);
 
/**
* Implementations of this method can do some additional checks on the creators validity or do
* any other operations related to creators. This method must merge all creators into a single
* one.
*
* @param creators
* @return the creator that will be used by the BeanDescriptor
*/
protected abstract BeanCreator checkAndMerge(Type ofType, List<BeanCreator> creators);
 
/**
* Implementations are supposed to merge the {@link PropertyMutator}s from mutators list into a
* single PropertyMutator.
*
* @param name
* @param mutators
* @return a single PropertyMutator or null.
*/
protected abstract PropertyMutator checkAndMergeMutators(String name,
LinkedList<PropertyMutator> mutators);
 
/**
* Implementations may do additional merge operations based on the resolved creator
* parameters and the resolved mutators.
*
* @param ofType
* @param mutators
* @param creator
*/
protected abstract void mergeMutatorsWithCreatorProperties(Type ofType, Map<String, PropertyMutator> mutators, BeanCreator creator);
 
/**
* Implementations may do additional merge operations based on the resolved creator
* parameters and the resolved accessors.
*
* @param ofType
* @param accessors
* @param creator
*/
protected abstract void mergeAccessorsWithCreatorProperties(Type ofType, List<PropertyAccessor> accessors, BeanCreator creator);
 
/**
* Implementations are supposed to merge the {@link PropertyAccessor}s from accessors list into
* a single PropertyAccessor.
*
* @param name
* @param accessors
* @return a single property accessor for this name
*/
protected abstract PropertyAccessor checkAndMergeAccessors(String name,
LinkedList<PropertyAccessor> accessors);
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/BeanDescriptor.java
New file
0,0 → 1,204
package com.owlike.genson.reflect;
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
import com.owlike.genson.*;
import com.owlike.genson.reflect.BeanCreator.BeanCreatorProperty;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
 
/**
* BeanDescriptors are used to serialize/deserialize objects based on their fields, methods and
* constructors. By default it is supposed to work on JavaBeans, however it can be configured and
* extended to support different kind of objects.
* <p/>
* In most cases BeanDescriptors should not be used directly as it is used internally to support
* objects not handled by the default Converters. The most frequent case when you will use directly
* a BeanDescriptor is when you want to deserialize into an existing instance. Here is an example :
* <p/>
* <pre>
* Genson genson = new Genson();
* BeanDescriptorProvider provider = genson.getBeanDescriptorProvider();
* BeanDescriptor&lt;MyClass&gt; descriptor = provider.provide(MyClass.class, genson);
*
* MyClass existingInstance = descriptor.deserialize(existingInstance, new JsonReader(&quot;{}&quot;),
* new Context(genson));
* </pre>
*
* @param <T> type that this BeanDescriptor can serialize and deserialize.
* @author eugen
* @see BeanDescriptorProvider
*/
public class BeanDescriptor<T> implements Converter<T> {
final Class<?> fromDeclaringClass;
final Class<T> ofClass;
final Map<String, PropertyMutator> mutableProperties;
final List<PropertyAccessor> accessibleProperties;
final boolean failOnMissingProperty;
 
final BeanCreator creator;
private final boolean _noArgCtr;
 
private static final Object MISSING = new Object();
// Used as a cache so we just copy it instead of recreating and assigning the default values
private Object[] globalCreatorArgs;
 
private final static Comparator<BeanProperty> _readablePropsComparator = new Comparator<BeanProperty>() {
public int compare(BeanProperty o1, BeanProperty o2) {
return o1.name.compareToIgnoreCase(o2.name);
}
};
 
public BeanDescriptor(Class<T> forClass, Class<?> fromDeclaringClass,
List<PropertyAccessor> readableBps,
Map<String, PropertyMutator> writableBps, BeanCreator creator,
boolean failOnMissingProperty) {
this.ofClass = forClass;
this.fromDeclaringClass = fromDeclaringClass;
this.creator = creator;
this.failOnMissingProperty = failOnMissingProperty;
mutableProperties = writableBps;
 
Collections.sort(readableBps, _readablePropsComparator);
 
accessibleProperties = Collections.unmodifiableList(readableBps);
if (this.creator != null) {
_noArgCtr = this.creator.parameters.size() == 0;
globalCreatorArgs = new Object[creator.parameters.size()];
Arrays.fill(globalCreatorArgs, MISSING);
} else {
_noArgCtr = false;
}
}
 
public boolean isReadable() {
return !accessibleProperties.isEmpty();
}
 
public boolean isWritable() {
return creator != null;
}
 
public void serialize(T obj, ObjectWriter writer, Context ctx) {
writer.beginObject();
RuntimePropertyFilter runtimePropertyFilter = ctx.genson.runtimePropertyFilter();
for (PropertyAccessor accessor : accessibleProperties) {
if (runtimePropertyFilter.shouldInclude(accessor, ctx)) accessor.serialize(obj, writer, ctx);
}
writer.endObject();
}
 
public T deserialize(ObjectReader reader, Context ctx) {
T bean = null;
// optimization for default ctr
if (_noArgCtr) {
bean = ofClass.cast(creator.create());
deserialize(bean, reader, ctx);
} else {
if (creator == null)
throw new JsonBindingException("No constructor has been found for type "
+ ofClass);
bean = _deserWithCtrArgs(reader, ctx);
}
return bean;
}
 
public void deserialize(T into, ObjectReader reader, Context ctx) {
reader.beginObject();
RuntimePropertyFilter runtimePropertyFilter = ctx.genson.runtimePropertyFilter();
for (; reader.hasNext(); ) {
reader.next();
String propName = reader.name();
PropertyMutator mutator = mutableProperties.get(propName);
if (mutator != null) {
if (runtimePropertyFilter.shouldInclude(mutator, ctx)) {
mutator.deserialize(into, reader, ctx);
} else {
reader.skipValue();
}
} else if (failOnMissingProperty) throw missingPropertyException(propName);
else reader.skipValue();
}
reader.endObject();
}
 
 
protected T _deserWithCtrArgs(ObjectReader reader, Context ctx) {
List<String> names = new ArrayList<String>();
List<Object> values = new ArrayList<Object>();
RuntimePropertyFilter runtimePropertyFilter = ctx.genson.runtimePropertyFilter();
 
reader.beginObject();
for (; reader.hasNext(); ) {
reader.next();
String propName = reader.name();
PropertyMutator muta = mutableProperties.get(propName);
 
if (muta != null) {
if (runtimePropertyFilter.shouldInclude(muta, ctx)) {
Object param = muta.deserialize(reader, ctx);
names.add(propName);
values.add(param);
} else {
reader.skipValue();
}
} else if (failOnMissingProperty) throw missingPropertyException(propName);
else reader.skipValue();
}
 
int size = names.size();
int foundCtrParameters = 0;
Object[] creatorArgs = globalCreatorArgs.clone();
String[] newNames = new String[size];
Object[] newValues = new Object[size];
 
for (int i = 0, j = 0; i < size; i++) {
BeanCreatorProperty mp = creator.paramsAndAliases.get(names.get(i));
if (mp != null) {
creatorArgs[mp.index] = values.get(i);
foundCtrParameters++;
} else {
newNames[j] = names.get(i);
newValues[j] = values.get(i);
j++;
}
}
 
if (foundCtrParameters < creator.parameters.size()) updateWithDefaultValues(creatorArgs, ctx.genson);
 
T bean = ofClass.cast(creator.create(creatorArgs));
for (int i = 0; i < size; i++) {
PropertyMutator property = mutableProperties.get(newNames[i]);
if (property != null) property.mutate(bean, newValues[i]);
}
reader.endObject();
return bean;
}
 
private void updateWithDefaultValues(Object[] creatorArgs, Genson genson) {
for (int i = 0; i < creatorArgs.length; i++) {
if (creatorArgs[i] == MISSING) {
for (BeanCreatorProperty property : creator.parameters.values()) {
if (property.index == i) {
creatorArgs[i] = genson.defaultValue(property.getRawClass());
break;
}
}
}
}
}
 
public Class<T> getOfClass() {
return ofClass;
}
 
private JsonBindingException missingPropertyException(String name) {
return new JsonBindingException("No matching property in " + getOfClass() + " for key " + name);
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/PropertyAccessor.java
New file
0,0 → 1,117
package com.owlike.genson.reflect;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
 
import com.owlike.genson.*;
import com.owlike.genson.stream.JsonWriter;
import com.owlike.genson.stream.ObjectWriter;
 
public abstract class PropertyAccessor extends BeanProperty implements Comparable<PropertyAccessor> {
Serializer<Object> propertySerializer;
private final char[] escapedName;
 
protected PropertyAccessor(String name, Type type, Class<?> declaringClass, Class<?> concreteClass,
Annotation[] annotations, int modifiers) {
super(name, type, declaringClass, concreteClass, annotations, modifiers);
escapedName = JsonWriter.escapeString(name);
}
 
public void serialize(Object propertySource, ObjectWriter writer, Context ctx) {
Object propertyValue = access(propertySource);
writer.writeEscapedName(escapedName);
try {
propertySerializer.serialize(propertyValue, writer, ctx);
} catch (Throwable th) {
throw couldNotSerialize(th);
}
}
 
public abstract Object access(final Object target);
 
public int compareTo(PropertyAccessor o) {
return o.priority() - priority();
}
 
protected JsonBindingException couldNotAccess(Exception e) {
return new JsonBindingException("Could not access value of property named '"
+ name + "' using accessor " + signature() + " from class "
+ declaringClass.getName(), e);
}
 
protected JsonBindingException couldNotSerialize(Throwable e) {
return new JsonBindingException("Could not serialize property '" + name
+ "' from class " + declaringClass.getName(), e);
}
 
public static class MethodAccessor extends PropertyAccessor {
protected final Method _getter;
 
public MethodAccessor(String name, Method getter, Type type, Class<?> concreteClass) {
super(name, type, getter.getDeclaringClass(), concreteClass, getter.getAnnotations(), getter.getModifiers());
this._getter = getter;
if (!_getter.isAccessible()) {
_getter.setAccessible(true);
}
}
 
@Override
public Object access(final Object target) {
try {
return _getter.invoke(target);
} catch (IllegalArgumentException e) {
throw couldNotAccess(e);
} catch (IllegalAccessException e) {
throw couldNotAccess(e);
} catch (InvocationTargetException e) {
throw couldNotAccess(e);
}
}
 
@Override
String signature() {
return _getter.toGenericString();
}
 
@Override
int priority() {
return 100;
}
}
 
public static class FieldAccessor extends PropertyAccessor {
protected final Field _field;
 
public FieldAccessor(String name, Field field, Type type, Class<?> concreteClass) {
super(name, type, field.getDeclaringClass(), concreteClass, field.getAnnotations(), field.getModifiers());
this._field = field;
if (!_field.isAccessible()) {
_field.setAccessible(true);
}
}
 
@Override
public Object access(final Object target) {
try {
return _field.get(target);
} catch (IllegalArgumentException e) {
throw couldNotAccess(e);
} catch (IllegalAccessException e) {
throw couldNotAccess(e);
}
}
 
@Override
public String signature() {
return _field.toGenericString();
}
 
@Override
public int priority() {
return 50;
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/PropertyNameResolver.java
New file
0,0 → 1,195
package com.owlike.genson.reflect;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
 
import com.owlike.genson.annotation.JsonProperty;
 
/**
* This interface is intended to be implemented by classes who want to change the way genson does
* name resolution. The resolved name will be used in the generated stream during serialization and
* injected into constructors/or setters during deserialization. If you can not resolve the name
* just return null. You can have a look at the <a href=
* "http://code.google.com/p/genson/source/browse/src/main/java/com/owlike/genson/reflect/PropertyNameResolver.java"
* >source code</a> for an example.
*
* @author eugen
* @see com.owlike.genson.annotation.JsonProperty JsonProperty
*/
public interface PropertyNameResolver {
/**
* Resolve the parameter name on position parameterIdx in the constructor fromConstructor.
*
* @param parameterIdx
* @param fromConstructor
* @return the resolved name of the parameter or null
*/
public String resolve(int parameterIdx, Constructor<?> fromConstructor);
 
/**
* Resolve the name of the parameter with parameterIdx as index in fromMethod method.
*
* @param parameterIdx
* @param fromMethod
* @return the resolved name of the parameter or null
*/
public String resolve(int parameterIdx, Method fromMethod);
 
/**
* Resolve the property name from this field.
*
* @param fromField - the field to use for name resolution.
* @return the resolved name or null.
*/
public String resolve(Field fromField);
 
/**
* Resolve the property name from this method.
*
* @param fromMethod - the method to be used for name resolution.
* @return the resolved name or null.
*/
public String resolve(Method fromMethod);
 
public static class CompositePropertyNameResolver implements PropertyNameResolver {
private List<PropertyNameResolver> components;
 
public CompositePropertyNameResolver(List<PropertyNameResolver> components) {
if (components == null || components.isEmpty()) {
throw new IllegalArgumentException(
"The composite resolver must have at least one resolver as component!");
}
this.components = new LinkedList<PropertyNameResolver>(components);
}
 
public CompositePropertyNameResolver add(PropertyNameResolver... resolvers) {
// should at the head position so custom resolvers a privileged
components.addAll(0, Arrays.asList(resolvers));
return this;
}
 
public String resolve(int parameterIdx, Constructor<?> fromConstructor) {
String resolvedName = null;
for (Iterator<PropertyNameResolver> it = components.iterator(); resolvedName == null
&& it.hasNext(); ) {
resolvedName = it.next().resolve(parameterIdx, fromConstructor);
}
return resolvedName;
}
 
public String resolve(int parameterIdx, Method fromMethod) {
String resolvedName = null;
for (Iterator<PropertyNameResolver> it = components.iterator(); resolvedName == null
&& it.hasNext(); ) {
resolvedName = it.next().resolve(parameterIdx, fromMethod);
}
return resolvedName;
}
 
public String resolve(Field fromField) {
String resolvedName = null;
for (Iterator<PropertyNameResolver> it = components.iterator(); resolvedName == null
&& it.hasNext(); ) {
resolvedName = it.next().resolve(fromField);
}
return resolvedName;
}
 
public String resolve(Method fromMethod) {
String resolvedName = null;
for (Iterator<PropertyNameResolver> it = components.iterator(); resolvedName == null
&& it.hasNext(); ) {
resolvedName = it.next().resolve(fromMethod);
}
return resolvedName;
}
 
}
 
public static class ConventionalBeanPropertyNameResolver implements PropertyNameResolver {
 
public String resolve(int parameterIdx, Constructor<?> fromConstructor) {
return null;
}
 
public String resolve(Field fromField) {
return fromField.getName();
}
 
public String resolve(Method fromMethod) {
String name = fromMethod.getName();
int length = -1;
 
if (name.startsWith("get"))
length = 3;
else if (name.startsWith("is"))
length = 2;
else if (name.startsWith("set"))
length = 3;
 
if (length > -1 && length < name.length()) {
return Character.toLowerCase(name.charAt(length)) + name.substring(length + 1);
} else
return null;
}
 
public String resolve(int parameterIdx, Method fromMethod) {
return null;
}
 
}
 
/**
* JsonProperty resolver based on @JsonProperty annotation. Can be used on fields, methods and
* constructor parameters.
*/
public static class AnnotationPropertyNameResolver implements PropertyNameResolver {
public AnnotationPropertyNameResolver() {
}
 
public String resolve(int parameterIdx, Constructor<?> fromConstructor) {
Annotation[] paramAnns = fromConstructor.getParameterAnnotations()[parameterIdx];
String name = null;
for (int j = 0; j < paramAnns.length; j++) {
if (paramAnns[j] instanceof JsonProperty) {
name = ((JsonProperty) paramAnns[j]).value();
break;
}
}
return "".equals(name) ? null : name;
}
 
public String resolve(int parameterIdx, Method fromMethod) {
Annotation[] anns = fromMethod.getParameterAnnotations()[parameterIdx];
String name = null;
for (Annotation ann : anns) {
if (ann instanceof JsonProperty) {
name = ((JsonProperty) ann).value();
break;
}
}
return "".equals(name) ? null : name;
}
 
public String resolve(Field fromField) {
return getName(fromField);
}
 
public String resolve(Method fromMethod) {
return getName(fromMethod);
}
 
protected String getName(AnnotatedElement annElement) {
JsonProperty name = annElement.getAnnotation(JsonProperty.class);
return name != null && name.value() != null && !name.value().isEmpty() ? name.value()
: null;
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/BaseBeanDescriptorProvider.java
New file
0,0 → 1,346
package com.owlike.genson.reflect;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
 
import com.owlike.genson.Genson;
import com.owlike.genson.annotation.JsonCreator;
import com.owlike.genson.reflect.BeanCreator.BeanCreatorProperty;
 
import static com.owlike.genson.reflect.TypeUtil.*;
import static com.owlike.genson.Trilean.*;
 
/**
* Standard implementation of AbstractBeanDescriptorProvider that uses
* {@link BeanMutatorAccessorResolver} and {@link PropertyNameResolver}. If you want to change the
* way BeanDescriptors are created you can subclass this class and override the needed methods. If
* you only want to create instances of your own PropertyMutators/PropertyAccessors or BeanCreators
* just override the corresponding createXXX methods.
*
* @author eugen
*/
public class BaseBeanDescriptorProvider extends AbstractBeanDescriptorProvider {
 
private final static Comparator<BeanCreator> _beanCreatorsComparator = new Comparator<BeanCreator>() {
public int compare(BeanCreator o1, BeanCreator o2) {
return o1.parameters.size() - o2.parameters.size();
}
};
 
private final BeanPropertyFactory propertyFactory;
protected final BeanMutatorAccessorResolver mutatorAccessorResolver;
protected final PropertyNameResolver nameResolver;
protected final boolean useGettersAndSetters;
protected final boolean useFields;
protected final boolean favorEmptyCreators;
 
public BaseBeanDescriptorProvider(ContextualConverterFactory ctxConverterFactory, BeanPropertyFactory propertyFactory,
BeanMutatorAccessorResolver mutatorAccessorResolver, PropertyNameResolver nameResolver,
boolean useGettersAndSetters, boolean useFields, boolean favorEmptyCreators) {
super(ctxConverterFactory);
 
if (mutatorAccessorResolver == null)
throw new IllegalArgumentException("mutatorAccessorResolver must be not null!");
if (nameResolver == null)
throw new IllegalArgumentException("nameResolver must be not null!");
if (propertyFactory == null)
throw new IllegalArgumentException("propertyFactory must be not null!");
 
this.propertyFactory = propertyFactory;
this.mutatorAccessorResolver = mutatorAccessorResolver;
this.nameResolver = nameResolver;
this.useFields = useFields;
this.useGettersAndSetters = useGettersAndSetters;
if (!useFields && !useGettersAndSetters)
throw new IllegalArgumentException("You must allow at least one mode: with fields or methods.");
this.favorEmptyCreators = favorEmptyCreators;
}
 
@Override
public List<BeanCreator> provideBeanCreators(Type ofType, Genson genson) {
List<BeanCreator> creators = new ArrayList<BeanCreator>();
Class<?> ofClass = getRawClass(ofType);
if (ofClass.isMemberClass() && (ofClass.getModifiers() & Modifier.STATIC) == 0)
return creators;
 
provideConstructorCreators(ofType, creators, genson);
for (Class<?> clazz = ofClass; clazz != null && !Object.class.equals(clazz); clazz = clazz
.getSuperclass()) {
provideMethodCreators(clazz, creators, ofType, genson);
}
return creators;
}
 
@Override
public void provideBeanPropertyAccessors(Type ofType,
Map<String, LinkedList<PropertyAccessor>> accessorsMap, Genson genson) {
ArrayDeque<Class<?>> classesToInspect = new ArrayDeque<Class<?>>();
classesToInspect.push(getRawClass(ofType));
while (!classesToInspect.isEmpty()) {
Class<?> clazz = classesToInspect.pop();
if (clazz.getSuperclass() != null && clazz.getSuperclass() != Object.class) {
classesToInspect.push(clazz.getSuperclass());
}
for (Class<?> anInterface : clazz.getInterfaces()) classesToInspect.push(anInterface);
 
// first lookup for fields
if (useFields) provideFieldAccessors(clazz, accessorsMap, ofType, genson);
// and now search methods (getters)
if (useGettersAndSetters) provideMethodAccessors(clazz, accessorsMap, ofType, genson);
}
}
 
@Override
public void provideBeanPropertyMutators(Type ofType,
Map<String, LinkedList<PropertyMutator>> mutatorsMap, Genson genson) {
ArrayDeque<Class<?>> classesToInspect = new ArrayDeque<Class<?>>();
classesToInspect.push(getRawClass(ofType));
while (!classesToInspect.isEmpty()) {
Class<?> clazz = classesToInspect.pop();
if (clazz.getSuperclass() != null && clazz.getSuperclass() != Object.class) {
classesToInspect.push(clazz.getSuperclass());
}
for (Class<?> anInterface : clazz.getInterfaces()) classesToInspect.push(anInterface);
 
// first lookup for fields
if (useFields) provideFieldMutators(clazz, mutatorsMap, ofType, genson);
// and now search methods (getters)
if (useGettersAndSetters) provideMethodMutators(clazz, mutatorsMap, ofType, genson);
}
}
 
protected void provideConstructorCreators(Type ofType, List<BeanCreator> creators, Genson genson) {
Class<?> ofClass = getRawClass(ofType);
Constructor<?>[] ctrs = ofClass.getDeclaredConstructors();
for (Constructor<?> ctr : ctrs) {
if (TRUE == mutatorAccessorResolver.isCreator(ctr, ofClass)) {
Type[] parameterTypes = ctr.getGenericParameterTypes();
int paramCnt = parameterTypes.length;
String[] parameterNames = new String[paramCnt];
int idx = 0;
for (; idx < paramCnt; idx++) {
String name = nameResolver.resolve(idx, ctr);
if (name == null) break;
parameterNames[idx] = name;
}
 
if (idx == paramCnt) {
BeanCreator creator = propertyFactory.createCreator(ofType, ctr, parameterNames, genson);
creators.add(creator);
}
}
}
}
 
protected void provideMethodCreators(Class<?> ofClass, List<BeanCreator> creators, Type ofType,
Genson genson) {
Method[] ctrs = ofClass.getDeclaredMethods();
for (Method ctr : ctrs) {
if (TRUE == mutatorAccessorResolver.isCreator(ctr, getRawClass(ofType))) {
Type[] parameterTypes = ctr.getGenericParameterTypes();
int paramCnt = parameterTypes.length;
String[] parameterNames = new String[paramCnt];
int idx = 0;
for (; idx < paramCnt; idx++) {
String name = nameResolver.resolve(idx, ctr);
if (name == null) break;
parameterNames[idx] = name;
}
 
if (idx == paramCnt) {
BeanCreator creator = propertyFactory.createCreator(ofType, ctr, parameterNames, genson);
creators.add(creator);
}
}
}
}
 
protected void provideFieldAccessors(Class<?> ofClass,
Map<String, LinkedList<PropertyAccessor>> accessorsMap, Type ofType, Genson genson) {
Field[] fields = ofClass.getDeclaredFields();
for (Field field : fields) {
if (TRUE == mutatorAccessorResolver.isAccessor(field, getRawClass(ofType))) {
String name = nameResolver.resolve(field);
if (name == null) {
throw new IllegalStateException("Field '" + field.getName() + "' from class "
+ ofClass.getName()
+ " has been discovered as accessor but its name couldn't be resolved!");
}
PropertyAccessor accessor = propertyFactory.createAccessor(name, field, ofType, genson);
update(accessor, accessorsMap);
}
}
}
 
protected void provideMethodAccessors(Class<?> ofClass,
Map<String, LinkedList<PropertyAccessor>> accessorsMap, Type ofType, Genson genson) {
Method[] methods = ofClass.getDeclaredMethods();
for (Method method : methods) {
if (TRUE == mutatorAccessorResolver.isAccessor(method, getRawClass(ofType))) {
String name = nameResolver.resolve(method);
if (name == null) {
throw new IllegalStateException("Method '" + method.getName() + "' from class "
+ ofClass.getName()
+ " has been discovered as accessor but its name couldn't be resolved!");
}
PropertyAccessor accessor = propertyFactory.createAccessor(name, method, ofType, genson);
update(accessor, accessorsMap);
}
}
}
 
protected void provideFieldMutators(Class<?> ofClass,
Map<String, LinkedList<PropertyMutator>> mutatorsMap, Type ofType, Genson genson) {
Field[] fields = ofClass.getDeclaredFields();
for (Field field : fields) {
if (TRUE == mutatorAccessorResolver.isMutator(field, getRawClass(ofType))) {
String name = nameResolver.resolve(field);
if (name == null) {
throw new IllegalStateException("Field '" + field.getName() + "' from class "
+ ofClass.getName()
+ " has been discovered as mutator but its name couldn't be resolved!");
}
 
PropertyMutator mutator = propertyFactory.createMutator(name, field, ofType, genson);
update(mutator, mutatorsMap);
}
}
}
 
protected void provideMethodMutators(Class<?> ofClass,
Map<String, LinkedList<PropertyMutator>> mutatorsMap, Type ofType, Genson genson) {
Method[] methods = ofClass.getDeclaredMethods();
for (Method method : methods) {
if (TRUE == mutatorAccessorResolver.isMutator(method, getRawClass(ofType))) {
String name = nameResolver.resolve(method);
if (name == null) {
throw new IllegalStateException("Method '" + method.getName() + "' from class "
+ ofClass.getName()
+ " has been discovered as mutator but its name couldn't be resolved!");
}
PropertyMutator mutator = propertyFactory.createMutator(name, method, ofType, genson);
update(mutator, mutatorsMap);
}
}
}
 
protected <T extends BeanProperty> void update(T property, Map<String, LinkedList<T>> map) {
LinkedList<T> accessors = map.get(property.name);
if (accessors == null) {
accessors = new LinkedList<T>();
map.put(property.name, accessors);
}
accessors.add(property);
}
 
@Override
protected BeanCreator checkAndMerge(Type ofType, List<BeanCreator> creators) {
Class<?> ofClass = getRawClass(ofType);
// hum maybe do not check this case as we may have class that will only be serialized so
// they do not need a ctr?
// if (creators == null || creators.isEmpty())
// throw new IllegalStateException("Could not create BeanDescriptor for type "
// + ofClass.getName() + ", no creator has been found.");
if (creators == null || creators.isEmpty()) return null;
 
// now lets do the merge
if (favorEmptyCreators) {
Collections.sort(creators, _beanCreatorsComparator);
}
 
boolean hasCreatorAnnotation = false;
BeanCreator creator = null;
 
// first lets do some checks
for (int i = 0; i < creators.size(); i++) {
BeanCreator ctr = creators.get(i);
if (ctr.isAnnotationPresent(JsonCreator.class)) {
if (!hasCreatorAnnotation)
hasCreatorAnnotation = true;
else
_throwCouldCreateBeanDescriptor(ofClass,
" only one @JsonCreator annotation per class is allowed.");
}
}
 
if (hasCreatorAnnotation) {
for (BeanCreator ctr : creators)
if (ctr.isAnnotationPresent(JsonCreator.class)) return ctr;
} else {
creator = creators.get(0);
}
 
return creator;
}
 
protected void _throwCouldCreateBeanDescriptor(Class<?> ofClass, String reason) {
throw new IllegalStateException("Could not create BeanDescriptor for type "
+ ofClass.getName() + "," + reason);
}
 
@Override
protected PropertyAccessor checkAndMergeAccessors(String name,
LinkedList<PropertyAccessor> accessors) {
PropertyAccessor accessor = _mostSpecificPropertyDeclaringClass(name, accessors);
return VisibilityFilter.ABSTRACT.isVisible(accessor.getModifiers()) ? accessor : null;
}
 
@Override
protected PropertyMutator checkAndMergeMutators(String name,
LinkedList<PropertyMutator> mutators) {
PropertyMutator mutator = _mostSpecificPropertyDeclaringClass(name, mutators);
return VisibilityFilter.ABSTRACT.isVisible(mutator.getModifiers()) ? mutator : null;
}
 
protected <T extends BeanProperty> T _mostSpecificPropertyDeclaringClass(String name,
LinkedList<T> properties) {
Iterator<T> it = properties.iterator();
T property = it.next();
for (; it.hasNext(); ) {
T next = it.next();
// Doesn't matter which one will be used, we want to merge the metadata
next.updateBoth(property);
// 1 we search the most specialized class containing this property
// with highest priority
if ((property.declaringClass.equals(next.declaringClass) && property.priority() < next.priority())
|| property.declaringClass.isAssignableFrom(next.declaringClass)) {
property = next;
} else continue;
}
 
return property;
}
 
@Override
protected void mergeMutatorsWithCreatorProperties(Type ofType, Map<String, PropertyMutator> mutators, BeanCreator creator) {
 
for (Map.Entry<String, ? extends BeanCreatorProperty> entry : creator.parameters.entrySet()) {
PropertyMutator muta = mutators.get(entry.getKey());
if (muta == null) {
// add to mutators only creator properties that don't exist as standard
// mutator (dont exist as field or method, but only as ctr arg)
BeanCreatorProperty ctrProperty = entry.getValue();
mutators.put(entry.getKey(), ctrProperty);
} else {
// update the creator property annotations with mutator annotations and vice versa
entry.getValue().updateBoth(muta);
}
}
}
 
@Override
protected void mergeAccessorsWithCreatorProperties(Type ofType, List<PropertyAccessor> accessors, BeanCreator creator) {
// do nothing
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/BeanProperty.java
New file
0,0 → 1,110
package com.owlike.genson.reflect;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
 
import com.owlike.genson.annotation.JsonProperty;
 
/**
* Represents a bean property, in practice it can be an object field, method (getter/setter) or
* constructor parameter.
*
* @author eugen
*/
public abstract class BeanProperty {
protected final String name;
protected final Type type;
protected final Class<?> declaringClass;
protected final Class<?> concreteClass;
protected Annotation[] annotations;
protected final int modifiers;
 
protected BeanProperty(String name, Type type, Class<?> declaringClass,
Class<?> concreteClass, Annotation[] annotations, int modifiers) {
this.name = name;
this.type = type;
this.declaringClass = declaringClass;
this.concreteClass = concreteClass;
this.annotations = annotations;
this.modifiers = modifiers;
}
 
/**
* @return The class in which this property is declared
*/
public Class<?> getDeclaringClass() {
return declaringClass;
}
 
/**
* @return The final concrete class from which this property has been resolved.
* For example if this property is defined in class Root but was resolved for class Child extends Root,
* then getConcreteClass would return Child class and getDeclaringClass would return Root class.
*/
public Class<?> getConcreteClass() { return concreteClass; }
 
/**
* The name of this property (not necessarily the original one).
*/
public String getName() {
return name;
}
 
/**
* @return the type of the property
*/
public Type getType() {
return type;
}
 
public Class<?> getRawClass() {
return TypeUtil.getRawClass(type);
}
 
public int getModifiers() {
return modifiers;
}
 
public String[] aliases() {
JsonProperty ann = getAnnotation(JsonProperty.class);
return ann != null ? ann.aliases() : new String[]{};
}
 
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
for (Annotation ann : annotations)
if (annotationClass.isInstance(ann)) return annotationClass.cast(ann);
return null;
}
 
void updateBoth(BeanProperty otherBeanProperty) {
 
// FIXME: we don't care for duplicate annotations as it should not change the behaviour - actually we do as it can change the behaviour...
// an easy solution would be to forbid duplicate annotations, which can make sense.
if (annotations.length > 0 || otherBeanProperty.annotations.length > 0) {
Annotation[] mergedAnnotations = new Annotation[annotations.length + otherBeanProperty.annotations.length];
 
System.arraycopy(annotations, 0, mergedAnnotations, 0, annotations.length);
System.arraycopy(otherBeanProperty.annotations, 0, mergedAnnotations, annotations.length, otherBeanProperty.annotations.length);
 
if (otherBeanProperty.annotations.length > 0) this.annotations = mergedAnnotations;
// update also the other bean property with the merged result.
// This is easier rather than do it in one direction and then in the other one.
if (annotations.length > 0) otherBeanProperty.annotations = mergedAnnotations;
}
}
 
/**
* Used to give priority to implementations, for example by default a method would have a higher
* priority than a field because it can do some logic. The greater the priority value is the
* more important is this BeanProperty.
*
* @return the priority of this BeanProperty
*/
abstract int priority();
 
abstract String signature();
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/BeanViewDescriptorProvider.java
New file
0,0 → 1,269
package com.owlike.genson.reflect;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
import static com.owlike.genson.Trilean.FALSE;
import static com.owlike.genson.Trilean.TRUE;
import static com.owlike.genson.reflect.TypeUtil.*;
 
import com.owlike.genson.*;
import com.owlike.genson.annotation.JsonCreator;
import com.owlike.genson.reflect.PropertyAccessor.MethodAccessor;
import com.owlike.genson.reflect.PropertyMutator.MethodMutator;
 
/**
* This class constructs BeanDescriptors for the {@link com.owlike.genson.BeanView BeanView}
* mechanism. This class is mainly intended for internal use. It can be directly used if needed to
* get a BeanDescriptor instance for a BeanView (for example if you want to deserialize into an
* existing object and apply a BeanView). Extending BeanViewDescriptorProvider should be avoided.
*
* @author eugen
*/
public class BeanViewDescriptorProvider extends BaseBeanDescriptorProvider {
 
private Map<Class<?>, BeanView<?>> views;
private Map<Class<?>, BeanDescriptor<?>> descriptors = new ConcurrentHashMap<Class<?>, BeanDescriptor<?>>();
 
public BeanViewDescriptorProvider(ContextualConverterFactory ctxConverterFactory,
Map<Class<?>, BeanView<?>> views, BeanPropertyFactory propertyFactory,
BeanMutatorAccessorResolver mutatorAccessorResolver,
PropertyNameResolver nameResolver) {
super(ctxConverterFactory, propertyFactory, mutatorAccessorResolver, nameResolver, true, false, true);
this.views = views;
}
 
@SuppressWarnings("unchecked")
@Override
public <T> BeanDescriptor<T> provide(Class<T> ofClass,
Type ofType, Genson genson) {
Class<?> rawClass = getRawClass(ofType);
if (!BeanView.class.isAssignableFrom(rawClass))
throw new IllegalArgumentException("Expected argument of type "
+ BeanView.class.getName() + " but provided " + rawClass);
 
BeanDescriptor<T> descriptor = (BeanDescriptor<T>) descriptors.get(rawClass);
if (descriptor == null) {
Class<?> parameterizedTypeForBeanView =
getRawClass(expandType(BeanView.class.getTypeParameters()[0], ofType));
if (!ofClass.isAssignableFrom(parameterizedTypeForBeanView)) {
throw new IllegalArgumentException(
"Expected type for ofClass parameter is " + parameterizedTypeForBeanView
+ " but provided is " + ofClass);
}
 
try {
if (!views.containsKey(rawClass)) {
Constructor<BeanView<T>> ctr =
(Constructor<BeanView<T>>) rawClass.getDeclaredConstructor();
if (!ctr.isAccessible()) ctr.setAccessible(true);
views.put(rawClass, ctr.newInstance());
}
descriptor = super.provide(ofClass, ofType, genson);
descriptors.put(rawClass, descriptor);
} catch (SecurityException e) {
throw couldNotInstantiateBeanView(ofClass, e);
} catch (NoSuchMethodException e) {
throw couldNotInstantiateBeanView(ofClass, e);
} catch (IllegalArgumentException e) {
throw couldNotInstantiateBeanView(ofClass, e);
} catch (InstantiationException e) {
throw couldNotInstantiateBeanView(ofClass, e);
} catch (IllegalAccessException e) {
throw couldNotInstantiateBeanView(ofClass, e);
} catch (InvocationTargetException e) {
throw couldNotInstantiateBeanView(ofClass, e);
}
}
return descriptor;
}
 
private JsonBindingException couldNotInstantiateBeanView(Class<?> beanViewClass,
Exception e) {
return new JsonBindingException("Could not instantiate BeanView "
+ beanViewClass.getName()
+ ", BeanView implementations must have a public no arg constructor.", e);
}
 
@Override
public List<BeanCreator> provideBeanCreators(Type ofType, Genson genson) {
List<BeanCreator> creators = new ArrayList<BeanCreator>();
for (Class<?> clazz = getRawClass(ofType); clazz != null && !Object.class.equals(clazz); clazz =
clazz.getSuperclass()) {
provideMethodCreators(clazz, creators, ofType, genson);
}
Type viewForType = TypeUtil.expandType(BeanView.class.getTypeParameters()[0], ofType);
List<BeanCreator> oCtrs = super.provideBeanCreators(viewForType, genson);
creators.addAll(oCtrs);
return creators;
}
 
public static class BeanViewPropertyFactory implements BeanPropertyFactory {
private final Map<Class<?>, BeanView<?>> views;
 
public BeanViewPropertyFactory(Map<Class<?>, BeanView<?>> views) {
this.views = views;
}
 
public PropertyAccessor createAccessor(String name, Method method, Type ofType,
Genson genson) {
// the target bean must be first (and single) parameter for beanview accessors
BeanView<?> beanview = views.get(getRawClass(ofType));
if (beanview != null) {
Type superTypeWithParameter =
TypeUtil.lookupGenericType(BeanView.class, beanview.getClass());
Class<?> tClass =
getRawClass(typeOf(0,
expandType(superTypeWithParameter, beanview.getClass())));
Type type = expandType(method.getGenericReturnType(), ofType);
return new BeanViewPropertyAccessor(name, method, type, beanview, tClass);
} else return null;
}
 
public PropertyMutator createMutator(String name, Method method, Type ofType, Genson genson) {
// the target bean must be second parameter for beanview mutators
BeanView<?> beanview = views.get(getRawClass(ofType));
if (beanview != null) {
Type superTypeWithParameter =
TypeUtil.lookupGenericType(BeanView.class, beanview.getClass());
Class<?> tClass =
getRawClass(typeOf(0,
expandType(superTypeWithParameter, beanview.getClass())));
Type type = expandType(method.getGenericParameterTypes()[0], ofType);
return new BeanViewPropertyMutator(name, method, type, beanview, tClass);
} else return null;
}
 
@Override
public PropertyAccessor createAccessor(String name, Field field, Type ofType,
Genson genson) {
return null;
}
 
@Override
public BeanCreator createCreator(Type ofType, Constructor<?> ctr,
String[] resolvedNames, Genson genson) {
return null;
}
 
@Override
public BeanCreator createCreator(Type ofType, Method method,
String[] resolvedNames, Genson genson) {
return null;
}
 
@Override
public PropertyMutator createMutator(String name, Field field, Type ofType,
Genson genson) {
return null;
}
}
 
public static class BeanViewMutatorAccessorResolver implements BeanMutatorAccessorResolver {
 
public Trilean isAccessor(Field field, Class<?> baseClass) {
return FALSE;
}
 
public Trilean isAccessor(Method method, Class<?> baseClass) {
Type expectedType = TypeUtil.lookupGenericType(BeanView.class, baseClass);
expectedType = TypeUtil.expandType(expectedType, baseClass);
expectedType = TypeUtil.typeOf(0, expectedType);
int modifiers = method.getModifiers();
return Trilean.valueOf((method.getName().startsWith("get") || (method.getName()
.startsWith("is") && (TypeUtil.match(method.getGenericReturnType(),
Boolean.class, false) || boolean.class.equals(method.getReturnType()))))
&& TypeUtil.match(expectedType, method.getGenericParameterTypes()[0], false)
&& Modifier.isPublic(modifiers)
&& !Modifier.isAbstract(modifiers)
&& !Modifier.isNative(modifiers));
}
 
public Trilean isCreator(Constructor<?> constructor, Class<?> baseClass) {
int modifier = constructor.getModifiers();
return Trilean.valueOf(Modifier.isPublic(modifier)
|| !(Modifier.isPrivate(modifier) || Modifier.isProtected(modifier)));
}
 
public Trilean isCreator(Method method, Class<?> baseClass) {
if (method.getAnnotation(JsonCreator.class) != null) {
if (Modifier.isStatic(method.getModifiers())) return TRUE;
throw new JsonBindingException("Method " + method.toGenericString()
+ " annotated with @Creator must be static!");
}
return FALSE;
}
 
public Trilean isMutator(Field field, Class<?> baseClass) {
return FALSE;
}
 
public Trilean isMutator(Method method, Class<?> baseClass) {
Type expectedType = TypeUtil.lookupGenericType(BeanView.class, baseClass);
expectedType = TypeUtil.expandType(expectedType, baseClass);
expectedType = TypeUtil.typeOf(0, expectedType);
int modifiers = method.getModifiers();
return Trilean.valueOf(method.getName().startsWith("set")
&& void.class.equals(method.getReturnType())
&& method.getGenericParameterTypes().length == 2
&& TypeUtil.match(expectedType, method.getGenericParameterTypes()[1], false)
&& Modifier.isPublic(modifiers) && !Modifier.isAbstract(modifiers)
&& !Modifier.isNative(modifiers));
}
 
}
 
private static class BeanViewPropertyAccessor extends MethodAccessor {
private final BeanView<?> _view;
 
public BeanViewPropertyAccessor(String name, Method getter, Type type, BeanView<?> target,
Class<?> tClass) {
super(name, getter, type, tClass);
this._view = target;
}
 
@Override
public Object access(Object target) {
try {
return _getter.invoke(_view, target);
} catch (IllegalArgumentException e) {
throw couldNotAccess(e);
} catch (IllegalAccessException e) {
throw couldNotAccess(e);
} catch (InvocationTargetException e) {
throw couldNotAccess(e);
}
}
}
 
private static class BeanViewPropertyMutator extends MethodMutator {
private final BeanView<?> _view;
 
public BeanViewPropertyMutator(String name, Method setter, Type type, BeanView<?> target,
Class<?> tClass) {
super(name, setter, type, tClass);
this._view = target;
}
 
@Override
public void mutate(Object target, Object value) {
try {
_setter.invoke(_view, value, target);
} catch (IllegalArgumentException e) {
throw couldNotMutate(e);
} catch (IllegalAccessException e) {
throw couldNotMutate(e);
} catch (InvocationTargetException e) {
throw couldNotMutate(e);
}
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/BeanDescriptorProvider.java
New file
0,0 → 1,70
package com.owlike.genson.reflect;
 
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
 
import com.owlike.genson.Genson;
 
/**
* Interface implemented by classes who want to provide {@link BeanDescriptor} instances for the
* specified type.
*
* @author eugen
*/
public interface BeanDescriptorProvider {
/**
* Provides a BeanDescriptor for "type" using current Genson instance.
*
* @param type for which we need a BeanDescriptor.
* @param genson current instance.
* @return A BeanDescriptor instance able to serialize/deserialize objects of type T.
*/
public <T> BeanDescriptor<T> provide(Class<T> type, Genson genson);
 
/**
* Provides a BeanDescriptor that can serialize/deserialize "ofClass" type, based on "type"
* argument. The arguments "ofClass" and "type" will be the same in most cases, but for example
* in BeanViews ofClass will correspond to the parameterized type and "type" to the BeanView
* implementation.
*
* @param ofClass is the Class for which we need a BeanDescriptor that will be able to
* serialize/deserialize objects of that type;
* @param type to use to build this descriptor (use its declared methods, fields, etc).
* @param genson is the current Genson instance.
* @return A BeanDescriptor instance able to serialize/deserialize objects of type ofClass.
*/
public <T> BeanDescriptor<T> provide(Class<T> ofClass, Type type, Genson genson);
 
 
public static class CompositeBeanDescriptorProvider implements BeanDescriptorProvider {
private final List<BeanDescriptorProvider> providers;
 
private final ConcurrentHashMap<Type, BeanDescriptor<?>> cache = new ConcurrentHashMap<Type, BeanDescriptor<?>>();
 
public CompositeBeanDescriptorProvider(List<BeanDescriptorProvider> providers) {
this.providers = new ArrayList<BeanDescriptorProvider>(providers);
}
 
@Override
public <T> BeanDescriptor<T> provide(Class<T> ofClass, Genson genson) {
return provide(ofClass, ofClass, genson);
}
 
@Override
public <T> BeanDescriptor<T> provide(Class<T> ofClass, Type type, Genson genson) {
BeanDescriptor<T> desc = (BeanDescriptor<T>) cache.get(type);
if (desc == null) {
for (BeanDescriptorProvider provider : providers) {
desc = provider.provide(ofClass, type, genson);
if (desc != null) break;
}
 
cache.putIfAbsent(type, desc);
}
 
return desc;
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/TypeUtil.java
New file
0,0 → 1,600
package com.owlike.genson.reflect;
 
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
import com.owlike.genson.Operations;
 
/**
* This class provides utilities to work with java Types. Its main goal is to provide tools for working with generic
* types.
*
* @author eugen
*/
/*
* TODO ExpandedType do we need a reference to an original type?=> Not nice to provide 2
* implementations for ParameterizedType...
*/
public final class TypeUtil {
private final static Map<Class<?>, Class<?>> _wrappedPrimitives = new HashMap<Class<?>, Class<?>>();
 
static {
_wrappedPrimitives.put(int.class, Integer.class);
_wrappedPrimitives.put(double.class, Double.class);
_wrappedPrimitives.put(long.class, Long.class);
_wrappedPrimitives.put(float.class, Float.class);
_wrappedPrimitives.put(short.class, Short.class);
_wrappedPrimitives.put(boolean.class, Boolean.class);
_wrappedPrimitives.put(char.class, Character.class);
_wrappedPrimitives.put(byte.class, Byte.class);
_wrappedPrimitives.put(void.class, Void.class);
}
 
private final static Map<TypeAndRootClassKey, Type> _cache = new ConcurrentHashMap<TypeUtil.TypeAndRootClassKey, Type>(
32);
 
public final static Class<?> wrap(Class<?> clazz) {
Class<?> wrappedClass = _wrappedPrimitives.get(clazz);
return wrappedClass == null ? clazz : wrappedClass;
}
 
private final static ThreadLocal<Map<Type, Type>> _circularExpandedType = new ThreadLocal<Map<Type, Type>>();
 
/**
* Expands type in the type rootType to Class, ParameterizedType or GenericArrayType. Useful for generic types.
* rootType is used to get the specialization information for expansion.
*/
public final static Type expandType(final Type type, final Type rootType) {
/* TODO in case where it is a class we should maybe still try to expand it using rootType information?
* for example if I want to expand Map in rootType context Map<String, Integer>, actually this does not work.
* However such modification should be done with more care. Impacts on typeOf and lookUpGenericType, probably others too.
*/
if (type instanceof ExpandedType || type instanceof Class)
return type;
 
Map<Type, Type> circularTypes = _circularExpandedType.get();
if (circularTypes == null) {
circularTypes = new HashMap<Type, Type>();
_circularExpandedType.set(circularTypes);
}
 
// this allows to handle cyclic generic types (types that refer to them self)
if (circularTypes.containsKey(type)) {
return circularTypes.get(type);
} else {
try {
circularTypes.put(type, getRawClass(type));
TypeAndRootClassKey key = new TypeAndRootClassKey(type, rootType);
Type expandedType = _cache.get(key);
 
if (expandedType == null) {
if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
Type[] args = pType.getActualTypeArguments();
int len = args.length;
Type[] expandedArgs = new Type[len];
for (int i = 0; i < len; i++) {
expandedArgs[i] = expandType(args[i], rootType);
}
expandedType = new ExpandedParameterizedType(pType, getRawClass(rootType), expandedArgs);
} else if (type instanceof TypeVariable) {
@SuppressWarnings("unchecked")
TypeVariable<GenericDeclaration> tvType = (TypeVariable<GenericDeclaration>) type;
if (rootType instanceof ParameterizedType) {
ParameterizedType rootPType = (ParameterizedType) rootType;
Type[] typeArgs = rootPType.getActualTypeArguments();
String typeName = tvType.getName();
int idx = 0;
for (TypeVariable<?> parameter : genericDeclarationToClass(tvType.getGenericDeclaration())
.getTypeParameters()) {
if (typeName.equals(parameter.getName())) {
expandedType = typeArgs[idx];
break;
}
idx++;
}
} else
expandedType = resolveTypeVariable(tvType, getRawClass(rootType));
 
if (type == expandedType)
expandedType = expandType(tvType.getBounds()[0], rootType);
} else if (type instanceof GenericArrayType) {
GenericArrayType genArrType = (GenericArrayType) type;
Type cType = expandType(genArrType.getGenericComponentType(), rootType);
if (genArrType.getGenericComponentType() == cType)
cType = Object.class;
expandedType = new ExpandedGenericArrayType(genArrType, cType, getRawClass(rootType));
} else if (type instanceof WildcardType) {
WildcardType wType = (WildcardType) type;
// let's expand wildcards to their upper bound or object if no upper bound
// defined
// it will simplify things to accept only one upper bound and ignore lower
// bounds
// as it is equivalent to Object.
expandedType = wType.getUpperBounds().length > 0 ? expandType(wType.getUpperBounds()[0],
rootType) : Object.class;
}
 
if (expandedType == null)
throw new IllegalArgumentException("Type " + type + " not supported for expansion!");
 
_cache.put(key, expandedType);
}
 
return expandedType;
} finally {
circularTypes.remove(type);
}
}
}
 
/**
* Searches for ofClass in the inherited classes and interfaces of inClass. If ofClass has been found in the super
* classes/interfaces of inClass, then the generic type corresponding to inClass and its TypeVariables is returned,
* otherwise null. For example :
* <p/>
* <pre>
* abstract class MyClass implements Serializer&lt;Number&gt; {
*
* }
*
* // type value will be the parameterized type Serializer&lt;Number&gt;
* Type type = lookupGenericType(Serializer.class, MyClass.class);
* </pre>
*/
public final static Type lookupGenericType(Class<?> ofClass, Class<?> inClass) {
if (ofClass == null || inClass == null || !ofClass.isAssignableFrom(inClass))
return null;
if (ofClass.equals(inClass))
return inClass;
 
if (ofClass.isInterface()) {
// lets look if the interface is directly implemented by fromClass
Class<?>[] interfaces = inClass.getInterfaces();
 
for (int i = 0; i < interfaces.length; i++) {
// do they match?
if (ofClass.equals(interfaces[i])) {
return inClass.getGenericInterfaces()[i];
} else {
Type superType = lookupGenericType(ofClass, interfaces[i]);
if (superType != null)
return superType;
}
}
}
 
// ok it's not one of the directly implemented interfaces, lets try extended class
Class<?> superClass = inClass.getSuperclass();
if (ofClass.equals(superClass))
return inClass.getGenericSuperclass();
return lookupGenericType(ofClass, inClass.getSuperclass());
}
 
public final static Class<?> getRawClass(Type type) {
if (type instanceof Class<?>)
return (Class<?>) type;
else if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
return (Class<?>) pType.getRawType();
} else if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
return Array.newInstance(getRawClass(componentType), 0).getClass();
} else
return getRawClass(expand(type, null));
}
 
/**
* Returns the type of this Collection or Array.
*
* @throws IllegalArgumentException if type is not a Collection, not a generic array and not a primitive array.
*/
public final static Type getCollectionType(Type type) {
if (type instanceof GenericArrayType) {
return ((GenericArrayType) type).getGenericComponentType();
} else if (type instanceof Class<?>) {
Class<?> clazz = (Class<?>) type;
if (clazz.isArray())
return clazz.getComponentType();
else if (Collection.class.isAssignableFrom(clazz)) {
return Object.class;
}
} else if (type instanceof ParameterizedType && Collection.class.isAssignableFrom(getRawClass(type))) {
return typeOf(0, type);
}
 
throw new IllegalArgumentException(
"Could not extract parametrized type, are you sure it is a Collection or an Array?");
}
 
// protected for testing.
final static Type expand(Type type, Class<?> inClass) {
Type expandedType = null;
if (type instanceof TypeVariable) {
@SuppressWarnings("unchecked")
// for the moment we assume it is a class, we can later handle ctr and methods
TypeVariable<GenericDeclaration> tvType = (TypeVariable<GenericDeclaration>) type;
if (inClass == null)
inClass = genericDeclarationToClass(tvType.getGenericDeclaration());
expandedType = resolveTypeVariable(tvType, inClass);
if (type.equals(expandedType))
expandedType = tvType.getBounds()[0];
} else if (type instanceof WildcardType) {
WildcardType wType = (WildcardType) type;
expandedType = wType.getUpperBounds().length > 0 ? expand(wType.getUpperBounds()[0], inClass)
: Object.class;
} else
return type;
 
return expandedType == null || type.equals(expandedType) ? Object.class : expandedType;
}
 
/**
* Searches for the typevariable definition in the inClass hierarchy.
*
* @param type
* @param inClass
* @return the resolved type or type if unable to resolve it.
*/
public final static Type resolveTypeVariable(TypeVariable<? extends GenericDeclaration> type, Class<?> inClass) {
return resolveTypeVariable(type, genericDeclarationToClass(type.getGenericDeclaration()), inClass);
}
 
private final static Type resolveTypeVariable(TypeVariable<? extends GenericDeclaration> type,
Class<?> declaringClass, Class<?> inClass) {
 
if (inClass == null)
return null;
 
Class<?> superClass = null;
Type resolvedType = null;
Type genericSuperClass = null;
 
if (!declaringClass.equals(inClass)) {
if (declaringClass.isInterface()) {
// the declaringClass is an interface
Class<?>[] interfaces = inClass.getInterfaces();
for (int i = 0; i < interfaces.length && resolvedType == null; i++) {
superClass = interfaces[i];
resolvedType = resolveTypeVariable(type, declaringClass, superClass);
genericSuperClass = inClass.getGenericInterfaces()[i];
}
}
 
if (resolvedType == null) {
superClass = inClass.getSuperclass();
resolvedType = resolveTypeVariable(type, declaringClass, superClass);
genericSuperClass = inClass.getGenericSuperclass();
}
} else {
resolvedType = type;
genericSuperClass = superClass = inClass;
 
}
 
if (resolvedType != null) {
// if its another type this means we have finished
if (resolvedType instanceof TypeVariable<?>) {
type = (TypeVariable<?>) resolvedType;
TypeVariable<?>[] parameters = superClass.getTypeParameters();
int positionInClass = 0;
for (; positionInClass < parameters.length && !type.equals(parameters[positionInClass]); positionInClass++) {
}
 
// we located the position of the typevariable in the superclass
if (positionInClass < parameters.length) {
// let's look if we have type specialization information in the current class
if (genericSuperClass instanceof ParameterizedType) {
ParameterizedType pGenericType = (ParameterizedType) genericSuperClass;
Type[] args = pGenericType.getActualTypeArguments();
return positionInClass < args.length ? args[positionInClass] : null;
}
}
 
// we didnt find typevariable specialization in the class, so it's the best we can
// do, lets return the resolvedType...
}
}
 
return resolvedType;
}
 
/**
* Deep comparison between type and oType. If parameter strictMatch is true, then type and oType will be strictly
* compared otherwise this method checks whether oType is assignable from type.
*/
public final static boolean match(Type type, Type oType, boolean strictMatch) {
if (type == null || oType == null)
return type == null && oType == null;
Class<?> clazz = getRawClass(type);
Class<?> oClazz = getRawClass(oType);
boolean match = strictMatch ? oClazz.equals(clazz) : oClazz.isAssignableFrom(clazz);
 
if (Object.class.equals(oClazz) && !strictMatch)
return match;
 
if (clazz.isArray() && !oClazz.isArray())
return match;
 
Type[] types = getTypes(type);
Type[] oTypes = getTypes(oType);
 
match = match && (types.length == oTypes.length || types.length == 0);
 
for (int i = 0; i < types.length && match; i++)
match = match(types[i], oTypes[i], strictMatch);
 
return match;
}
 
/**
* Convenient method that returns the type of the parameter at position parameterIdx in the type fromType.
*
* @throws UnsupportedOperationException thrown if fromType is not a Class nor a ParameterizedType.
*/
public final static Type typeOf(int parameterIdx, Type fromType) {
if (fromType instanceof Class<?>) {
Class<?> tClass = (Class<?>) fromType;
TypeVariable<?>[] tvs = tClass.getTypeParameters();
if (tvs.length > parameterIdx)
return expandType(tvs[parameterIdx], fromType);
} else if (fromType instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) fromType;
Type[] ts = pType.getActualTypeArguments();
if (ts.length > parameterIdx)
return ts[parameterIdx];
}
throw new UnsupportedOperationException("Couldn't find parameter at " + parameterIdx + " from type " + fromType
+ " , you should first locate the parameterized type, expand it and then use typeOf.");
}
 
private static Class<?> genericDeclarationToClass(GenericDeclaration declaration) {
if (declaration instanceof Class)
return (Class<?>) declaration;
if (declaration instanceof Method)
return ((Method) declaration).getDeclaringClass();
if (declaration instanceof Constructor)
return ((Constructor<?>) declaration).getDeclaringClass();
throw new UnsupportedOperationException();
}
 
private final static Type[] getTypes(Type type) {
if (type instanceof Class) {
Class<?> tClass = (Class<?>) type;
if (tClass.isArray())
return new Type[]{tClass.getComponentType()};
else {
TypeVariable<?>[] tvs = ((Class<?>) type).getTypeParameters();
Type[] types = new Type[tvs.length];
int i = 0;
for (TypeVariable<?> tv : tvs) {
types[i++] = tv.getBounds()[0];
}
return types;
}
} else if (type instanceof ParameterizedType) {
return ((ParameterizedType) type).getActualTypeArguments();
} else if (type instanceof GenericArrayType) {
return new Type[]{((GenericArrayType) type).getGenericComponentType()};
} else if (type instanceof WildcardType) {
return Operations.union(Type[].class, ((WildcardType) type).getUpperBounds(),
((WildcardType) type).getLowerBounds());
} else if (type instanceof TypeVariable<?>) {
@SuppressWarnings("unchecked")
TypeVariable<Class<?>> tvType = (TypeVariable<Class<?>>) type;
Type resolvedType = resolveTypeVariable(tvType, tvType.getGenericDeclaration());
return tvType.equals(resolvedType) ? tvType.getBounds() : new Type[]{resolvedType};
} else
return new Type[0];
}
 
/*
* ExpandedType must implement hashcode and equals using only the original type
* The root class is not significant here as a type expanded in different root classes can yield to the same expanded type.
* Very important, hashcode and equals must also be implemented in subclasses and also use those from ExpandedType.
*
* http://code.google.com/p/genson/issues/detail?id=4
*/
private static abstract class ExpandedType<T extends Type> {
protected final T originalType;
protected final Class<?> rootClass;
private final int _hash;
 
private ExpandedType(T originalType, Class<?> rootClass) {
if (originalType == null || rootClass == null)
throw new IllegalArgumentException("Null arg not allowed!");
this.originalType = originalType;
this.rootClass = rootClass;
 
final int prime = 31;
int result = 1;
_hash = prime * result + ((originalType == null) ? 0 : originalType.hashCode());
}
 
@SuppressWarnings("unused")
public T getOriginalType() {
return originalType;
}
 
@SuppressWarnings("unused")
public Class<?> getRootClass() {
return rootClass;
}
 
@Override
public int hashCode() {
return _hash;
}
 
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
@SuppressWarnings("rawtypes")
ExpandedType other = (ExpandedType) obj;
if (originalType == null) {
if (other.originalType != null)
return false;
} else if (!originalType.equals(other.originalType))
return false;
return true;
}
}
 
/*
* http://code.google.com/p/genson/issues/detail?id=4
*/
private final static class ExpandedGenericArrayType extends ExpandedType<GenericArrayType> implements
GenericArrayType {
private final Type componentType;
private final int _hash;
 
public ExpandedGenericArrayType(GenericArrayType originalType, Type componentType, Class<?> rootClass) {
super(originalType, rootClass);
if (componentType == null)
throw new IllegalArgumentException("Null arg not allowed!");
this.componentType = componentType;
 
final int prime = 31;
int result = super.hashCode();
_hash = prime * result + ((componentType == null) ? 0 : componentType.hashCode());
}
 
public Type getGenericComponentType() {
return componentType;
}
 
@Override
public int hashCode() {
return _hash;
}
 
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
ExpandedGenericArrayType other = (ExpandedGenericArrayType) obj;
if (componentType == null) {
if (other.componentType != null)
return false;
} else if (!componentType.equals(other.componentType))
return false;
return true;
}
}
 
/*
* http://code.google.com/p/genson/issues/detail?id=4
*/
private final static class ExpandedParameterizedType extends ExpandedType<ParameterizedType> implements
ParameterizedType {
private final Type[] typeArgs;
private final int _hash;
 
public ExpandedParameterizedType(ParameterizedType originalType, Class<?> rootClass, Type[] typeArgs) {
super(originalType, rootClass);
if (typeArgs == null)
throw new IllegalArgumentException("Null arg not allowed!");
this.typeArgs = typeArgs;
 
final int prime = 31;
int result = super.hashCode();
_hash = prime * result + Arrays.hashCode(typeArgs);
}
 
public Type[] getActualTypeArguments() {
return typeArgs;
}
 
public Type getOwnerType() {
return originalType.getOwnerType();
}
 
public Type getRawType() {
return originalType.getRawType();
}
 
@Override
public int hashCode() {
return _hash;
}
 
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
ExpandedParameterizedType other = (ExpandedParameterizedType) obj;
if (!Arrays.equals(typeArgs, other.typeArgs))
return false;
return true;
}
}
 
/*
* No changes here, but it is important to keep using the rootType for computing the hashcode and equals
* as this is used to check if a type needs to be expanded or not. At that moment the type can be in its original form
* so yield to same types when it should be expanded.
*
* An alternative could be to remove the cashing from TypeUtil as anyway it is mainly used only during
* construction of Converters (that are cached). However this might decrease performances on android, where you might
* be more interested in one short ser/deser. Lets keep it like that for the moment.
*
* http://code.google.com/p/genson/issues/detail?id=4
*/
private final static class TypeAndRootClassKey {
private final Type type;
private final Type rootType;
private int _hash;
 
public TypeAndRootClassKey(Type type, Type rootType) {
super();
if (type == null || rootType == null)
throw new IllegalArgumentException("type and rootType must be not null!");
this.type = type;
this.rootType = rootType;
_hash = 31 + rootType.hashCode();
_hash = 31 + type.hashCode();
}
 
@Override
public int hashCode() {
return _hash;
}
 
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof TypeAndRootClassKey))
return false;
TypeAndRootClassKey other = (TypeAndRootClassKey) obj;
return rootType.equals(other.rootType) && type.equals(other.type);
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/package-info.java
New file
0,0 → 1,4
/**
* This package contains the core api providing databinding support for complex objects.
*/
package com.owlike.genson.reflect;
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/BeanCreator.java
New file
0,0 → 1,214
package com.owlike.genson.reflect;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
import com.owlike.genson.JsonBindingException;
import com.owlike.genson.Wrapper;
 
public abstract class BeanCreator extends Wrapper<AnnotatedElement> implements Comparable<BeanCreator> {
// The type of object it can create
protected final Class<?> ofClass;
protected final Map<String, BeanCreatorProperty> parameters;
protected final Map<String, BeanCreatorProperty> paramsAndAliases;
 
public BeanCreator(Class<?> ofClass, Class<?> declaringClass, Class<?> concreteClass,
String[] parameterNames, Type[] types, Annotation[][] anns) {
this.ofClass = ofClass;
this.parameters = new LinkedHashMap<String, BeanCreatorProperty>(parameterNames.length);
for (int i = 0; i < parameterNames.length; i++) {
this.parameters.put(parameterNames[i], new BeanCreatorProperty(parameterNames[i],
types[i], i, anns[i], declaringClass, concreteClass, this));
}
 
paramsAndAliases = new LinkedHashMap<String, BeanCreatorProperty>();
for (BeanCreatorProperty p : parameters.values()) {
paramsAndAliases.put(p.getName(), p);
for (String alias : p.aliases()) paramsAndAliases.put(alias, p);
}
}
 
public int contains(List<String> properties) {
int cnt = 0;
for (String prop : properties)
if (parameters.containsKey(prop)) cnt++;
return cnt;
}
 
public int compareTo(BeanCreator o) {
int comp = o.priority() - priority();
return comp != 0 ? comp : parameters.size() - o.parameters.size();
}
 
public abstract Object create(Object... args);
 
protected abstract String signature();
 
public abstract int priority();
 
protected JsonBindingException couldNotCreate(Exception e) {
return new JsonBindingException("Could not create bean of type " + ofClass.getName()
+ " using creator " + signature(), e);
}
 
public Map<String, BeanCreatorProperty> getProperties() {
return new LinkedHashMap<String, BeanCreatorProperty>(parameters);
}
 
public abstract int getModifiers();
 
public static class ConstructorBeanCreator extends BeanCreator {
protected final Constructor<?> constructor;
 
public ConstructorBeanCreator(Class<?> ofClass, Constructor<?> constructor,
String[] parameterNames, Type[] expandedParameterTypes) {
// We can use the same class, as anyway we don't want to use constructors
super(ofClass, ofClass, ofClass, parameterNames, expandedParameterTypes, constructor.getParameterAnnotations());
this.constructor = constructor;
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
decorate(constructor);
}
 
public Object create(Object... args) {
try {
return constructor.newInstance(args);
} catch (IllegalArgumentException e) {
throw couldNotCreate(e);
} catch (InstantiationException e) {
throw couldNotCreate(e);
} catch (IllegalAccessException e) {
throw couldNotCreate(e);
} catch (InvocationTargetException e) {
throw couldNotCreate(e);
}
}
 
@Override
protected String signature() {
return constructor.toGenericString();
}
 
@Override
public int priority() {
return 50;
}
 
@Override
public int getModifiers() {
return constructor.getModifiers();
}
}
 
public static class MethodBeanCreator extends BeanCreator {
protected final Method _creator;
 
public MethodBeanCreator(Method method, String[] parameterNames,
Type[] expandedParameterTypes, Class<?> concreteClass) {
super(method.getReturnType(), method.getDeclaringClass(), concreteClass, parameterNames,
expandedParameterTypes, method.getParameterAnnotations());
if (!Modifier.isStatic(method.getModifiers()))
throw new IllegalStateException("Only static methods can be used as creators!");
this._creator = method;
if (!_creator.isAccessible()) {
_creator.setAccessible(true);
}
decorate(_creator);
}
 
public Object create(Object... args) {
try {
// we will handle only static method creators
return ofClass.cast(_creator.invoke(null, args));
} catch (IllegalArgumentException e) {
throw couldNotCreate(e);
} catch (IllegalAccessException e) {
throw couldNotCreate(e);
} catch (InvocationTargetException e) {
throw couldNotCreate(e);
}
}
 
@Override
protected String signature() {
return _creator.toGenericString();
}
 
@Override
public int priority() {
return 100;
}
 
@Override
public int getModifiers() {
return _creator.getModifiers();
}
}
 
public static class BeanCreatorProperty extends PropertyMutator {
protected final int index;
protected final Annotation[] annotations;
protected final BeanCreator creator;
protected final boolean doThrowMutateException;
 
protected BeanCreatorProperty(String name, Type type, int index, Annotation[] annotations,
Class<?> declaringClass, Class<?> concreteClass, BeanCreator creator) {
this(name, type, index, annotations, declaringClass, concreteClass, creator, false);
}
 
protected BeanCreatorProperty(String name, Type type, int index, Annotation[] annotations,
Class<?> declaringClass, Class<?> concreteClass, BeanCreator creator,
boolean doThrowMutateException) {
super(name, type, declaringClass, concreteClass, annotations, 0);
this.index = index;
this.annotations = annotations;
this.creator = creator;
this.doThrowMutateException = doThrowMutateException;
}
 
public int getIndex() {
return index;
}
 
public Annotation[] getAnnotations() {
return annotations;
}
 
@Override
public int priority() {
return -1000;
}
 
@Override
public String signature() {
return new StringBuilder(type.toString()).append(' ').append(name).append(" from ")
.append(creator.signature()).toString();
}
 
@Override
public int getModifiers() {
return creator.getModifiers();
}
 
@Override
public void mutate(Object target, Object value) {
if (doThrowMutateException) {
throw new IllegalStateException(
"Method mutate should not be called on a mutator of type "
+ getClass().getName()
+ ", this property exists only as constructor parameter!");
}
}
 
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/BeanMutatorAccessorResolver.java
New file
0,0 → 1,338
package com.owlike.genson.reflect;
 
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
 
import static com.owlike.genson.Trilean.FALSE;
import static com.owlike.genson.Trilean.TRUE;
 
import com.owlike.genson.JsonBindingException;
import com.owlike.genson.Trilean;
import com.owlike.genson.annotation.JsonCreator;
import com.owlike.genson.annotation.JsonIgnore;
import com.owlike.genson.annotation.JsonProperty;
 
/**
* BeanMutatorAccessorResolver interface must be implemented by class who want to resolve mutators
* (fields or methods that allow you to modify a property), accessors (fields or methods that allow
* you to retrieve the value of a property) and creators (constructors or static methods that allow
* you to create objects).
* <p/>
* All methods return a {@link com.owlike.genson.Trilean Trilean}, so it may be TRUE, FALSE or UNKNOWN.
* This will allow us to separate the kind of information each implementation works on (one for
* annotations, another for visibility, etc) and to chain them. It also allows an easier addition of
* new features without modifying the existing code. Have a look at <a href=
* "http://code.google.com/p/genson/source/browse/src/main/java/com/owlike/genson/reflect/BeanMutatorAccessorResolver.java"
* >StandardMutaAccessorResolver</a> for an example of BeanMutatorAccessorResolver implementation.
* <p/>
* To register your own implementation instead of the one by default use the genson builder.
* <p/>
* <pre>
* new Genson.Builder().set(yourImplementation).create();
* </pre>
*
* @author eugen
* @see com.owlike.genson.Trilean Trilean
* @see StandardMutaAccessorResolver
* @see AbstractBeanDescriptorProvider
* @see BaseBeanDescriptorProvider
* @see BeanViewDescriptorProvider
*/
public interface BeanMutatorAccessorResolver {
Trilean isCreator(Constructor<?> constructor, Class<?> fromClass);
 
Trilean isCreator(Method method, Class<?> fromClass);
 
Trilean isAccessor(Field field, Class<?> fromClass);
 
Trilean isAccessor(Method method, Class<?> fromClass);
 
Trilean isMutator(Field field, Class<?> fromClass);
 
Trilean isMutator(Method method, Class<?> fromClass);
 
class PropertyBaseResolver implements BeanMutatorAccessorResolver {
@Override
public Trilean isAccessor(Field field, Class<?> fromClass) {
return Trilean.UNKNOWN;
}
 
@Override
public Trilean isAccessor(Method method, Class<?> fromClass) {
return Trilean.UNKNOWN;
}
 
@Override
public Trilean isCreator(Constructor<?> constructor, Class<?> fromClass) {
return Trilean.UNKNOWN;
}
 
@Override
public Trilean isCreator(Method method, Class<?> fromClass) {
return Trilean.UNKNOWN;
}
 
@Override
public Trilean isMutator(Field field, Class<?> fromClass) {
return Trilean.UNKNOWN;
}
 
@Override
public Trilean isMutator(Method method, Class<?> fromClass) {
return Trilean.UNKNOWN;
}
}
 
class CompositeResolver implements BeanMutatorAccessorResolver {
private List<BeanMutatorAccessorResolver> components;
 
public CompositeResolver(List<BeanMutatorAccessorResolver> components) {
if (components == null || components.isEmpty()) {
throw new IllegalArgumentException(
"The composite resolver must have at least one resolver as component!");
}
this.components = new LinkedList<BeanMutatorAccessorResolver>(components);
}
 
public CompositeResolver add(BeanMutatorAccessorResolver... resolvers) {
components.addAll(0, Arrays.asList(resolvers));
return this;
}
 
@Override
public Trilean isAccessor(Field field, Class<?> fromClass) {
Trilean resolved = Trilean.UNKNOWN;
for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.UNKNOWN)
&& it.hasNext(); ) {
resolved = it.next().isAccessor(field, fromClass);
}
return resolved;
}
 
@Override
public Trilean isAccessor(Method method, Class<?> fromClass) {
Trilean resolved = Trilean.UNKNOWN;
for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.UNKNOWN)
&& it.hasNext(); ) {
resolved = it.next().isAccessor(method, fromClass);
}
return resolved;
}
 
@Override
public Trilean isCreator(Constructor<?> constructor, Class<?> fromClass) {
Trilean resolved = Trilean.UNKNOWN;
for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.UNKNOWN)
&& it.hasNext(); ) {
resolved = it.next().isCreator(constructor, fromClass);
}
return resolved;
}
 
@Override
public Trilean isCreator(Method method, Class<?> fromClass) {
Trilean resolved = Trilean.UNKNOWN;
for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.UNKNOWN)
&& it.hasNext(); ) {
resolved = it.next().isCreator(method, fromClass);
}
return resolved;
}
 
@Override
public Trilean isMutator(Field field, Class<?> fromClass) {
Trilean resolved = Trilean.UNKNOWN;
for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.UNKNOWN)
&& it.hasNext(); ) {
resolved = it.next().isMutator(field, fromClass);
}
return resolved;
}
 
@Override
public Trilean isMutator(Method method, Class<?> fromClass) {
Trilean resolved = Trilean.UNKNOWN;
for (Iterator<BeanMutatorAccessorResolver> it = components.iterator(); resolved == null || resolved.equals(Trilean.UNKNOWN)
&& it.hasNext(); ) {
resolved = it.next().isMutator(method, fromClass);
}
return resolved;
}
}
 
class GensonAnnotationsResolver implements BeanMutatorAccessorResolver {
public Trilean isAccessor(Field field, Class<?> fromClass) {
// ok to look for this$ is ugly but it will do the job for the moment
if (mustIgnore(field, true) || field.getName().startsWith("this$"))
return FALSE;
if (mustInclude(field, true))
return TRUE;
return Trilean.UNKNOWN;
}
 
public Trilean isAccessor(Method method, Class<?> fromClass) {
if (mustIgnore(method, true))
return FALSE;
if (mustInclude(method, true) && method.getParameterTypes().length == 0)
return TRUE;
 
return Trilean.UNKNOWN;
}
 
public Trilean isCreator(Constructor<?> constructor, Class<?> fromClass) {
/*
* hum... it depends on different things, such as parameters name resolution, types, etc
* but we are not supposed to handle it here... lets only check visibility and handle it
* in the provider implementations
*/
if (mustIgnore(constructor, false))
return FALSE;
return Trilean.UNKNOWN;
}
 
public Trilean isCreator(Method method, Class<?> fromClass) {
if (method.getAnnotation(JsonCreator.class) != null) {
if (Modifier.isPublic(method.getModifiers())
&& Modifier.isStatic(method.getModifiers()))
return TRUE;
throw new JsonBindingException("Method " + method.toGenericString()
+ " annotated with @JsonCreator must be static!");
}
return FALSE;
}
 
public Trilean isMutator(Field field, Class<?> fromClass) {
if (mustIgnore(field, false) || field.getName().startsWith("this$"))
return FALSE;
if (mustInclude(field, false))
return TRUE;
return Trilean.UNKNOWN;
}
 
public Trilean isMutator(Method method, Class<?> fromClass) {
if (mustIgnore(method, false))
return FALSE;
if (mustInclude(method, false) && method.getParameterTypes().length == 1)
return TRUE;
 
return Trilean.UNKNOWN;
}
 
protected boolean mustIgnore(AccessibleObject property, boolean forSerialization) {
JsonIgnore ignore = property.getAnnotation(JsonIgnore.class);
if (ignore != null) {
if (forSerialization)
return !ignore.serialize();
else
return !ignore.deserialize();
}
return false;
}
 
protected boolean mustInclude(AccessibleObject property, boolean forSerialization) {
JsonProperty prop = property.getAnnotation(JsonProperty.class);
if (prop != null) {
if (forSerialization)
return prop.serialize();
else
return prop.deserialize();
}
return false;
}
}
 
/**
* Standard implementation of BeanMutatorAccessorResolver.
* Actually this implementation handles filtering by signature conventions (Java Bean) and visibility.
*
* @author eugen
*/
class StandardMutaAccessorResolver implements BeanMutatorAccessorResolver {
private final VisibilityFilter fieldVisibilityFilter;
private final VisibilityFilter methodVisibilityFilter;
private final VisibilityFilter creatorVisibilityFilter;
 
/**
* Creates a new instance of StandardMutaAccessorResolver with
* {@link VisibilityFilter#PACKAGE_PUBLIC} visibility for fields,
* {@link VisibilityFilter#PACKAGE_PUBLIC} visibility for methods and creators.
*/
public StandardMutaAccessorResolver() {
this(VisibilityFilter.PACKAGE_PUBLIC, VisibilityFilter.PACKAGE_PUBLIC,
VisibilityFilter.PACKAGE_PUBLIC);
}
 
/**
* Use this constructor if you want to customize the visibility filtering.
*
* @param filedVisibilityFilter
* @param methodVisibilityFilter
* @param creatorVisibilityFilter
*/
public StandardMutaAccessorResolver(VisibilityFilter filedVisibilityFilter,
VisibilityFilter methodVisibilityFilter, VisibilityFilter creatorVisibilityFilter) {
super();
this.fieldVisibilityFilter = filedVisibilityFilter;
this.methodVisibilityFilter = methodVisibilityFilter;
this.creatorVisibilityFilter = creatorVisibilityFilter;
}
 
/**
* Will resolve all public/package and non transient/static fields as accesssors.
*/
public Trilean isAccessor(Field field, Class<?> fromClass) {
return Trilean.valueOf(fieldVisibilityFilter.isVisible(field));
}
 
/**
* Resolves all public methods starting with get/is (boolean) and parameter less as
* accessors.
*/
public Trilean isAccessor(Method method, Class<?> fromClass) {
if (!method.isBridge()) {
String name = method.getName();
int len = name.length();
if (methodVisibilityFilter.isVisible(method)
&& ((len > 3 && name.startsWith("get")) || (len > 2 && name.startsWith("is") && (TypeUtil
.match(TypeUtil.expandType(method.getGenericReturnType(), fromClass),
Boolean.class, false) || TypeUtil.match(
method.getGenericReturnType(), boolean.class, false))))
&& method.getParameterTypes().length == 0)
return TRUE;
}
 
return FALSE;
}
 
public Trilean isCreator(Constructor<?> constructor, Class<?> fromClass) {
return Trilean.valueOf(creatorVisibilityFilter.isVisible(constructor));
}
 
public Trilean isCreator(Method method, Class<?> fromClass) {
return FALSE;
}
 
public Trilean isMutator(Field field, Class<?> fromClass) {
return Trilean.valueOf(fieldVisibilityFilter.isVisible(field));
}
 
public Trilean isMutator(Method method, Class<?> fromClass) {
if (!method.isBridge()) {
if (methodVisibilityFilter.isVisible(method) && method.getName().length() > 3
&& method.getName().startsWith("set") && method.getParameterTypes().length == 1
&& method.getReturnType() == void.class)
return TRUE;
}
 
return FALSE;
}
}
 
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/RenamingPropertyNameResolver.java
New file
0,0 → 1,63
package com.owlike.genson.reflect;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
 
public class RenamingPropertyNameResolver implements PropertyNameResolver {
 
private final String field;
private final Class<?> fromClass;
private final Class<?> ofType;
private final String toName;
 
public RenamingPropertyNameResolver(String field, Class<?> fromClass, Class<?> ofType, String toName) {
this.field = field;
this.fromClass = fromClass;
this.ofType = ofType;
this.toName = toName;
}
 
@Override
public String resolve(int parameterIdx, Constructor<?> fromConstructor) {
return null;
}
 
@Override
public String resolve(int parameterIdx, Method fromMethod) {
return null;
}
 
@Override
public String resolve(Field fromField) {
return tryToRename(fromField.getName(), fromField.getDeclaringClass(),
fromField.getType());
}
 
@Override
public String resolve(Method fromMethod) {
String name = fromMethod.getName();
if (name.startsWith("is") && name.length() > 2) {
return tryToRename(name.substring(2), fromMethod.getDeclaringClass(),
fromMethod.getReturnType());
}
if (name.length() > 3) {
if (name.startsWith("get"))
return tryToRename(name.substring(3), fromMethod.getDeclaringClass(),
fromMethod.getReturnType());
if (name.startsWith("set") && fromMethod.getParameterTypes().length == 1)
return tryToRename(name.substring(3), fromMethod.getDeclaringClass(),
fromMethod.getParameterTypes()[0]);
}
return null;
}
 
private String tryToRename(String actualName, Class<?> declaringClass,
Class<?> propertyType) {
if ((field == null || actualName.equalsIgnoreCase(field))
&& (fromClass == null || fromClass.isAssignableFrom(declaringClass))
&& (ofType == null || ofType.isAssignableFrom(propertyType)))
return toName;
return null;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/PropertyFilter.java
New file
0,0 → 1,65
package com.owlike.genson.reflect;
 
import com.owlike.genson.Trilean;
 
import java.lang.reflect.Field;
import java.lang.reflect.Method;
 
public class PropertyFilter extends BeanMutatorAccessorResolver.PropertyBaseResolver {
private final boolean exclude;
private final String field;
private final Class<?> declaringClass;
private final Class<?> ofType;
 
public PropertyFilter(boolean exclude, String field, Class<?> declaringClass, Class<?> ofType) {
this.exclude = exclude;
this.field = field;
this.declaringClass = declaringClass;
this.ofType = ofType;
}
 
@Override
public Trilean isAccessor(Field field, Class<?> fromClass) {
return filter(field.getName(), fromClass, field.getType(), exclude);
}
 
@Override
public Trilean isMutator(Field field, Class<?> fromClass) {
return filter(field.getName(), fromClass, field.getType(), exclude);
}
 
@Override
public Trilean isAccessor(Method method, Class<?> fromClass) {
String name = method.getName();
if (name.startsWith("is") && name.length() > 2) {
return filter(name.substring(2), method.getDeclaringClass(),
method.getReturnType(), exclude);
}
if (name.length() > 3) {
if (name.startsWith("get"))
return filter(name.substring(3), method.getDeclaringClass(),
method.getReturnType(), exclude);
}
return Trilean.UNKNOWN;
}
 
@Override
public Trilean isMutator(Method method, Class<?> fromClass) {
String name = method.getName();
if (name.length() > 3 && method.getParameterTypes().length == 1) {
if (name.startsWith("set"))
return filter(name.substring(3), method.getDeclaringClass(),
method.getParameterTypes()[0], exclude);
}
return Trilean.UNKNOWN;
}
 
private Trilean filter(String actualName, Class<?> fromClass,
Class<?> propertyType, boolean exclude) {
if ((field == null || actualName.equalsIgnoreCase(field))
&& (declaringClass == null || declaringClass.isAssignableFrom(fromClass))
&& (ofType == null || ofType.isAssignableFrom(TypeUtil.wrap(propertyType))))
return exclude ? Trilean.FALSE : Trilean.TRUE;
return Trilean.UNKNOWN;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/VisibilityFilter.java
New file
0,0 → 1,79
package com.owlike.genson.reflect;
 
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
 
/**
* This class is used as filter for properties discovery. It uses java modifiers to check if a
* property (can be a method, field, constructor or any class that implements Member interface) is
* visible.
* <p/>
* The filter acts by excluding the properties with specified modifiers. Here are some examples :
* <p/>
* <pre>
* // will filter nothing :
* new VisibilityFilter();
*
* // exclude only private and transient:
* new VisibilityFilter(Modifier.TRANSIENT, Modifier.PRIVATE);
*
* // exclude only public!! and allow all the rest
* new VisibilityFilter(Modifier.public);
* </pre>
* <p/>
* So the idea is to pass to the constructor all the Modifier.XXX modifiers that you want to be
* filtered.
*
* @author eugen
* @see BeanMutatorAccessorResolver.StandardMutaAccessorResolver
*/
public final class VisibilityFilter {
 
private final static int JAVA_MODIFIERS = Modifier.PUBLIC | Modifier.PROTECTED
| Modifier.PRIVATE | Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL
| Modifier.TRANSIENT | Modifier.VOLATILE | Modifier.SYNCHRONIZED | Modifier.NATIVE
| Modifier.STRICT | Modifier.INTERFACE;
 
public final static VisibilityFilter ABSTRACT = new VisibilityFilter(Modifier.ABSTRACT);
public final static VisibilityFilter PRIVATE = new VisibilityFilter(Modifier.TRANSIENT,
Modifier.NATIVE, Modifier.STATIC);
public final static VisibilityFilter ALL = new VisibilityFilter();
public final static VisibilityFilter NONE = new VisibilityFilter(JAVA_MODIFIERS);
public final static VisibilityFilter PROTECTED = new VisibilityFilter(Modifier.TRANSIENT,
Modifier.NATIVE, Modifier.STATIC, Modifier.PRIVATE);
public final static VisibilityFilter PACKAGE_PUBLIC = new VisibilityFilter(Modifier.TRANSIENT,
Modifier.NATIVE, Modifier.STATIC, Modifier.PRIVATE, Modifier.PROTECTED);
 
private int filter;
 
/**
* Creates a new VisibilityFilter with specified modifiers. You must use existing values from
* Modifier class otherwise an exception will be thrown.
*
* @param modifier all the modifiers you want to exclude.
*/
public VisibilityFilter(int... modifier) {
filter = 0;
for (int m : modifier) {
 
if ((m & JAVA_MODIFIERS) == 0)
throw new IllegalArgumentException(
"One of the modifiers is not a standard java modifier.");
filter = filter | m;
}
}
 
/**
* Checks whether this member is visible or not according to this filter.
*
* @param member
* @return true if this member is visible according to this filter.
*/
public final boolean isVisible(Member member) {
return isVisible(member.getModifiers());
}
 
public final boolean isVisible(int modifiers) {
return (modifiers & filter) == 0;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/reflect/RuntimePropertyFilter.java
New file
0,0 → 1,15
package com.owlike.genson.reflect;
 
import com.owlike.genson.Context;
 
public interface RuntimePropertyFilter {
RuntimePropertyFilter noFilter = new RuntimePropertyFilter() {
@Override
public boolean shouldInclude(BeanProperty property, Context ctx) {
return true;
}
};
 
boolean shouldInclude(BeanProperty property, Context ctx);
}
 
/branches/grupo4/impl/src/java/com/owlike/genson/Converter.java
New file
0,0 → 1,45
package com.owlike.genson;
 
import java.io.IOException;
 
import com.owlike.genson.stream.ObjectReader;
 
/**
* Converter interface is a shorthand for classes who want to implement both serialization and
* deserialization. You should always privilege Converter instead of low level Serializer and
* Deseriliazer as they will be wrapped into a converter and all the ChainedFactory mechanism is
* designed for converters. Here is an example of a Converter of URLs.
* <p/>
* <pre>
* Genson genson = new Genson.Builder().with(new Converter&lt;URL&gt;() {
*
* &#064;Override
* public void serialize(URL url, ObjectWriter writer, Context ctx) {
* // you don't have to worry about null objects, as the library will handle them.
* writer.writeValue(obj.toExternalForm());
* }
*
* &#064;Override
* public URL deserialize(ObjectReader reader, Context ctx) {
* return new URL(reader.valueAsString());
* }
*
* }).create();
*
* String serializedUrl = genson.serialize(new URL(&quot;http://www.google.com&quot;));
* URL url = genson.deserialize(serializedUrl, URL.class);
* </pre>
* <p/>
* As you can see it is quite straightforward to create and register new Converters. Here is an
* example dealing with more complex objects.
*
* @param <T> type of objects handled by this converter.
* @author eugen
*/
public interface Converter<T> extends Serializer<T>, Deserializer<T> {
@Override
public void serialize(T object, com.owlike.genson.stream.ObjectWriter writer, Context ctx) throws Exception;
 
@Override
public T deserialize(ObjectReader reader, Context ctx) throws Exception;
}
/branches/grupo4/impl/src/java/com/owlike/genson/Factory.java
New file
0,0 → 1,71
package com.owlike.genson;
 
import java.lang.reflect.Type;
 
/**
* Factory interface must be implemented by classes who want to act as factories and create
* instances of Converter/Serializer/Deserializer. Implementations will be used as Converter,
* Serializer and Deserializer factories. So the type T will be something like
* Converter&lt;Integer&gt; but the type argument of method create will correspond to Integer <u>or
* a subclass of Integer</u>.
* <p/>
* As an example you can have a look at factories from {@link com.owlike.genson.convert.DefaultConverters
* DefaultConverters}. Here is an example with a custom converter and factory for enums.
* <p/>
* <pre>
* public static class EnumConverter&lt;T extends Enum&lt;T&gt;&gt; implements Converter&lt;T&gt; {
* private final Class&lt;T&gt; eClass;
*
* public EnumConverter(Class&lt;T&gt; eClass) {
* this.eClass = eClass;
* }
*
* &#064;Override
* public void serialize(T obj, ObjectWriter writer, Context ctx) {
* writer.writeUnsafeValue(obj.name());
* }
*
* &#064;Override
* public T deserialize(ObjectReader reader, Context ctx) {
* return Enum.valueOf(eClass, reader.valueAsString());
* }
* }
*
* public final static class EnumConverterFactory implements Factory&lt;Converter&lt;? extends Enum&lt;?&gt;&gt;&gt; {
* public final static EnumConverterFactory instance = new EnumConverterFactory();
*
* private EnumConverterFactory() {
* }
*
* &#064;SuppressWarnings({ &quot;rawtypes&quot;, &quot;unchecked&quot; })
* &#064;Override
* public Converter&lt;Enum&lt;?&gt;&gt; create(Type type, Genson genson) {
* Class&lt;?&gt; rawClass = TypeUtil.getRawClass(type);
* return rawClass.isEnum() || Enum.class.isAssignableFrom(rawClass) ? new EnumConverter(
* rawClass) : null;
* }
* };
* </pre>
* <p/>
* Note the use of {@link com.owlike.genson.reflect.TypeUtil TypeUtil} class that provides operations to
* work with generic types. However this class might change in the future, in order to provide a better API.
*
* @param <T> the base type of the objects this factory can create. T can be of type Converter,
* Serializer or Deserializer.
* @author eugen
* @see com.owlike.genson.Converter
* @see com.owlike.genson.convert.ChainedFactory ChainedFactory
* @see com.owlike.genson.Serializer
* @see com.owlike.genson.Deserializer
*/
public interface Factory<T> {
/**
* Implementations of this method must try to create an instance of type T based on the
* parameter "type". If this factory can not create an object of type T for parameter type then
* it must return null.
*
* @param type used to build an instance of T.
* @return null if it doesn't support this type or an instance of T (or a subclass).
*/
public T create(Type type, Genson genson);
}
/branches/grupo4/impl/src/java/com/owlike/genson/Serializer.java
New file
0,0 → 1,69
package com.owlike.genson;
 
import java.io.IOException;
 
import com.owlike.genson.stream.ObjectWriter;
 
/**
* Serializers handle serialization by writing a java object of type T to a stream using
* {@link com.owlike.genson.stream.ObjectWriter ObjectWriter}. Genson Serializers work like classic
* serializers from other libraries. Here is an example of a custom serializer that will delegate
* the serialization of Author type to the library:
* <p/>
* <pre>
* class Book {
* String title;
* int totalPages;
* Author author;
* }
*
* class Author {
* String name;
* }
*
* static class BookSerializer implements Serializer&lt;Book&gt; {
* private final Serializer&lt;Author&gt; authorSerializer;
*
* // a reference to a delegated author serializer
* BookSerializer(Serializer&lt;Author&gt; authorSerializer) {
* this.authorSerializer = authorSerializer;
* }
*
* public void serialize(Book book, ObjectWriter writer, Context ctx) {
* // we don't have to worry if book is null by default it is handled by the library.
* writer.beginObject().writeName(&quot;title&quot;).writeValue(book.title).writeName(&quot;totalPages&quot;)
* .writeValue(book.totalPages).writeName(&quot;author&quot;);
*
* // again no need to check if author is null the library will handle it
* authorSerializer.serialize(book.author, writer, ctx);
* writer.endObject();
* }
*
* public final static Factory&lt;Serializer&lt;Book&gt;&gt; bookFactory = new Factory&lt;Serializer&lt;Book&gt;&gt;() {
*
* public Serializer&lt;Book&gt; create(Type type, Genson genson) {
* Serializer&lt;Author&gt; authorSerializer = genson.provideConverter(Author.class);
* return new GoodBookSerializer(authorSerializer);
* }
* }
* }
* </pre>
* <p/>
* As you see it involves very few lines of code and is quite powerful.
*
* @param <T> the type of objects this Serializer can serialize.
* @author eugen
* @see Converter
* @see com.owlike.genson.Factory Factory
*/
public interface Serializer<T> {
/**
* @param object we want to serialize. The object is of type T or a subclass (if this serializer
* has been registered for subclasses).
* @param writer to use to write data to the output stream.
* @param ctx the current context.
* @throws com.owlike.genson.JsonBindingException
* @throws com.owlike.genson.stream.JsonStreamException
*/
public void serialize(T object, ObjectWriter writer, Context ctx) throws Exception;
}
/branches/grupo4/impl/src/java/com/owlike/genson/stream/ObjectWriter.java
New file
0,0 → 1,311
package com.owlike.genson.stream;
 
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
 
/**
* ObjectWriter defines the api allowing to write data to different format and the contract for
* classes that implement ObjectWriter to provide different formats support. Implementations are
* extremely efficient as they use low level stream operations and optimizations. If you want
* optimal performance you can directly use the streaming api (ObjectWriter and {@link ObjectReader}
* ) without the databind support that comes with the converters. This will be very close in terms
* of performance as writing manually formated data to the stream.
* <p/>
* If you want to write the array new int[1, 2, 3] to the stream with ObjectWriter:
* <p/>
* <pre>
* writer.beginArray().writeValue(1).writeValue(2).writeValue(3).endArray();
* </pre>
* <p/>
* And to write Person (we simplify, in practice you must handle null values):
* <p/>
* <pre>
* class Person {
* public static void main(String[] args) {
* // we will write from Person to json string
* Person p = new Person();
* p.name = &quot;eugen&quot;;
* p.age = 26;
* p.childrenYearOfBirth = new ArrayList&lt;Integer&gt;();
* StringWriter sw = new StringWriter();
* ObjectWriter writer = new JsonWriter(sw);
* p.write(writer);
* writer.flush();
* writer.close();
* // will write {&quot;name&quot;:&quot;eugen&quot;,&quot;age&quot;:26,&quot;childrenYearOfBirth&quot;:[]}
* System.out.println(sw.toString());
* }
*
* String name;
* int age;
* List&lt;Integer&gt; childrenYearOfBirth;
*
* public void write(ObjectWriter writer) {
* writer.beginObject().writeName(&quot;name&quot;);
* if (name == null) writer.writeNull();
* else writer.writeValue(name)
* writer.writeName(&quot;age&quot;).writeAge(age)
* .writeName(&quot;childrenYearOfBirth&quot;);
* if (childrenYearOfBirth == null) writer.writeNull();
* else {
* writer.beginArray();
* for (Integer year : childrenYearOfBirth)
* writer.writeValue(year);
* writer.endArray()
* }
* writer.endObject();
* }
* }
* </pre>
* <p/>
* Be careful if you instantiate ObjectWriter your self you are responsible of flushing and closing
* the stream.
*
* @author eugen
* @see JsonWriter
* @see ObjectReader
* @see JsonReader
*/
public interface ObjectWriter {
 
/**
* Starts to write an array (use it also for collections). An array is a suite of values that
* may be literals, arrays or objects. When you finished writing the values don't forget to call
* endArray().
*
* @return a reference to this allowing to chain method calls.
* @throws JsonStreamException if trying to produce invalid json
*/
public ObjectWriter beginArray();
 
/**
* Ends the array, if beginArray was not called, implementations should throw an exception.
*
* @return a reference to this allowing to chain method calls.
* @throws JsonStreamException if trying to produce invalid json
*/
public ObjectWriter endArray();
 
/**
* Starts a object, objects are a suite of name/value pairs, values may be literals, arrays or
* objects. Don't forget to call endObject.
*
* @return a reference to this allowing to chain method calls.
* @throws JsonStreamException if trying to produce invalid json
*/
public ObjectWriter beginObject();
 
/**
* Ends the object being written, if beginObject was not called an exception will be throwed.
*
* @return a reference to this allowing to chain method calls.
* @throws JsonStreamException if trying to produce invalid json
*/
public ObjectWriter endObject();
 
/**
* Writes the name of a property. Names can be written only in objects and must be called before
* writing the properties value.
*
* @param name a non null String
* @return a reference to this, allowing to chain method calls.
* @throws JsonStreamException if trying to produce invalid json
*/
public ObjectWriter writeName(String name);
 
/**
* Will write the name without escaping special characters, assuming it has been done by the caller or the string
* doesn't contain any character needing to be escaped.
* @param name a non null escaped String
* @return a reference to this, allowing to chain method calls.
* @throws JsonStreamException if trying to produce invalid json
*/
public ObjectWriter writeEscapedName(char[] name);
 
/**
* Writes a value to the stream. Values can be written in arrays and in objects (after writing
* the name).
*
* @param value to write.
* @return a reference to this, allowing to chain method calls.
* @throws JsonStreamException if trying to produce invalid json
*/
public ObjectWriter writeValue(int value);
 
/**
* See {@link #writeValue(int)}.
*
* @throws JsonStreamException if trying to produce invalid json
* @see #writeValue(int)
*/
public ObjectWriter writeValue(double value);
 
/**
* See {@link #writeValue(int)}.
*
* @throws JsonStreamException if trying to produce invalid json
* @see #writeValue(int)
*/
public ObjectWriter writeValue(long value);
 
/**
* See {@link #writeValue(int)}.
*
* @throws JsonStreamException if trying to produce invalid json
* @see #writeValue(int)
*/
public ObjectWriter writeValue(short value);
 
/**
* @see #writeValue(int)
*/
public ObjectWriter writeValue(float value);
 
/**
* See {@link #writeValue(int)}.
*
* @throws JsonStreamException if trying to produce invalid json
* @see #writeValue(int)
*/
public ObjectWriter writeValue(boolean value);
 
/**
* @see #writeString(String)
*/
public ObjectWriter writeBoolean(Boolean value);
 
/**
* See {@link #writeValue(int)}.
*
* @throws JsonStreamException if trying to produce invalid json
* @see #writeValue(int)
*/
public ObjectWriter writeValue(Number value);
 
/**
* @see #writeString(String)
*/
public ObjectWriter writeNumber(Number value);
 
/**
* See {@link #writeValue(int)}.
*
* @throws JsonStreamException if trying to produce invalid json
* @see #writeValue(int)
*/
public ObjectWriter writeValue(String value);
 
/**
* Similar to writeValue(String) but is null safe, meaning that if the value is null,
* then the write will call writeNull for you.
*/
public ObjectWriter writeString(String value);
 
/**
* Writes an array of bytes as a base64 encoded string. See {@link #writeValue(int)}.
*
* @throws JsonStreamException if trying to produce invalid json
* @see #writeValue(int)
*/
public ObjectWriter writeValue(byte[] value);
 
/**
* @see #writeString(String)
*/
public ObjectWriter writeBytes(byte[] value);
 
/**
* Writes value as is without any pre-processing, it's faster than {@link #writeValue(String)}
* but should be used only if you know that it is safe.
*
* @throws JsonStreamException if trying to produce invalid json
* @see #writeValue(int)
*/
public ObjectWriter writeUnsafeValue(String value);
 
/**
* Must be called when a null value is encountered. Implementations will deal with the null
* representation (just skip it or write null, etc).
*
* @return a reference to this allowing to chain method calls.
* @throws JsonStreamException if trying to produce invalid json
* @see #writeValue(int)
*/
public ObjectWriter writeNull();
 
/**
* This method is a kind of cheat as it allows us to start writing metadata and then still be
* able to call beginObject. This is mainly intended to be used in wrapped converters that want
* to handle a part of the serialization and then let the chain continue. Have a look at <a
* href=
* "http://code.google.com/p/genson/source/browse/src/main/java/com/owlike/genson/convert/ClassMetadataConverter.java"
* >ClassMetadataConverter</a>
*
* @return a reference to this allowing to chain method calls.
* @throws JsonStreamException
* @see #writeMetadata(String, String)
*/
public ObjectWriter beginNextObjectMetadata();
 
/**
* Metadata is a suite of name/value pairs, names will be prepended with '@' (handled by the
* library). Metadata feature is experimental for the moment so things may change a bit. The
* signature will not, but the way it is implemented could... Actually the contract is that
* metadata must be written first and only in objects. If it does not respect these conditions
* ObjectReader won't be able to detect it as metadata. Here is an example of two ways to write
* object metadata.
* <p/>
* <pre>
* // here it is transparent for the library if you write metadata or something else, you must call
* // beginObject before being able to start writing its metadata.
* writer.beginObject().writeMetadata(&quot;doc&quot;, &quot;Object documentation bla bla...&quot;).writeName(&quot;name&quot;)
* .writeNull().endObject().flush();
*
* // previous example works fine, but if you want to write some metadata and still be able to call
* // beginObject (for example in a converter you want to write some metadata and have all the existing
* // continue to work with calling beginObject) you must use beginNextObjectMetadata.
*
* // written from a first converter
* writer.beginNextObjectMetadata().writeMetadata(&quot;dataFromConverter1&quot;, &quot;writtenFromConverter1&quot;);
* // written from a second converter after first one
* writer.beginNextObjectMetadata().writeMetadata(&quot;dataFromConverter2&quot;, &quot;writtenFromConverter2&quot;);
* // finally concrete properties will be written from a custom converter
* writer.beginObject().writeName(&quot;name&quot;).writeNull().endObject().flush();
* </pre>
*
* @param name of the metadata property, should not start with '@', the library will add it.
* @param value of the metadata property.
* @return a reference to this allowing to chain method calls.
* @throws JsonStreamException
* @see #beginNextObjectMetadata()
*/
public ObjectWriter writeMetadata(String name, String value);
 
/**
* @see #writeString(String, String)
*/
public ObjectWriter writeBoolean(String name, Boolean value);
 
/**
* @see #writeString(String, String)
*/
public ObjectWriter writeNumber(String name, Number value);
 
/**
* Will write the name and the value, it is just a shortcut for writer.writeName("key").writeString(value).
* Note if the value is null, writeNull is used.
*/
public ObjectWriter writeString(String name, String value);
 
/**
* @see #writeString(String, String)
*/
public ObjectWriter writeBytes(String name, byte[] value);
 
public void flush();
 
public void close();
 
public JsonType enclosingType();
}
/branches/grupo4/impl/src/java/com/owlike/genson/stream/Base64.java
New file
0,0 → 1,585
package com.owlike.genson.stream;
 
import java.util.Arrays;
 
/**
* A very fast and memory efficient class to encode and decode to and from BASE64 in full accordance
* with RFC 2045.<br><br>
* On Windows XP sp1 with 1.4.2_04 and later ;), this encoder and decoder is about 10 times faster
* on small arrays (10 - 1000 bytes) and 2-3 times as fast on larger arrays (10000 - 1000000 bytes)
* compared to <code>sun.misc.Encoder()/Decoder()</code>.<br><br>
* <p/>
* On byte arrays the encoder is about 20% faster than Jakarta Commons Base64 Codec for encode and
* about 50% faster for decoding large arrays. This implementation is about twice as fast on very small
* arrays (&lt 30 bytes). If source/destination is a <code>String</code> this
* version is about three times as fast due to the fact that the Commons Codec result has to be recoded
* to a <code>String</code> from <code>byte[]</code>, which is very expensive.<br><br>
* <p/>
* This encode/decode algorithm doesn't create any temporary arrays as many other codecs do, it only
* allocates the resulting array. This produces less garbage and it is possible to handle arrays twice
* as large as algorithms that create a temporary array. (E.g. Jakarta Commons Codec). It is unknown
* whether Sun's <code>sun.misc.Encoder()/Decoder()</code> produce temporary arrays but since performance
* is quite low it probably does.<br><br>
* <p/>
* The encoder produces the same output as the Sun one except that the Sun's encoder appends
* a trailing line separator if the last character isn't a pad. Unclear why but it only adds to the
* length and is probably a side effect. Both are in conformance with RFC 2045 though.<br>
* Commons codec seem to always att a trailing line separator.<br><br>
* <p/>
* <b>Note!</b>
* The encode/decode method pairs (types) come in three versions with the <b>exact</b> same algorithm and
* thus a lot of code redundancy. This is to not create any temporary arrays for transcoding to/from different
* format types. The methods not used can simply be commented out.<br><br>
* <p/>
* There is also a "fast" version of all decode methods that works the same way as the normal ones, but
* har a few demands on the decoded input. Normally though, these fast verions should be used if the source if
* the input is known and it hasn't bee tampered with.<br><br>
* <p/>
* If you find the code useful or you find a bug, please send me a note at base64 @ miginfocom . com.
* <p/>
* Licence (BSD):
* ==============
* <p/>
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com)
* All rights reserved.
* <p/>
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
* <p/>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @author Mikael Grev
* Date: 2004-aug-02
* Time: 11:31:11
* @version 2.2
*/
 
class Base64 {
private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
private static final int[] IA = new int[256];
 
static {
Arrays.fill(IA, -1);
for (int i = 0, iS = CA.length; i < iS; i++)
IA[CA[i]] = i;
IA['='] = 0;
}
 
// ****************************************************************************************
// * char[] version
// ****************************************************************************************
 
/**
* Encodes a raw byte array into a BASE64 <code>char[]</code> representation i accordance with RFC 2045.
*
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*/
public final static char[] encodeToChar(byte[] sArr, boolean lineSep) {
// Check special case
int sLen = sArr != null ? sArr.length : 0;
if (sLen == 0)
return new char[0];
 
int eLen = (sLen / 3) * 3; // Length of even 24-bits.
int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
char[] dArr = new char[dLen];
 
// Encode even 24-bits
for (int s = 0, d = 0, cc = 0; s < eLen; ) {
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
 
// Encode the int into four chars
dArr[d++] = CA[(i >>> 18) & 0x3f];
dArr[d++] = CA[(i >>> 12) & 0x3f];
dArr[d++] = CA[(i >>> 6) & 0x3f];
dArr[d++] = CA[i & 0x3f];
 
// Add optional line separator
if (lineSep && ++cc == 19 && d < dLen - 2) {
dArr[d++] = '\r';
dArr[d++] = '\n';
cc = 0;
}
}
 
// Pad and encode last bits if source isn't even 24 bits.
int left = sLen - eLen; // 0 - 2.
if (left > 0) {
// Prepare the int
int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
 
// Set last four chars
dArr[dLen - 4] = CA[i >> 12];
dArr[dLen - 3] = CA[(i >>> 6) & 0x3f];
dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '=';
dArr[dLen - 1] = '=';
}
return dArr;
}
 
/**
* Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with
* and without line separators.
*
* @param sArr The source array. <code>null</code> or length 0 will return an empty array.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*/
public final static byte[] decode(char[] sArr) {
// Check special case
int sLen = sArr != null ? sArr.length : 0;
if (sLen == 0)
return new byte[0];
 
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
// so we don't have to reallocate & copy it later.
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
if (IA[sArr[i]] < 0)
sepCnt++;
 
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
if ((sLen - sepCnt) % 4 != 0)
return null;
 
int pad = 0;
for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0; )
if (sArr[i] == '=')
pad++;
 
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
 
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
 
for (int s = 0, d = 0; d < len; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = 0;
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
int c = IA[sArr[s++]];
if (c >= 0)
i |= c << (18 - j * 6);
else
j--;
}
// Add the bytes
dArr[d++] = (byte) (i >> 16);
if (d < len) {
dArr[d++] = (byte) (i >> 8);
if (d < len)
dArr[d++] = (byte) i;
}
}
return dArr;
}
 
/**
* Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as
* fast as {@link #decode(char[])}. The preconditions are:<br>
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
* + Line separator must be "\r\n", as specified in RFC 2045
* + The array must not contain illegal characters within the encoded string<br>
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
*
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0.
*/
public final static byte[] decodeFast(char[] sArr) {
// Check special case
int sLen = sArr.length;
if (sLen == 0)
return new byte[0];
 
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
 
// Trim illegal chars from start
while (sIx < eIx && IA[sArr[sIx]] < 0)
sIx++;
 
// Trim illegal chars from end
while (eIx > 0 && IA[sArr[eIx]] < 0)
eIx--;
 
// get the padding count (=) (0, 1 or 2)
int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
int cCnt = eIx - sIx + 1; // Content count including possible separators
int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
 
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
 
// Decode all but the last 0 - 2 bytes.
int d = 0;
for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
 
// Add the bytes
dArr[d++] = (byte) (i >> 16);
dArr[d++] = (byte) (i >> 8);
dArr[d++] = (byte) i;
 
// If line separator, jump over it.
if (sepCnt > 0 && ++cc == 19) {
sIx += 2;
cc = 0;
}
}
 
if (d < len) {
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
int i = 0;
for (int j = 0; sIx <= eIx - pad; j++)
i |= IA[sArr[sIx++]] << (18 - j * 6);
 
for (int r = 16; d < len; r -= 8)
dArr[d++] = (byte) (i >> r);
}
 
return dArr;
}
 
// ****************************************************************************************
// * byte[] version
// ****************************************************************************************
 
/**
* Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045.
*
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*/
public final static byte[] encodeToByte(byte[] sArr, boolean lineSep) {
// Check special case
int sLen = sArr != null ? sArr.length : 0;
if (sLen == 0)
return new byte[0];
 
int eLen = (sLen / 3) * 3; // Length of even 24-bits.
int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
byte[] dArr = new byte[dLen];
 
// Encode even 24-bits
for (int s = 0, d = 0, cc = 0; s < eLen; ) {
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
 
// Encode the int into four chars
dArr[d++] = (byte) CA[(i >>> 18) & 0x3f];
dArr[d++] = (byte) CA[(i >>> 12) & 0x3f];
dArr[d++] = (byte) CA[(i >>> 6) & 0x3f];
dArr[d++] = (byte) CA[i & 0x3f];
 
// Add optional line separator
if (lineSep && ++cc == 19 && d < dLen - 2) {
dArr[d++] = '\r';
dArr[d++] = '\n';
cc = 0;
}
}
 
// Pad and encode last bits if source isn't an even 24 bits.
int left = sLen - eLen; // 0 - 2.
if (left > 0) {
// Prepare the int
int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
 
// Set last four chars
dArr[dLen - 4] = (byte) CA[i >> 12];
dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f];
dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
dArr[dLen - 1] = '=';
}
return dArr;
}
 
/**
* Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
* and without line separators.
*
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*/
public final static byte[] decode(byte[] sArr) {
// Check special case
int sLen = sArr.length;
 
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
// so we don't have to reallocate & copy it later.
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
if (IA[sArr[i] & 0xff] < 0)
sepCnt++;
 
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
if ((sLen - sepCnt) % 4 != 0)
return null;
 
int pad = 0;
for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0; )
if (sArr[i] == '=')
pad++;
 
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
 
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
 
for (int s = 0, d = 0; d < len; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = 0;
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
int c = IA[sArr[s++] & 0xff];
if (c >= 0)
i |= c << (18 - j * 6);
else
j--;
}
 
// Add the bytes
dArr[d++] = (byte) (i >> 16);
if (d < len) {
dArr[d++] = (byte) (i >> 8);
if (d < len)
dArr[d++] = (byte) i;
}
}
 
return dArr;
}
 
 
/**
* Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
* fast as {@link #decode(byte[])}. The preconditions are:<br>
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
* + Line separator must be "\r\n", as specified in RFC 2045
* + The array must not contain illegal characters within the encoded string<br>
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
*
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0.
*/
public final static byte[] decodeFast(byte[] sArr) {
// Check special case
int sLen = sArr.length;
if (sLen == 0)
return new byte[0];
 
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
 
// Trim illegal chars from start
while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0)
sIx++;
 
// Trim illegal chars from end
while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0)
eIx--;
 
// get the padding count (=) (0, 1 or 2)
int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
int cCnt = eIx - sIx + 1; // Content count including possible separators
int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
 
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
 
// Decode all but the last 0 - 2 bytes.
int d = 0;
for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
 
// Add the bytes
dArr[d++] = (byte) (i >> 16);
dArr[d++] = (byte) (i >> 8);
dArr[d++] = (byte) i;
 
// If line separator, jump over it.
if (sepCnt > 0 && ++cc == 19) {
sIx += 2;
cc = 0;
}
}
 
if (d < len) {
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
int i = 0;
for (int j = 0; sIx <= eIx - pad; j++)
i |= IA[sArr[sIx++]] << (18 - j * 6);
 
for (int r = 16; d < len; r -= 8)
dArr[d++] = (byte) (i >> r);
}
 
return dArr;
}
 
// ****************************************************************************************
// * String version
// ****************************************************************************************
 
/**
* Encodes a raw byte array into a BASE64 <code>String</code> representation i accordance with RFC 2045.
*
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
* little faster.
* @return A BASE64 encoded array. Never <code>null</code>.
*/
public final static String encodeToString(byte[] sArr, boolean lineSep) {
// Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower.
return new String(encodeToChar(sArr, lineSep));
}
 
/**
* Decodes a BASE64 encoded <code>String</code>. All illegal characters will be ignored and can handle both strings with
* and without line separators.<br>
* <b>Note!</b> It can be up to about 2x the speed to call <code>decode(str.toCharArray())</code> instead. That
* will create a temporary array though. This version will use <code>str.charAt(i)</code> to iterate the string.
*
* @param str The source string. <code>null</code> or length 0 will return an empty array.
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
*/
public final static byte[] decode(String str) {
// Check special case
int sLen = str != null ? str.length() : 0;
if (sLen == 0)
return new byte[0];
 
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
// so we don't have to reallocate & copy it later.
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
if (IA[str.charAt(i)] < 0)
sepCnt++;
 
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
if ((sLen - sepCnt) % 4 != 0)
return null;
 
// Count '=' at end
int pad = 0;
for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0; )
if (str.charAt(i) == '=')
pad++;
 
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
 
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
 
for (int s = 0, d = 0; d < len; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = 0;
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
int c = IA[str.charAt(s++)];
if (c >= 0)
i |= c << (18 - j * 6);
else
j--;
}
// Add the bytes
dArr[d++] = (byte) (i >> 16);
if (d < len) {
dArr[d++] = (byte) (i >> 8);
if (d < len)
dArr[d++] = (byte) i;
}
}
return dArr;
}
 
/**
* Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as
* fast as {@link #decode(String)}. The preconditions are:<br>
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
* + Line separator must be "\r\n", as specified in RFC 2045
* + The array must not contain illegal characters within the encoded string<br>
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
*
* @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception.
* @return The decoded array of bytes. May be of length 0.
*/
public final static byte[] decodeFast(String s) {
// Check special case
int sLen = s.length();
if (sLen == 0)
return new byte[0];
 
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
 
// Trim illegal chars from start
while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0)
sIx++;
 
// Trim illegal chars from end
while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0)
eIx--;
 
// get the padding count (=) (0, 1 or 2)
int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end.
int cCnt = eIx - sIx + 1; // Content count including possible separators
int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0;
 
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
 
// Decode all but the last 0 - 2 bytes.
int d = 0;
for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
// Assemble three bytes into an int from four "valid" characters.
int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)];
 
// Add the bytes
dArr[d++] = (byte) (i >> 16);
dArr[d++] = (byte) (i >> 8);
dArr[d++] = (byte) i;
 
// If line separator, jump over it.
if (sepCnt > 0 && ++cc == 19) {
sIx += 2;
cc = 0;
}
}
 
if (d < len) {
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
int i = 0;
for (int j = 0; sIx <= eIx - pad; j++)
i |= IA[s.charAt(sIx++)] << (18 - j * 6);
 
for (int r = 16; d < len; r -= 8)
dArr[d++] = (byte) (i >> r);
}
 
return dArr;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/stream/JsonStreamException.java
New file
0,0 → 1,82
package com.owlike.genson.stream;
 
/**
* JsonStreamException are thrown by ObjectWriter and ObjectReader implementations. They indicate
* that there was a syntax error or a state error (calling endObject when it should be endArray
* etc).
*
* @author eugen
*/
public final class JsonStreamException extends RuntimeException {
private static final long serialVersionUID = 8033784054415043293L;
 
private final int column;
private final int row;
 
public JsonStreamException(String message, Throwable cause) {
this(message, cause, -1, -1);
}
 
public JsonStreamException(String message) {
this(message, null);
}
 
public JsonStreamException(Throwable cause) {
this(null, cause);
}
 
// package visibility, api users are not supposed to use it
JsonStreamException(String message, Throwable cause, int row, int col) {
super(message, cause);
this.column = col;
this.row = row;
}
 
public int getColumn() {
return column;
}
 
public int getRow() {
return row;
}
 
public static <T extends Exception> T niceTrace(T exception) {
final StackTraceElement[] stackTrace = exception.getStackTrace();
final StackTraceElement[] newStackTrace = new StackTraceElement[stackTrace.length - 1];
 
System.arraycopy(stackTrace, 1, newStackTrace, 0, stackTrace.length - 1);
exception.setStackTrace(newStackTrace);
return exception;
}
 
public JsonStreamException niceTrace() {
return niceTrace(this);
}
 
static class Builder {
private int col;
private int row;
private String message;
private Throwable cause;
 
public JsonStreamException create() {
return new JsonStreamException(message, cause, row, col);
}
 
Builder locate(int row, int col) {
this.row = row;
this.col = col;
return this;
}
 
public Builder message(String message) {
this.message = message;
return this;
}
 
public Builder cause(Throwable th) {
this.cause = th;
return this;
}
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/stream/package-info.java
New file
0,0 → 1,5
/**
* This package provides the streaming api used to read and write to streams.
* Actually only json format is supported however xml may be added latter ;)
*/
package com.owlike.genson.stream;
/branches/grupo4/impl/src/java/com/owlike/genson/stream/JsonWriter.java
New file
0,0 → 1,578
package com.owlike.genson.stream;
 
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
 
public class JsonWriter implements ObjectWriter {
/*
* TODO try to do something different and faster, optimize writeValue(String)
*/
private final static char[][] REPLACEMENT_CHARS;
private final static char[][] HTML_SAFE_REPLACEMENT_CHARS;
 
static {
REPLACEMENT_CHARS = new char[128][];
for (int i = 0; i <= 0x1f; i++) {
REPLACEMENT_CHARS[i] = String.format("\\u%04x", (int) i).toCharArray();
}
REPLACEMENT_CHARS['"'] = "\\\"".toCharArray();
REPLACEMENT_CHARS['\\'] = "\\\\".toCharArray();
REPLACEMENT_CHARS['\t'] = "\\t".toCharArray();
REPLACEMENT_CHARS['\b'] = "\\b".toCharArray();
REPLACEMENT_CHARS['\n'] = "\\n".toCharArray();
REPLACEMENT_CHARS['\r'] = "\\r".toCharArray();
REPLACEMENT_CHARS['\f'] = "\\f".toCharArray();
HTML_SAFE_REPLACEMENT_CHARS = REPLACEMENT_CHARS.clone();
HTML_SAFE_REPLACEMENT_CHARS['\''] = "\\u0027".toCharArray();
HTML_SAFE_REPLACEMENT_CHARS['<'] = "\\u003c".toCharArray();
HTML_SAFE_REPLACEMENT_CHARS['>'] = "\\u003e".toCharArray();
HTML_SAFE_REPLACEMENT_CHARS['&'] = "\\u0026".toCharArray();
HTML_SAFE_REPLACEMENT_CHARS['='] = "\\u003d".toCharArray();
}
 
private final static char[] _INT_TO_CHARARRAY = new char[10];
 
static {
for (int i = 0; i < 10; i++) {
_INT_TO_CHARARRAY[i] = (char) (i + 48);
}
}
 
private final static char[] NULL_VALUE = {'n', 'u', 'l', 'l'};
private final static char[] TRUE_VALUE = {'t', 'r', 'u', 'e'};
private final static char[] FALSE_VALUE = {'f', 'a', 'l', 's', 'e'};
// seems to work well, but maybe a smaller value would be better?
private final static int _LIMIT_WRITE_TO_BUFFER = 64;
 
private final boolean htmlSafe;
private final boolean skipNull;
 
private final Writer writer;
final Deque<JsonType> _ctx = new ArrayDeque<JsonType>(10);
private boolean _hasPrevious;
private char[] _name;
private final boolean indentation;
private final static char[] _indentation = new char[]{' ', ' '};
 
private final char[] _buffer = new char[1024];
private final int _bufferSize = _buffer.length;
private int _len = 0;
 
List<MetadataPair> _metadata = new ArrayList<MetadataPair>();
 
private class MetadataPair {
final String name;
final String value;
 
public MetadataPair(String name, String value) {
super();
this.name = name;
this.value = value;
}
}
 
public JsonWriter(Writer writer) {
this(writer, false, false, false);
}
 
public JsonWriter(Writer writer, final boolean skipNull, final boolean htmlSafe,
boolean indentation) {
this.writer = writer;
this.skipNull = skipNull;
this.htmlSafe = htmlSafe;
this.indentation = indentation;
_ctx.push(JsonType.EMPTY);
}
 
public JsonType enclosingType() {
return _ctx.peek();
}
 
public void close() {
flush();
try {
writer.close();
} catch (IOException e) {
throw new JsonStreamException(e);
}
}
 
public void flush() {
flushBuffer();
try {
writer.flush();
} catch (IOException e) {
throw new JsonStreamException(e);
}
}
 
public JsonWriter beginArray() {
clearMetadata();
if (_ctx.peek() == JsonType.OBJECT && _name == null)
throw new JsonStreamException(
"Englobing scope is OBJECT before begining a new value call writeName.");
return begin(JsonType.ARRAY, '[');
}
 
public JsonWriter beginObject() {
if (_ctx.peek() == JsonType.METADATA) {
_ctx.pop();
begin(JsonType.OBJECT, '{');
for (MetadataPair pair : _metadata) {
writeName('@' + pair.name);
beforeValue();
writeInternalString(pair.value);
}
} else begin(JsonType.OBJECT, '{');
return this;
}
 
protected final JsonWriter begin(final JsonType jsonType, final char token) {
beforeValue();
_ctx.push(jsonType);
if ((_len + 1) >= _bufferSize) flushBuffer();
_buffer[_len++] = token;
_hasPrevious = false;
return this;
}
 
public JsonWriter endArray() {
return end(JsonType.ARRAY, ']');
}
 
public JsonWriter endObject() {
return end(JsonType.OBJECT, '}');
}
 
private final JsonWriter end(final JsonType jsonType, final char token) {
JsonType jt = _ctx.pop();
if (jt != jsonType)
throw new JsonStreamException("Expect type " + jsonType.name() + " but was written "
+ jt.name() + ", you must call the adequate beginXXX method before endXXX.");
 
if (indentation) {
_buffer[_len++] = '\n';
for (int i = 0; i < _ctx.size() - 1; i++)
writeToBuffer(_indentation, 0, 2);
}
 
if ((_len + 1) >= _bufferSize) flushBuffer();
 
_buffer[_len++] = token;
_hasPrevious = true;
return this;
}
 
private final JsonWriter beforeValue() {
final JsonType enclosingType = _ctx.peek();
if (enclosingType == JsonType.ARRAY) {
if (_name != null) throw newIllegalKeyValuePairInJsonArray(new String(_name));
if (_hasPrevious) {
if ((_len + 1) >= _bufferSize) flushBuffer();
_buffer[_len++] = ',';
}
indent();
} else if (_name != null) {
final int l = _name.length;
// hum I dont think there may be names with a length near to 1024... we flush only once
if ((_len + 4 + l) >= _bufferSize) flushBuffer();
if (_hasPrevious) _buffer[_len++] = ',';
indent();
if ((_len + 3 + l) >= _bufferSize) flushBuffer();
 
_buffer[_len++] = '"';
writeToBuffer(_name, 0, l);
_buffer[_len++] = '"';
 
_buffer[_len++] = ':';
_name = null;
} else if (enclosingType == JsonType.OBJECT) throw newIllegalSingleValueInJsonObject();
 
return this;
}
 
private JsonStreamException newIllegalKeyValuePairInJsonArray(String name) {
return JsonStreamException
.niceTrace(new JsonStreamException(
"Tried to write key/value pair with key="
+ name
+ ", Json format does not allow key/value pairs inside arrays, only allowed for Json Objects."));
}
 
private JsonStreamException newIllegalSingleValueInJsonObject() {
return JsonStreamException.niceTrace(new JsonStreamException(
"Tried to write value with no key in a JsonObject, Json format does not allow "
+ "values without keys in JsonObjects, authorized only for arrays."));
}
 
private final void clearMetadata() {
if (_ctx.peek() == JsonType.METADATA) {
_metadata.clear();
_ctx.pop();
}
}
 
protected void indent() {
if (indentation) {
if ((_len + 1) >= _bufferSize) flushBuffer();
if (_ctx.peek() != JsonType.EMPTY) _buffer[_len++] = '\n';
int len = _ctx.peek() == JsonType.METADATA ? _ctx.size() - 2 : _ctx.size() - 1;
for (int i = 0; i < len; i++)
writeToBuffer(_indentation, 0, 2);
}
}
 
public JsonWriter writeName(final String name) {
_name = escapeString(name);
return this;
}
 
public ObjectWriter writeEscapedName(char[] name) {
_name = name;
return this;
}
 
public JsonWriter writeValue(int value) {
clearMetadata();
beforeValue();
// ok so the buffer must always be bigger than the max length of a long
if ((_len + 11) >= _bufferSize) flushBuffer();
if (value < 0) {
_buffer[_len++] = '-';
writeInt(-((long) value));
} else writeInt(value);
_hasPrevious = true;
return this;
}
 
public JsonWriter writeValue(final double value) {
checkValidJsonDouble(value);
clearMetadata();
beforeValue();
writeToBuffer(Double.toString(value), 0);
_hasPrevious = true;
return this;
}
 
public JsonWriter writeValue(long value) {
clearMetadata();
beforeValue();
// ok so the buffer must always be bigger than the max length of a long
if ((_len + 21) >= _bufferSize) flushBuffer();
 
 
if (value < 0) {
if (value != Long.MIN_VALUE) {
_buffer[_len++] = '-';
writeInt(-1 * value);
} else writeToBuffer(Long.toString(value), 0);
} else writeInt(value);
 
_hasPrevious = true;
return this;
}
 
public ObjectWriter writeValue(short value) {
clearMetadata();
beforeValue();
// ok so the buffer must always be bigger than the max length of a short
if ((_len + 5) >= _bufferSize) flushBuffer();
if (value < 0) {
_buffer[_len++] = '-';
value *= -1;
}
writeInt(value);
_hasPrevious = true;
return this;
}
 
public ObjectWriter writeValue(float value) {
checkValidJsonFloat(value);
clearMetadata();
beforeValue();
writeToBuffer(Float.toString(value), 0);
_hasPrevious = true;
return this;
}
 
public JsonWriter writeValue(final boolean value) {
clearMetadata();
beforeValue();
if (value) writeToBuffer(TRUE_VALUE, 0, 4);
else writeToBuffer(FALSE_VALUE, 0, 5);
_hasPrevious = true;
return this;
}
 
protected final int writeInt(long value) {
final int len = (int) Math.log10(value) + 1;
if (value == 0) {
_buffer[_len++] = '0';
return 1;
}
 
int pos = _len + len - 1;
long intPart;
for (; value > 0; ) {
intPart = value / 10;
_buffer[pos--] = _INT_TO_CHARARRAY[(int) (value - (intPart * 10))];
value = intPart;
}
 
_len += len;
return len;
}
 
public JsonWriter writeValue(final Number value) {
checkValidJsonDouble(value);
checkValidJsonFloat(value);
clearMetadata();
beforeValue();
writeToBuffer(value.toString(), 0);
_hasPrevious = true;
return this;
}
 
public ObjectWriter writeBoolean(final Boolean value) {
if (value == null) return writeNull();
else return writeValue(value);
}
 
public ObjectWriter writeNumber(final Number value) {
if (value == null) return writeNull();
else return writeValue(value);
}
 
public ObjectWriter writeString(String value) {
if (value == null) return writeNull();
else return writeValue(value);
}
 
public ObjectWriter writeBytes(byte[] value) {
if (value == null) return writeNull();
else return writeValue(value);
}
 
private void checkValidJsonDouble(Number num) {
if (num.equals(Double.NaN))
throw new NumberFormatException("NaN is not a valid json number.");
if (num.equals(Double.NEGATIVE_INFINITY) || num.equals(Double.POSITIVE_INFINITY))
throw new NumberFormatException("Infinity is not a valid json number.");
}
 
private void checkValidJsonFloat(Number num) {
if (num.equals(Float.NaN))
throw new NumberFormatException("NaN is not a valid json number.");
if (num.equals(Float.NEGATIVE_INFINITY) || num.equals(Float.POSITIVE_INFINITY))
throw new NumberFormatException("Infinity is not a valid json number.");
}
 
public ObjectWriter writeValue(byte[] value) {
clearMetadata();
beforeValue();
 
if ((_len + 1) >= _bufferSize) flushBuffer();
_buffer[_len++] = '"';
final char[] charArray = Base64.encodeToChar(value, false);
 
writeToBuffer(charArray, 0, charArray.length);
 
if ((_len + 1) >= _bufferSize) flushBuffer();
_buffer[_len++] = '"';
_hasPrevious = true;
 
flush();
return this;
}
 
public JsonWriter writeUnsafeValue(final String value) {
clearMetadata();
beforeValue();
if ((_len + 1) >= _bufferSize) flushBuffer();
_buffer[_len++] = '"';
writeToBuffer(value.toCharArray(), 0, value.length());
if ((_len + 1) >= _bufferSize) flushBuffer();
_buffer[_len++] = '"';
_hasPrevious = true;
return this;
}
 
public JsonWriter writeValue(final String value) {
clearMetadata();
beforeValue();
writeInternalString(value);
return this;
}
 
public final static char[] escapeString(final String value) {
StringBuilder sb = new StringBuilder();
int last = 0;
final int length = value.length();
for (int i = 0; i < length; i++) {
char c = value.charAt(i);
char[] replacement;
if (c < 128) {
replacement = REPLACEMENT_CHARS[c];
if (replacement == null) {
continue;
}
} else if (c == '\u2028') {
replacement = "\\u2028".toCharArray();
} else if (c == '\u2029') {
replacement = "\\u2029".toCharArray();
} else {
continue;
}
if (last < i) {
sb.append(value, last, i - last);
}
sb.append(replacement, 0, replacement.length);
last = i + 1;
}
if (last < length) {
sb.append(value, last, length);
}
 
return sb.toString().toCharArray();
}
 
private final void writeInternalString(final String value) {
final char[][] replacements = htmlSafe ? HTML_SAFE_REPLACEMENT_CHARS : REPLACEMENT_CHARS;
if ((_len + 1) >= _bufferSize) flushBuffer();
_buffer[_len++] = '"';
int last = 0;
final int length = value.length();
final char[] carray = value.toCharArray();
for (int i = 0; i < length; i++) {
char c = carray[i];
char[] replacement;
if (c < 128) {
replacement = replacements[c];
if (replacement == null) {
continue;
}
} else if (c == '\u2028') {
replacement = "\\u2028".toCharArray();
} else if (c == '\u2029') {
replacement = "\\u2029".toCharArray();
} else {
continue;
}
if (last < i) {
writeToBuffer(carray, last, i - last);
}
 
writeToBuffer(replacement, 0, replacement.length);
last = i + 1;
}
if (last < length) {
writeToBuffer(carray, last, length - last);
}
if ((_len + 1) >= _bufferSize) flushBuffer();
 
_buffer[_len++] = '"';
 
_hasPrevious = true;
}
 
public ObjectWriter writeNull() {
if (skipNull) {
_name = null;
} else {
beforeValue();
writeToBuffer(NULL_VALUE, 0, 4);
_hasPrevious = true;
}
return this;
}
 
public ObjectWriter beginNextObjectMetadata() {
// this way we can use this method multiple times in different converters before calling beginObject
if (_ctx.peek() != JsonType.METADATA) {
_ctx.push(JsonType.METADATA);
_metadata.clear();
}
return this;
}
 
public ObjectWriter writeMetadata(String name, String value) {
if (_ctx.peek() == JsonType.METADATA) _metadata.add(new MetadataPair(name, value));
else if (_ctx.peek() == JsonType.OBJECT) {
writeName('@' + name);
writeValue(value);
}
// else do nothing so we silently don't write metadata for literals and arrays
return this;
}
 
public ObjectWriter writeBoolean(String name, Boolean value) {
writeName(name);
return writeBoolean(value);
}
 
public ObjectWriter writeNumber(String name, Number value) {
writeName(name);
return writeNumber(value);
}
 
public ObjectWriter writeString(String name, String value) {
writeName(name);
return writeString(value);
}
 
public ObjectWriter writeBytes(String name, byte[] value) {
writeName(name);
return writeBytes(value);
}
 
private final void writeToBuffer(final char[] data, final int offset, final int length) {
if (length < _LIMIT_WRITE_TO_BUFFER && length < (_bufferSize - _len)) {
System.arraycopy(data, offset, _buffer, _len, length);
_len += length;
} else {
flushBuffer();
try {
writer.write(data, offset, length);
} catch (IOException e) {
throw new JsonStreamException(e);
}
}
}
 
private final void writeToBuffer(final String data, final int offset) {
writeToBuffer(data, offset, data.length());
}
 
private final void writeToBuffer(final String data, final int offset, final int length) {
if (length < _LIMIT_WRITE_TO_BUFFER && length < (_bufferSize - _len)) {
data.getChars(offset, offset + length, _buffer, _len);
_len += length;
} else {
flushBuffer();
try {
writer.write(data, offset, length);
} catch (IOException e) {
throw new JsonStreamException(e);
}
}
}
 
private final void flushBuffer() {
try {
if (_len > 0) {
writer.write(_buffer, 0, _len);
_len = 0;
}
} catch (IOException ioe) {
throw new JsonStreamException(ioe);
}
}
 
public Writer unwrap() {
return writer;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/stream/ObjectReader.java
New file
0,0 → 1,236
package com.owlike.genson.stream;
 
import java.io.Closeable;
import java.io.IOException;
 
/**
* ObjectReader is part of the streaming api, it's implementations allow you to read data from the
* stream. The root of the input should always be a object, an array or a literal. There may be some
* differences between implementations if they try to be compliant with their format specification.
* <p/>
* <ul>
* <li>To read an array call {@link #beginArray()} then use {@link #hasNext()} to check if there is
* a next element and then call {@link #next()} to advance. When you call next in an array it will
* read the next value and return its type {@link ValueType}. Use it to check values type and to
* retrieve its value (if it is a literal) use one of valueAsXXX methods, otherwise it is an array
* or object. When hasNext returns false terminate the array by calling {@link #endArray()}.
* <li>To read a object call {@link #beginObject()} then use {@link #hasNext()} to check if there is
* a next property and then call {@link #next()} to read the name/value pair and {@link #name()} to
* retrieve its name. If the value is a literal retrieve its value with valueAsXXX methods,
* otherwise it is an array or object. When you finished reading all properties call
* {@link #endObject()}.
* <li>Objects can also contain metadata as their first properties. To read object metadata you have
* two options:
* <ol>
* <li>Just begin your object with beginObject and then retrieve the metadata that you want with
* {@link #metadata(String) metadata(nameOfTheMetadataProperty)}.
* <li>Use {@link #nextObjectMetadata()} to read the next objects metadata without calling
* beginObject. This is useful when you want to handle some metadata in a converter and then
* delegate the rest to another converter (that will call beginObject or again nextObjectMetadata,
* so for him it will be transparent that you retrieved already some metadata and he will still be
* able to retrieve the same data).
* </ol>
* <li>To read a literal use valueAsXXX methods. Actual implementation allows literals as root and
* is relatively tolerant to wrong types, for example if the stream contains the string "123" but
* you want to retrieve it as a int, {@link JsonReader#valueAsInt()} will parse it and return 123.
* It does also conversion between numeric types (double <-> int etc).
* <li>To skip a value use {@link #skipValue()}. If the value is an object or an array it will skip
* all its content.
* </ul>
* <p/>
* Here is an example if you want to use directly the streaming api instead of the databind api (or
* if you write a custom converter or deserializer).
* <p/>
* <pre>
* public static void main(String[] args) {
* // we will read from json to Person
* Person.read(new JsonReader(&quot;{\&quot;name\&quot;:\&quot;eugen\&quot;,\&quot;age\&quot;:26, \&quot;childrenYearOfBirth\&quot;:[]}&quot;));
* }
*
* class Person {
* String name;
* int age;
* List&lt;Integer&gt; childrenYearOfBirth;
*
* public static Person read(ObjectReader reader) {
* Person p = new Person();
* for (; reader.hasNext();) {
* if (&quot;name&quot;.equals(reader.name()))
* p.name = reader.valueAsString();
* else if (&quot;age&quot;.equals(reader.name()))
* p.age = reader.valueAsInt();
* else if (&quot;childrenYearOfBirth&quot;.equals(reader.name())) {
* if (reader.getValueType() == TypeValue.NULL)
* p.childrenYearOfBirth = null;
* else {
* reader.beginArray();
* p.childrenYearOfBirth = new ArrayList&lt;Integer&gt;();
* for (int i = 0; reader.hasNext(); i++)
* p.childrenYearOfBirth.add(reader.valueAsInt());
* reader.endArray();
* }
* }
* }
* return p;
* }
* }
* </pre>
*
* @author eugen
* @see ValueType
* @see JsonReader
* @see ObjectWriter
* @see JsonWriter
*/
public interface ObjectReader extends Closeable {
/**
* Starts reading a object. Objects contain name/value pairs. Call {@link #endObject()} when the
* objects contains no more properties.
*
* @return a reference to the reader.
* @throws JsonStreamException
*/
ObjectReader beginObject();
 
/**
* Ends the object. If you were not in an object or the object contains more data, an exception
* will be thrown.
*
* @return a reference to the reader.
* @throws JsonStreamException
*/
ObjectReader endObject();
 
/**
* Starts reading an array. Arrays contain only values. Call {@link #endArray()} when the array
* contains no more values.
*
* @return a reference to the reader.
* @throws JsonStreamException
*/
ObjectReader beginArray();
 
/**
* Ends the array. If you were not in an array or the array contains more data, an exception
* will be thrown.
*
* @return a reference to the reader.
* @throws JsonStreamException
*/
ObjectReader endArray();
 
/**
* Will read nexts object metadata. You can call this method as many times as you want, with the
* condition that you use only {@link #metadata(String)} method. For example if you call
* {@link #beginObject()} you wont be able to do it anymore (however you still can retrieve the
* metadata!).
*
* @return a reference to the reader.
* @throws JsonStreamException
*/
ObjectReader nextObjectMetadata();
 
/**
* If we are in a object it will read the next name/value pair and if we are in an array it will
* read the next value (except if value is of complex type, in that case after the call to
* next() you must use one of beginXXX methods).
*
* @return the type of the value, see {@link ValueType} for possible types.
* @throws JsonStreamException
*/
ValueType next();
 
/**
* @return true if there is a next property or value, false otherwise.
* @throws JsonStreamException
*/
boolean hasNext();
 
/**
* If the value is of complex type it will skip its content.
*
* @return a reference to the reader.
* @throws JsonStreamException
*/
ObjectReader skipValue();
 
/**
* @return The type of current value.
* @see ValueType
*/
ValueType getValueType();
 
/**
* @param name the name of the metadata to retrieve.
* @return value of metadata with name as key or null if there is no such metadata.
* @throws JsonStreamException
*/
String metadata(String name);
 
/**
* @return the name of current property, valid only if we are in a object and you called
* {@link #next()} before.
* @throws JsonStreamException
*/
String name();
 
/**
* @return the current value as a String. It will try to convert the actual value to String if
* its not of that type.
* @throws JsonStreamException
*/
String valueAsString();
 
/**
* @throws JsonStreamException
* @throws NumberFormatException
* @see #valueAsString()
*/
int valueAsInt();
 
/**
* @throws JsonStreamException
* @throws NumberFormatException
* @see #valueAsString()
*/
long valueAsLong();
 
/**
* @throws JsonStreamException
* @throws NumberFormatException
* @see #valueAsString()
*/
double valueAsDouble();
 
/**
* @throws JsonStreamException
* @throws NumberFormatException
* @see #valueAsString()
*/
short valueAsShort();
 
/**
* @throws JsonStreamException
* @throws NumberFormatException
* @see #valueAsString()
*/
float valueAsFloat();
 
/**
* @throws JsonStreamException
* @see #valueAsString()
*/
boolean valueAsBoolean();
 
/**
* @return the incoming base64 string converted to a byte array.
* @throws JsonStreamException
*/
byte[] valueAsByteArray();
 
JsonType enclosingType();
 
int column();
 
int row();
}
/branches/grupo4/impl/src/java/com/owlike/genson/stream/JsonType.java
New file
0,0 → 1,8
package com.owlike.genson.stream;
 
public enum JsonType {
EMPTY,
OBJECT,
ARRAY,
METADATA
}
/branches/grupo4/impl/src/java/com/owlike/genson/stream/JsonReader.java
New file
0,0 → 1,972
package com.owlike.genson.stream;
 
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
 
import static com.owlike.genson.stream.ValueType.*;
 
public class JsonReader implements ObjectReader {
 
protected final static int[] SKIPPED_TOKENS;
 
static {
SKIPPED_TOKENS = new int[128];
SKIPPED_TOKENS['\t'] = 1;
SKIPPED_TOKENS['\b'] = 1;
SKIPPED_TOKENS['\n'] = 1;
SKIPPED_TOKENS['\r'] = 1;
SKIPPED_TOKENS['\f'] = 1;
SKIPPED_TOKENS[' '] = 1;
}
 
private final static boolean[] _NEXT_TOKEN = new boolean[128];
 
static {
_NEXT_TOKEN[','] = true;
_NEXT_TOKEN['"'] = true;
_NEXT_TOKEN['{'] = true;
_NEXT_TOKEN['['] = true;
_NEXT_TOKEN['n'] = true;
_NEXT_TOKEN['N'] = true;
_NEXT_TOKEN['-'] = true;
_NEXT_TOKEN['t'] = true;
_NEXT_TOKEN['f'] = true;
_NEXT_TOKEN['T'] = true;
_NEXT_TOKEN['F'] = true;
 
for (int i = 48; i < 58; i++)
_NEXT_TOKEN[i] = true;
}
 
private final static char[] _END_OF_LINE = new char[]{'\n'};
private final static char[] _END_OF_BLOCK_COMMENT = new char[]{'*', '/'};
 
/*
* Recupere dans Jackson
*/
private final static int[] sHexValues = new int[128];
 
static {
Arrays.fill(sHexValues, -1);
for (int i = 0; i < 10; ++i) {
sHexValues['0' + i] = i;
}
for (int i = 0; i < 6; ++i) {
sHexValues['a' + i] = 10 + i;
sHexValues['A' + i] = 10 + i;
}
}
 
private final static double[] _POWS = new double[309];
 
static {
for (int i = 0; i < _POWS.length; i++)
_POWS[i] = Math.pow(10, i);
}
 
private final Reader reader;
private final boolean strictDoubleParse;
private final boolean readMetadata;
private final char[] _buffer = new char[2048];
private int _col;
private int _row;
private int _cursor;
private int _buflen;
 
private char[] _stringBuffer = new char[16];
private int _stringBufferTail = 0;
private int _stringBufferLength = _stringBuffer.length;
 
private String currentName;
private String _stringValue;
protected long _intValue;
protected double _doubleValue;
private int _numberLen = 0;
private Boolean _booleanValue;
private ValueType valueType;
private boolean _first = true;
private boolean _metadata_readen = false;
private Map<String, String> _metadata = new HashMap<String, String>(5);
 
private final Deque<JsonType> _ctx = new ArrayDeque<JsonType>(10);
 
{
_ctx.push(JsonType.EMPTY);
}
 
public JsonReader(String source) {
this(new StringReader(source), false, false);
}
 
public JsonReader(Reader reader, boolean strictDoubleParse, boolean readMetadata) {
this.reader = reader;
this.strictDoubleParse = strictDoubleParse;
this.readMetadata = readMetadata;
 
char token = (char) readNextToken(false);
if ('[' == token) valueType = ARRAY;
else if ('{' == token) valueType = OBJECT;
else {
// ok lets try to read next
if (_buflen > 0) {
try {
valueType = consumeValue();
} catch (JsonStreamException jse) {
try {
// we must cheat because consumeString attends the current token to be "
// and will increment the cursor
_cursor = -1;
_col = -1;
_stringValue = consumeString('"');
valueType = STRING;
} catch (RuntimeException re) {
throw re;
}
}
if (valueOf(valueType.name()) == null)
throw new JsonStreamException(
"Failed to instanciate reader, first character was " + (char) token
+ " when possible characters are [ and {");
} else valueType = NULL;
}
}
 
public void close() {
try {
reader.close();
} catch (IOException e) {
throw new JsonStreamException(e);
}
}
 
public ObjectReader beginArray() {
begin('[', JsonType.ARRAY);
valueType = ARRAY;
if (_metadata_readen) _metadata.clear();
return this;
}
 
public ObjectReader beginObject() {
if (!_metadata_readen) {
begin('{', JsonType.OBJECT);
valueType = OBJECT;
if (readMetadata) {
_metadata.clear();
readMetadata();
}
}
return this;
}
 
public ObjectReader nextObjectMetadata() {
return beginObject();
}
 
public ObjectReader endArray() {
end(']', JsonType.ARRAY);
return this;
}
 
public ObjectReader endObject() {
end('}', JsonType.OBJECT);
_metadata.clear();
_metadata_readen = false;
return this;
}
 
public String name() {
if (enclosingType() != JsonType.OBJECT)
throw new JsonStreamException("Only json objects have names, actual type is "
+ valueType);
return currentName;
}
 
public String valueAsString() {
if (STRING == valueType) return _stringValue;
if (INTEGER == valueType) return "" + _intValue;
if (DOUBLE == valueType) return "" + _doubleValue;
if (NULL == valueType) return null;
if (BOOLEAN == valueType) {
return _booleanValue.toString();
}
throw new JsonStreamException("Readen value can not be converted to String");
}
 
public int valueAsInt() {
if (INTEGER == valueType) {
int value = (int) _intValue;
if (value != _intValue) throwNumberFormatException("an int", "overflowing long value " + _intValue);
return value;
} else if (DOUBLE == valueType) {
int value = (int) _doubleValue;
long longValue = (long) _doubleValue;
// lets accept only if the integer part is the same and ignore the decimals
if (value != longValue) {
throwNumberFormatException("an int", "overflowing double value " + _doubleValue);
}
return value;
} else if (STRING == valueType) return Integer.parseInt(_stringValue);
 
throw new JsonStreamException("Expected a int but value is of type " + valueType);
}
 
public long valueAsLong() {
if (INTEGER == valueType) {
return _intValue;
} else if (DOUBLE == valueType) {
if (Long.MIN_VALUE > _doubleValue || _doubleValue > Long.MAX_VALUE) {
throwNumberFormatException("a long", "overflowing double value " + _doubleValue);
}
return (long) _doubleValue;
} else if (STRING == valueType) return Long.parseLong(_stringValue);
 
throw new JsonStreamException("Expected a long but value is of type " + valueType);
}
 
public double valueAsDouble() {
if (DOUBLE == valueType) {
return _doubleValue;
} else if (INTEGER == valueType) {
// for the moment lets do that even if there is some precision loss...
return Long.valueOf(_intValue).doubleValue();
} else if (STRING == valueType) return Double.parseDouble(_stringValue);
 
throw new JsonStreamException("Expected a double but value is of type " + valueType);
}
 
public short valueAsShort() {
if (INTEGER == valueType) {
short value = (short) _intValue;
if (value != _intValue) throwNumberFormatException("a short", "overflowing long value " + _intValue);
return value;
} else if (DOUBLE == valueType) {
short value = (short) _doubleValue;
long longValue = (long) _doubleValue;
// lets accept only if the integer part is the same and ignore the decimals
if (value != longValue) {
throwNumberFormatException("a short", "overflowing double value " + _doubleValue);
}
return value;
} else if (STRING == valueType) return Short.parseShort(_stringValue);
 
throw new JsonStreamException("Expected a short but value is of type " + valueType);
}
 
public float valueAsFloat() {
if (DOUBLE == valueType) {
return (float) _doubleValue;
} else if (INTEGER == valueType) {
// same as for doubles, for the moment lets do that even if there is some precision
// loss...
return Long.valueOf(_intValue).floatValue();
} else if (STRING == valueType) return Float.parseFloat(_stringValue);
 
throw new JsonStreamException("Expected a float but value is of type " + valueType);
}
 
public boolean valueAsBoolean() {
if (BOOLEAN == valueType) {
return _booleanValue;
}
if (STRING == valueType) return Boolean.parseBoolean(_stringValue);
 
throw new JsonStreamException("Readen value is not of type boolean");
}
 
public byte[] valueAsByteArray() {
if (STRING == valueType) return Base64.decodeFast(_stringValue);
if (NULL == valueType) return null;
throw new JsonStreamException("Expected a String to convert to byte array found "
+ valueType);
}
 
public String metadata(String name) {
if (!_metadata_readen) nextObjectMetadata();
return _metadata.get(name);
}
 
public ValueType getValueType() {
return valueType;
}
 
public ObjectReader skipValue() {
 
if (ARRAY == valueType || OBJECT == valueType) {
int balance = 0;
do {
if (ARRAY == valueType) {
beginArray();
balance++;
} else if (OBJECT == valueType) {
beginObject();
balance++;
}
 
while (hasNext()) {
next();
skipValue();
}
 
JsonType type = _ctx.peek();
if (JsonType.ARRAY == type) {
endArray();
balance--;
} else if (JsonType.OBJECT == type) {
endObject();
balance--;
}
} while (balance > 0);
}
 
return this;
}
 
public boolean hasNext() {
int token = readNextToken(false);
if (token == -1) return false;
if (token < 128) {
if (_first || _ctx.size() == 1) return _NEXT_TOKEN[token];
else if (token == ',') return true;
}
 
return false;
}
 
public ValueType next() {
_metadata_readen = false;
_first = false;
 
char ctoken = (char) readNextToken(false);
 
if (ctoken == ',') {
_cursor++;
ctoken = (char) readNextToken(false);
} else if (JsonType.ARRAY == _ctx.peek()) {
if (ctoken == '[') {
valueType = ARRAY;
return valueType;
}
if (ctoken == '{') {
valueType = OBJECT;
return valueType;
}
}
 
if (JsonType.OBJECT == _ctx.peek()) {
currentName = consumeString(ctoken);
if (readNextToken(true) != ':') newWrongTokenException(":", _cursor - 1);
}
 
valueType = consumeValue();
return valueType;
}
 
@Override
public JsonType enclosingType() {
return _ctx.peek();
}
 
protected final ValueType consumeValue() {
char ctoken = (char) readNextToken(false);
if (ctoken == '"') {
_stringValue = consumeString(ctoken);
return STRING;
} else if (ctoken == '[') return ARRAY;
else if (ctoken == '{') return OBJECT;
else return consumeLiteral();
}
 
protected final void readMetadata() {
_metadata_readen = true;
while (true) {
char ctoken = (char) readNextToken(false);
if ('"' != ctoken) return;
ensureBufferHas(2, true);
 
if ('@' == _buffer[_cursor + 1]) {
_cursor++;
// we cheat here...
String key = consumeString(ctoken);
 
if (readNextToken(true) != ':') newWrongTokenException(":", _cursor - 1);
 
String value = consumeString((char) readNextToken(false));
_metadata.put(key, value);
if (readNextToken(false) == ',') {
_cursor++;
}
} else return;
}
}
 
protected final void begin(int character, JsonType type) {
int token = readNextToken(true);
// seems unecessary as it is done in readNextToken
// checkIllegalEnd(token);
if (character == token) {
_ctx.push(type);
} else newWrongTokenException("" + (char) character, _cursor - 1);
_first = true;
}
 
protected final void end(int character, JsonType type) {
int token = readNextToken(true);
// seems unecessary as it is done in readNextToken
// checkIllegalEnd(token);
if (character == token && type == _ctx.peek()) {
_ctx.pop();
} else newWrongTokenException("" + (char) character, _cursor - 1);
_first = false;
}
 
protected final String consumeString(int token) {
if (token != '"') newMisplacedTokenException(_cursor);
_cursor++;
boolean buffered = false;
while (true) {
if (fillBuffer(true) < 0) {
// TODO ugly to copy, by the way ensure we don't have the same problem elsewhere
String name = new String(_stringBuffer, 0, _stringBufferTail);
_stringBufferTail = 0;
return name;
}
 
int i = _cursor;
for (; i < _buflen; ) {
if (_buffer[i] == '"') {
if (buffered) {
writeToStringBuffer(_buffer, _cursor, i - _cursor);
_cursor = i + 1;
String name = new String(_stringBuffer, 0, _stringBufferTail);
_stringBufferTail = 0;
return name;
} else {
String name = new String(_buffer, _cursor, i - _cursor);
_cursor = i + 1;
return name;
}
} else if (_buffer[i] == '\\') {
buffered = true;
writeToStringBuffer(_buffer, _cursor, i - _cursor);
_cursor = i + 1;
if (_stringBufferLength <= (_stringBufferTail + 1)) expandStringBuffer(16);
_stringBuffer[_stringBufferTail++] = readEscaped();
i = _cursor;
} else i++;
}
 
buffered = true;
writeToStringBuffer(_buffer, _cursor, i - _cursor);
_cursor = i + 1;
}
}
 
/**
* Reads the next literal value into _booleanValue, _doubleValue or _intValue and returns the
* type of the readed literal, possible values are : INTEGER, DOUBLE, BOOLEAN, NULL. When
* calling this method the _cursor must be positioned on the first character of the value in the
* _buffer, you can ensure that by calling {@link #readNextToken(boolean)}.
*/
protected final ValueType consumeLiteral() {
int token = _buffer[_cursor];
 
if ((token > 47 && token < 58) || token == 45) {
return consumeNumber();
} else {
ensureBufferHas(4, true);
 
if ((_buffer[_cursor] == 'N' || _buffer[_cursor] == 'n')
&& (_buffer[_cursor + 1] == 'U' || _buffer[_cursor + 1] == 'u')
&& (_buffer[_cursor + 2] == 'L' || _buffer[_cursor + 2] == 'l')
&& (_buffer[_cursor + 3] == 'L' || _buffer[_cursor + 3] == 'l')) {
_cursor += 4;
return NULL;
}
 
if ((_buffer[_cursor] == 'T' || _buffer[_cursor] == 't')
&& (_buffer[_cursor + 1] == 'R' || _buffer[_cursor + 1] == 'r')
&& (_buffer[_cursor + 2] == 'U' || _buffer[_cursor + 2] == 'u')
&& (_buffer[_cursor + 3] == 'E' || _buffer[_cursor + 3] == 'e')) {
_booleanValue = true;
_cursor += 4;
return BOOLEAN;
}
ensureBufferHas(5, true);
 
if ((_buffer[_cursor] == 'F' || _buffer[_cursor] == 'f')
&& (_buffer[_cursor + 1] == 'A' || _buffer[_cursor + 1] == 'a')
&& (_buffer[_cursor + 2] == 'L' || _buffer[_cursor + 2] == 'l')
&& (_buffer[_cursor + 3] == 'S' || _buffer[_cursor + 3] == 's')
&& (_buffer[_cursor + 4] == 'E' || _buffer[_cursor + 4] == 'e')) {
_booleanValue = false;
_cursor += 5;
return BOOLEAN;
} else {
throw new JsonStreamException.Builder().message(
"Illegal character around row " + _row + " and column " + (_cursor - _col)
+ " awaited for literal (number, boolean or null) but read '"
+ _buffer[_cursor] + "'!").create();
}
}
}
 
private ValueType consumeNumber() {
// lets fill the buffer and handle differently overflowing values
if ((_buflen - _cursor) < 378) ensureBufferHas(_buflen, false);
 
int begin = _cursor;
int cur;
boolean negative;
// check the sign
if (_buffer[_cursor] == 45) {
negative = true;
_cursor++;
cur = _cursor;
} else {
negative = false;
cur = _cursor;
}
// just to handle invalid leading 0000
for (; cur < _buflen && _buffer[cur] == 48; cur++) ;
// Careful we consume the '-' here, but also all the leading 0, even if it is of form 0.xxx
_cursor = cur;
 
int len = Math.min(_buflen, cur + 18);
int token;
 
long longValue = 0;
for (; cur < len; cur++) {
token = _buffer[cur];
if (token < 48 || token > 57) {
break;
}
longValue = 10L * longValue + (token - 48);
}
 
if (cur < _buflen) {
// read the maximum we can to fill the long capacity, at max we can read 1 additional
// digit
token = _buffer[cur];
if (token > 47 && token < 58) {
long newLongValue = 10L * longValue + (token - 48);
if (newLongValue > longValue) {
longValue = newLongValue;
cur++;
}
/* TODO we parse here Long.MIN_VALUE as a double, we had also pb in the writer
* the solution => instead of doing operations on positive numbers, do the inverse, use negative numbers
* as the min negative long holds the - max positive long.
*/
// else we exceed long capacity, just continue and parse it as a double
}
 
if (cur < _buflen
&& ((token = _buffer[cur]) == 46 || token == 101 || token == 69 || (token > 47 && token < 58))) {
 
if (strictDoubleParse) {
_cursor = begin;
return consumeStrictNumber(cur);
} else return consumeDouble(cur, longValue, negative);
}
}
 
_intValue = negative ? -longValue : longValue;
_numberLen = cur - _cursor;
_cursor = cur;
return INTEGER;
}
 
// a custom implementation based on fast path principles
private ValueType consumeDouble(int cur, long longValue, boolean negative) {
int token;
 
// TODO a verifier : on ne veut compter dans les intDigit que ce qui n'est pas pris dans le
// longValue, idem pour les decimales??
int intDigits = cur - _cursor;
int valueDigits = longValue > 0 ? cur - _cursor : 0;
 
// ok we have readen as many characters as a long can contain
// the next readen characters will serve for the digit count for large integer numbers
if (intDigits > 17) {
for (; cur < _buflen; cur++) {
if (_buffer[cur] < 48 || _buffer[cur] > 57) {
break;
}
}
// only if we advanced
if (intDigits != (cur - _cursor)) intDigits = (cur - _cursor) - intDigits;
} else
// TODO check ça m'a l'air bizarre comme cas...
intDigits = 0;
 
int decimalDigits = 0;
 
// next possible case is a dot
if (cur < _buflen && _buffer[cur] == 46) {
cur++;
int start = cur;
// if integer part value is zero we could use scientific notation and win in precision
if (longValue == 0) {
// reset the counter as we don't care of the leading zeros
intDigits = 0;
// now lets try to read as many consecutive zeros as available
for (; cur < _buflen && _buffer[cur] == 48; cur++) ;
}
// ok now we must read again into the longValue
int len = Math.min(_buflen, cur + (18 - valueDigits));
 
for (; cur < len; cur++) {
token = _buffer[cur];
if (token < 48 || token > 57) {
break;
}
longValue = 10L * longValue + (token - 48);
}
decimalDigits = cur - start;
 
start = cur;
// no need to count digits after the precision we support for decimals
// continue reading digits and just ignore the values, we will truncate
for (; cur < _buflen; cur++) {
if (_buffer[cur] < 48 || _buffer[cur] > 57) {
break;
}
}
}
 
// now try to read exponent E/e
if ((cur + 1) < _buflen && (_buffer[cur] == 101 || _buffer[cur] == 69)) {
token = _buffer[++cur];
boolean negativeExp;
// check the sign
if (token == 45) {
negativeExp = true;
cur++;
} else {
if (token == 43) cur++;
negativeExp = false;
}
// read the power of ten
int powValue = 0;
for (; cur < _buflen; cur++) {
token = _buffer[cur];
if (token < 48 || token > 57) {
break;
}
powValue = 10 * powValue + (token - 48);
}
 
// depending on the sign put it in the decimal digit counter or integer digit counter
if (negativeExp) decimalDigits += powValue;
else intDigits += powValue;
}
 
// and now make the difference so it balances well
decimalDigits = intDigits - decimalDigits;
 
if (decimalDigits < 0) {
/*
* This allows to handle also Double.MIN_VALUE and Double.MIN_NORMAL as
* Double.MIN_NORMAL has 16 decimal digits, 308+16=324, but 10^324 overflows the double
* capacity, its Infinity. So we use this little trick.
*/
if (decimalDigits < -308) {
if (decimalDigits < -325) {
_doubleValue = 0;
} else {
_doubleValue = longValue / _POWS[-decimalDigits - 308];
_doubleValue = _doubleValue / _POWS[308];
}
} else {
// better precision than multiplication
_doubleValue = longValue / _POWS[-decimalDigits];
}
} else {
if (decimalDigits > 308) {
_doubleValue = Double.POSITIVE_INFINITY;
} else {
// we don't need to apply same technique as before as
// 308-16=292 so it's okay :)
_doubleValue = longValue * _POWS[decimalDigits];
}
}
 
_doubleValue = negative ? -_doubleValue : _doubleValue;
_numberLen = cur - _cursor;
_cursor = cur;
return DOUBLE;
}
 
private final ValueType consumeStrictNumber(int localCursor) {
if (localCursor < _buflen) {
// consider all the remaining integer values as part of the double
for (; localCursor < _buflen; localCursor++) {
if (_buffer[localCursor] < 48 || _buffer[localCursor] > 57) {
break;
}
}
}
 
if (localCursor < _buflen) {
if (_buffer[localCursor] == '.') {
localCursor = advanceWhileNumeric(++localCursor);
}
}
 
if (localCursor + 1 < _buflen) {
char ctoken = _buffer[localCursor];
if (ctoken == 'e' || ctoken == 'E') {
ctoken = _buffer[++localCursor];
if (ctoken == '-' || ctoken == '+' || (ctoken > 47 && ctoken < 58)) {
localCursor = advanceWhileNumeric(++localCursor);
} else newWrongTokenException("'-' or '+' or '' (same as +)");
}
}
 
// it may overflow of the max numeric value we accept to read, it should
if (localCursor >= _buflen) {
 
}
 
_numberLen = localCursor - _cursor;
_stringValue = new String(_buffer, _cursor, _numberLen);
_doubleValue = Double.parseDouble(_stringValue);
_cursor = localCursor;
return DOUBLE;
}
 
private int advanceWhileNumeric(int cursor) {
for (; cursor < _buflen; cursor++) {
if ((_buffer[cursor] < 48 || _buffer[cursor] > 57)) {
return cursor;
}
}
return cursor;
}
 
protected final int readNextToken(boolean consume) {
while (true) {
if (_cursor >= _buflen) fillBuffer(true);
 
for (; _cursor < _buflen; _cursor++) {
int token = _buffer[_cursor];
if (token < 128 && SKIPPED_TOKENS[token] == 0) {
if (token == '/') {
ensureBufferHas(2, true);
if (_buffer[_cursor + 1] == '*') {
_cursor += 2;
advanceAfter(_END_OF_BLOCK_COMMENT);
} else if (_buffer[_cursor + 1] == '/') {
_cursor += 2;
advanceAfter(_END_OF_LINE);
_row++;
_col = _cursor;
} else newWrongTokenException("start comment // or /*", _cursor);
// don't consume the token
_cursor--;
} else if (consume) {
return _buffer[_cursor++];
} else return token;
} else if (_buffer[_cursor] == '\n') {
_row++;
_col = _cursor;
}
}
 
if (_buflen == -1) break;
}
 
return _cursor < _buflen ? _buffer[_cursor] : -1;
}
 
private final void advanceAfter(char[] str) {
int strPos = 0;
while (true) {
if (_cursor >= _buflen) fillBuffer(true);
 
for (; _cursor < _buflen && strPos < str.length; _cursor++) {
if (_buffer[_cursor] == str[strPos]) {
strPos++;
} else strPos = 0;
}
 
if (strPos == str.length) {
return;
}
if (_buflen == -1) break;
}
}
 
protected final char readEscaped() {
fillBuffer(true);
 
char token = _buffer[_cursor++];
switch (token) {
case 'b':
return '\b';
case 't':
return '\t';
case 'n':
return '\n';
case 'f':
return '\f';
case 'r':
return '\r';
case '"':
case '/':
case '\\':
return token;
 
case 'u':
break;
 
default:
newMisplacedTokenException(_cursor - 1);
}
 
int value = 0;
if (ensureBufferHas(4, false) < 0) {
throw new JsonStreamException("Expected 4 hex-digit for character escape sequence!");
// System.arraycopy(buffer, cursor, buffer, 0, buflen-cursor);
// buflen = buflen - cursor + reader.read(buffer, buflen-cursor, cursor);
// cursor = 0;
}
for (int i = 0; i < 4; ++i) {
int ch = _buffer[_cursor++];
int digit = (ch > 127) ? -1 : sHexValues[ch];
if (digit < 0) {
throw new JsonStreamException("Wrong character '" + ch
+ "' expected a hex-digit for character escape sequence!");
}
value = (value << 4) | digit;
}
 
return (char) value;
}
 
private final void writeToStringBuffer(final char[] data, final int offset, final int length) {
if (_stringBufferLength <= (_stringBufferTail + length)) {
expandStringBuffer(length);
}
System.arraycopy(data, offset, _stringBuffer, _stringBufferTail, length);
_stringBufferTail += length;
}
 
private final void expandStringBuffer(int length) {
char[] extendedStringBuffer = new char[_stringBufferLength * 2 + length];
System.arraycopy(_stringBuffer, 0, extendedStringBuffer, 0, _stringBufferTail);
_stringBuffer = extendedStringBuffer;
_stringBufferLength = extendedStringBuffer.length;
}
 
private final int fillBuffer(boolean doThrow) {
if (_cursor < _buflen) return _buflen;
try {
_buflen = reader.read(_buffer);
} catch (IOException ioe) {
throw new JsonStreamException(ioe);
}
checkIllegalEnd(_buflen);
_cursor = 0;
_col = 0;
return _buflen;
}
 
private final int ensureBufferHas(int minLength, boolean doThrow) {
try {
int actualLen = _buflen - _cursor;
if (actualLen >= minLength) {
return actualLen;
}
 
System.arraycopy(_buffer, _cursor, _buffer, 0, actualLen);
for (; actualLen < minLength; ) {
int len = reader.read(_buffer, actualLen, _buffer.length - actualLen);
if (len < 0) {
if (doThrow) throw new JsonStreamException(
"Encountered end of stream, incomplete json!");
else {
_buflen = actualLen;
_col = 0;
_cursor = 0;
return len;
}
}
actualLen += len;
}
_buflen = actualLen;
_col = 0;
_cursor = 0;
return actualLen;
} catch (IOException ioe) {
throw new JsonStreamException(ioe);
}
}
 
protected final boolean isEOF() {
return _buflen < 0 || fillBuffer(false) < 0;
}
 
private final void newWrongTokenException(String awaited) {
newWrongTokenException(awaited, _cursor);
}
 
public int column() {
int col = _cursor - _col;
return col < 0 ? 0 : col;
}
 
public int row() {
return _row;
}
 
private final void newWrongTokenException(String awaited, int cursor) {
// otherwise it fails when an error occurs on first character
if (cursor < 0) cursor = 0;
int pos = cursor - _col;
if (pos < 0) pos = 0;
 
if (_buflen < 0) throw new JsonStreamException(
"Incomplete data or malformed json : encoutered end of stream but expected "
+ awaited).niceTrace();
else throw new JsonStreamException.Builder()
.message(
"Illegal character at row " + _row + " and column " + pos + " expected "
+ awaited + " but read '" + _buffer[cursor] + "' !")
.locate(_row, pos).create().niceTrace();
}
 
private final void newMisplacedTokenException(int cursor) {
if (_buflen < 0)
throw JsonStreamException.niceTrace(new JsonStreamException(
"Incomplete data or malformed json : encoutered end of stream."));
 
if (cursor < 0) cursor = 0;
int pos = cursor - _col;
if (pos < 0) pos = 0;
 
throw new JsonStreamException.Builder()
.message(
"Encountred misplaced character '" + _buffer[cursor] + "' around row "
+ _row + " and column " + pos).locate(_row, pos).create().niceTrace();
}
 
private final void checkIllegalEnd(int token) {
if (token == -1 && JsonType.EMPTY != _ctx.peek())
throw new JsonStreamException(
"Incomplete data or malformed json : encoutered end of stream!").niceTrace();
}
 
private void throwNumberFormatException(String expected, String encoutered) {
int pos = _cursor - _col - _numberLen;
throw JsonStreamException.niceTrace(new NumberFormatException("Wrong numeric type at row " + _row + " and column " + pos
+ ", expected " + expected + " but encoutered " + encoutered));
}
 
}
/branches/grupo4/impl/src/java/com/owlike/genson/stream/ValueType.java
New file
0,0 → 1,24
package com.owlike.genson.stream;
 
import java.util.List;
import java.util.Map;
 
public enum ValueType {
ARRAY(List.class),
OBJECT(Map.class),
STRING(String.class),
INTEGER(Long.class),
DOUBLE(Double.class),
BOOLEAN(Boolean.class),
NULL(null);
 
private final Class<?> clazz;
 
ValueType(Class<?> clazz) {
this.clazz = clazz;
}
 
public Class<?> toClass() {
return clazz;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/GenericType.java
New file
0,0 → 1,70
package com.owlike.genson;
 
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
 
import com.owlike.genson.reflect.TypeUtil;
 
/**
* This class is a holder for generic types so we can work around type erasure. You can read <a
* href="http://gafter.blogspot.fr/2006/12/super-type-tokens.html">this blog post</a> who explains a
* bit more in details what it is about. For example if you want to use at runtime a
* List&lt;Integer&gt; :
* <p/>
* <pre>
* GenericType&lt;List&lt;Integer&gt;&gt; genericType = new GenericType&lt;List&lt;Integer&gt;&gt;() {
* };
* List&lt;Integer&gt; listOfIntegers = new Genson().deserialize(&quot;[1,2,3]&quot;, genericType);
*
* // if you want to get the standard java.lang.reflect.Type corresponding to List&lt;Integer&gt; from
* // genericType
* Type listOfIntegersType = genericType.getType();
* // listOfIntegersType will be an instance of ParameterizedType with Integer class as type argument
* </pre>
*
* @param <T> the real type
* @author eugen
*/
public abstract class GenericType<T> {
private final Type type;
private final Class<T> rawClass;
 
@SuppressWarnings("unchecked")
protected GenericType() {
Type superType = getClass().getGenericSuperclass();
if (superType instanceof Class<?>) {
throw new IllegalArgumentException("You must specify the parametrized type!");
}
type = ((ParameterizedType) superType).getActualTypeArguments()[0];
rawClass = (Class<T>) TypeUtil.getRawClass(type);
}
 
private GenericType(Class<T> rawClass) {
this.type = rawClass;
this.rawClass = rawClass;
}
 
@SuppressWarnings("unchecked")
private GenericType(Type type) {
this.type = type;
this.rawClass = (Class<T>) TypeUtil.getRawClass(type);
}
 
public static <T> GenericType<T> of(Class<T> rawClass) {
return new GenericType<T>(rawClass) {
};
}
 
public static GenericType<Object> of(Type type) {
return new GenericType<Object>(type) {
};
}
 
public Type getType() {
return type;
}
 
public Class<T> getRawClass() {
return rawClass;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/ext/GensonBundle.java
New file
0,0 → 1,45
package com.owlike.genson.ext;
 
import com.owlike.genson.GensonBuilder;
import com.owlike.genson.reflect.AbstractBeanDescriptorProvider.ContextualConverterFactory;
import com.owlike.genson.reflect.BeanDescriptorProvider;
import com.owlike.genson.reflect.BeanMutatorAccessorResolver;
import com.owlike.genson.reflect.BeanPropertyFactory;
import com.owlike.genson.reflect.PropertyNameResolver;
 
/**
* Bundles allow to package all kind of Genson customizations into a single module and register
* them all together. Extensions are registered using Genson.Builder.
* <p/>
* <pre>
* Genson genson = new GensonBuilder().with(new SuperCoolExtension()).create();
* </pre>
* <p/>
* Extension configuration is mixed with user custom configuration (no way to distinguish them),
* however user custom config. has preference over bundle configuration. This means that you can
* override bundle configuration with custom one.
* <p/>
*
* <b>Important note, bundles must be registered after any other configuration.</b>
*
* This part of the API is still in beta, it could change in the future in order to make it more
* powerful.
*
* @author eugen
*/
public abstract class GensonBundle {
/**
* This method does not provide any guarantee to when it is called: before user config, during,
* or after. Thus it should not rely on accessor methods from GensonBuilder they might not reflect
* the final configuration. Use the builder to register your components.
*/
public abstract void configure(GensonBuilder builder);
 
public BeanDescriptorProvider createBeanDescriptorProvider(ContextualConverterFactory contextualConverterFactory,
BeanPropertyFactory propertyFactory,
BeanMutatorAccessorResolver propertyResolver,
PropertyNameResolver nameResolver,
GensonBuilder builder) {
return null;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/ext/guava/GuavaBundle.java
New file
0,0 → 1,13
package com.owlike.genson.ext.guava;
 
import com.google.common.base.Optional;
import com.owlike.genson.GensonBuilder;
import com.owlike.genson.ext.GensonBundle;
 
public class GuavaBundle extends GensonBundle {
@Override
public void configure(GensonBuilder builder) {
builder.useDefaultValue(Optional.absent(), Optional.class)
.withConverterFactory(new OptionalConverter.OptionalConverterFactory());
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/ext/guava/OptionalConverter.java
New file
0,0 → 1,46
package com.owlike.genson.ext.guava;
 
import com.google.common.base.Optional;
import com.owlike.genson.*;
import com.owlike.genson.annotation.HandleNull;
import com.owlike.genson.reflect.TypeUtil;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
import com.owlike.genson.stream.ValueType;
 
import java.io.IOException;
import java.lang.reflect.Type;
 
@HandleNull
public class OptionalConverter<T> implements Converter<Optional<T>> {
static class OptionalConverterFactory implements Factory<Converter<Optional<Object>>> {
 
@Override
public Converter<Optional<Object>> create(Type type, Genson genson) {
Type typeOfValue = TypeUtil.typeOf(0, type);
 
return new OptionalConverter<Object>(genson.provideConverter(typeOfValue));
}
}
 
private final Converter<T> valueConverter;
 
public OptionalConverter(Converter<T> valueConverter) {
this.valueConverter = valueConverter;
}
 
@Override
public void serialize(Optional<T> object, ObjectWriter writer, Context ctx) throws Exception {
if (object == null || object.isPresent()) {
valueConverter.serialize(object.get(), writer, ctx);
} else writer.writeNull();
}
 
@Override
public Optional<T> deserialize(ObjectReader reader, Context ctx) throws Exception {
if (ValueType.NULL.equals(reader.getValueType())) {
return Optional.absent();
}
return Optional.of(valueConverter.deserialize(reader, ctx));
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/ext/jaxb/JAXBBundle.java
New file
0,0 → 1,536
package com.owlike.genson.ext.jaxb;
 
import static com.owlike.genson.reflect.TypeUtil.*;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
 
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
 
import com.owlike.genson.*;
import com.owlike.genson.annotation.HandleClassMetadata;
import com.owlike.genson.annotation.HandleBeanView;
import com.owlike.genson.convert.ChainedFactory;
import com.owlike.genson.convert.ContextualFactory;
import com.owlike.genson.convert.DefaultConverters.WrappedRootValueConverter;
import com.owlike.genson.convert.DefaultConverters.DateConverter;
import com.owlike.genson.ext.GensonBundle;
import com.owlike.genson.reflect.*;
import com.owlike.genson.stream.ObjectReader;
import com.owlike.genson.stream.ObjectWriter;
 
/**
* Provides support for some JAXB annotations and data types.
*
* @author eugen
*/
public class JAXBBundle extends GensonBundle {
private final DatatypeFactory dateFactory;
private boolean wrapRootValues = false;
 
public JAXBBundle() {
try {
dateFactory = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException dce) {
throw new IllegalStateException("Could not obtain an instance of DatatypeFactory.", dce);
}
}
 
/**
* When enabled allows to use @XmlRootElement annotation on root objects to wrap them inside a object under some key.
* The key by default will be the class name with the first letter to lower case.
*/
public JAXBBundle wrapRootValues(boolean enable) {
wrapRootValues = enable;
return this;
}
 
@Override
public void configure(GensonBuilder builder) {
// forcing here the order of GensonAnnotationsResolver and AnnotationPropertyNameResolver allows
// us to give them preference over Jaxb annotations. We can not assume it true for any bundle,
// as in some cases a bundle might want to have preference over all std Genson components
builder.withConverters(new XMLGregorianCalendarConverter(), new DurationConveter())
.with(new BeanMutatorAccessorResolver.GensonAnnotationsResolver(), new JaxbAnnotationsResolver())
.with(new PropertyNameResolver.AnnotationPropertyNameResolver(), new JaxbNameResolver())
.withConverterFactory(new EnumConverterFactory())
.withBeanPropertyFactory(new JaxbBeanPropertyFactory())
.withContextualFactory(new XmlTypeAdapterFactory());
 
if (wrapRootValues)
builder.withConverterFactory(new ChainedFactory() {
@Override
protected Converter<?> create(Type type, Genson genson, Converter<?> nextConverter) {
Class<?> clazz = TypeUtil.getRawClass(type);
XmlRootElement ann = clazz.getAnnotation(XmlRootElement.class);
 
if (ann != null) {
String name = "##default".equals(ann.name()) ? firstCharToLower(clazz.getSimpleName()) : ann.name();
return new WrappedRootValueConverter<Object>(name, name, (Converter<Object>) nextConverter);
}
return null;
}
});
}
 
private String firstCharToLower(String str) {
return Character.toLowerCase(str.charAt(0)) + (str.length() > 0 ? str.substring(1) : "");
}
 
private class DurationConveter implements Converter<Duration> {
@Override
public void serialize(Duration object, ObjectWriter writer, Context ctx) {
writer.writeValue(object.toString());
}
 
@Override
public Duration deserialize(ObjectReader reader, Context ctx) {
return dateFactory.newDuration(reader.valueAsString());
}
}
 
@HandleClassMetadata
@HandleBeanView
private class XMLGregorianCalendarConverter implements Converter<XMLGregorianCalendar> {
private final DateConverter converter = new DateConverter();
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-DD'T'hh:mm:ssZ");
 
@Override
public void serialize(XMLGregorianCalendar object, ObjectWriter writer, Context ctx) {
converter.serialize(object.toGregorianCalendar().getTime(), writer, ctx);
}
 
@Override
public synchronized XMLGregorianCalendar deserialize(ObjectReader reader, Context ctx) {
GregorianCalendar cal = new GregorianCalendar();
try {
cal.setTime(dateFormat.parse(reader.valueAsString()));
} catch (ParseException e) {
throw new JsonBindingException("Could not parse date "
+ reader.valueAsString(), e);
}
 
return dateFactory.newXMLGregorianCalendar(cal);
}
 
}
 
private class XmlTypeAdapterFactory implements ContextualFactory<Object> {
@Override
public Converter<Object> create(BeanProperty property, Genson genson) {
XmlJavaTypeAdapter ann = property.getAnnotation(XmlJavaTypeAdapter.class);
Converter<Object> converter = null;
 
if (ann != null) {
Class<? extends XmlAdapter> adapterClass = ann.value();
Type adapterExpandedType = expandType(
lookupGenericType(XmlAdapter.class, adapterClass), adapterClass);
Type adaptedType = typeOf(0, adapterExpandedType);
Type originalType = typeOf(1, adapterExpandedType);
Type propertyType = property.getType();
 
if (getRawClass(propertyType).isPrimitive())
propertyType = wrap(getRawClass(propertyType));
 
XmlElement el = property.getAnnotation(XmlElement.class);
Type xmlElementType = el != null && el.type() != XmlElement.DEFAULT.class ? el.type() : null;
 
// checking type consistency
if (xmlElementType != null) {
if (!match(adaptedType, xmlElementType, false))
throw new ClassCastException("The BoundType of XMLAdapter " + adapterClass
+ " is not assignable from property " + property.getName()
+ " declared in " + property.getDeclaringClass());
} else if (!match(propertyType, originalType, false))
throw new ClassCastException("The BoundType of XMLAdapter " + adapterClass
+ " is not assignable from property " + property.getName()
+ " declared in " + property.getDeclaringClass());
 
try {
XmlAdapter adapter = adapterClass.newInstance();
// we also need to find a converter for the adapted type
Converter<Object> adaptedTypeConverter = genson.provideConverter(
xmlElementType != null ? xmlElementType : adaptedType);
converter = new AdaptedConverter(adapter, adaptedTypeConverter);
} catch (InstantiationException e) {
throw new JsonBindingException(
"Could not instantiate XmlAdapter of type " + adapterClass, e);
} catch (IllegalAccessException e) {
throw new JsonBindingException(
"Could not instantiate XmlAdapter of type " + adapterClass, e);
}
}
return converter;
}
 
private class AdaptedConverter implements Converter<Object> {
private final XmlAdapter<Object, Object> adapter;
private final Converter<Object> converter;
 
public AdaptedConverter(XmlAdapter<Object, Object> adapter, Converter<Object> converter) {
super();
this.adapter = adapter;
this.converter = converter;
}
 
@Override
public Object deserialize(ObjectReader reader, Context ctx) throws Exception {
Object value = converter.deserialize(reader, ctx);
try {
return adapter.unmarshal(value);
} catch (Exception e) {
throw new JsonBindingException("Could not unmarshal object using adapter "
+ adapter.getClass());
}
}
 
@Override
public void serialize(Object object, ObjectWriter writer, Context ctx) throws Exception {
Object adaptedValue = null;
try {
adaptedValue = adapter.marshal(object);
} catch (Exception e) {
throw new JsonBindingException("Could not marshal object using adapter "
+ adapter.getClass());
}
converter.serialize(adaptedValue, writer, ctx);
}
}
}
 
private class EnumConverterFactory implements Factory<Converter<Enum<?>>> {
 
@Override
public Converter<Enum<?>> create(Type type, Genson genson) {
Class<?> rawClass = getRawClass(type);
if (rawClass.isEnum() || Enum.class.isAssignableFrom(rawClass)) {
@SuppressWarnings({"unchecked"})
Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) rawClass;
 
try {
Map<String, Enum<?>> valueToEnum = new HashMap<String, Enum<?>>();
Map<Enum<?>, String> enumToValue = new HashMap<Enum<?>, String>();
for (Enum<?> enumConstant : enumClass.getEnumConstants()) {
XmlEnumValue ann = rawClass.getField(enumConstant.name()).getAnnotation(
XmlEnumValue.class);
 
if (ann != null) {
valueToEnum.put(ann.value(), enumConstant);
enumToValue.put(enumConstant, ann.value());
} else {
valueToEnum.put(enumConstant.name(), enumConstant);
enumToValue.put(enumConstant, enumConstant.name());
}
}
 
return new EnumConverter(valueToEnum, enumToValue);
} catch (SecurityException e) {
throw new JsonBindingException("Unable to introspect enum "
+ enumClass, e);
} catch (NoSuchFieldException e) {
}
}
 
// otherwise let genson standard converter handle the conversion
return null;
}
 
@HandleClassMetadata
@HandleBeanView
private class EnumConverter implements Converter<Enum<?>> {
private final Map<String, Enum<?>> valueToEnum;
private final Map<Enum<?>, String> enumToValue;
 
public EnumConverter(Map<String, Enum<?>> valueToEnum, Map<Enum<?>, String> enumToValue) {
super();
this.valueToEnum = valueToEnum;
this.enumToValue = enumToValue;
}
 
@Override
public void serialize(Enum<?> object, ObjectWriter writer, Context ctx) {
writer.writeUnsafeValue(enumToValue.get(object));
}
 
@Override
public Enum<?> deserialize(ObjectReader reader, Context ctx) {
return valueToEnum.get(reader.valueAsString());
}
}
}
 
private class JaxbBeanPropertyFactory implements BeanPropertyFactory {
 
@Override
public PropertyAccessor createAccessor(String name, Field field, Type ofType, Genson genson) {
Type newType = getType(field, field.getGenericType(), ofType);
if (newType != null) {
return new PropertyAccessor.FieldAccessor(name, field, newType, getRawClass(ofType));
}
 
return null;
}
 
@Override
public PropertyAccessor createAccessor(String name, Method method, Type ofType,
Genson genson) {
Type newType = getType(method, method.getReturnType(), ofType);
if (newType != null) {
return new PropertyAccessor.MethodAccessor(name, method, newType,
getRawClass(ofType));
}
return null;
}
 
@Override
public PropertyMutator createMutator(String name, Field field, Type ofType, Genson genson) {
Type newType = getType(field, field.getGenericType(), ofType);
if (newType != null) {
return new PropertyMutator.FieldMutator(name, field, newType, getRawClass(ofType));
}
 
return null;
}
 
@Override
public PropertyMutator createMutator(String name, Method method, Type ofType, Genson genson) {
if (method.getParameterTypes().length == 1) {
Type newType = getType(method, method.getReturnType(), ofType);
if (newType != null) {
return new PropertyMutator.MethodMutator(name, method, newType,
getRawClass(ofType));
}
}
return null;
}
 
@Override
public BeanCreator createCreator(Type ofType, Constructor<?> ctr, String[] resolvedNames,
Genson genson) {
return null;
}
 
@Override
public BeanCreator createCreator(Type ofType, Method method, String[] resolvedNames,
Genson genson) {
return null;
}
 
private Type getType(AccessibleObject object, Type objectType, Type contextType) {
XmlElement el = object.getAnnotation(XmlElement.class);
if (el != null && el.type() != XmlElement.DEFAULT.class) {
if (!TypeUtil.getRawClass(objectType).isAssignableFrom(el.type())) {
XmlJavaTypeAdapter ad = object.getAnnotation(XmlJavaTypeAdapter.class);
if (ad == null)
throw new ClassCastException("Inavlid XmlElement annotation, " + objectType
+ " is not assignable from " + el.type());
}
return el.type();
} else
return null;
}
}
 
private class JaxbNameResolver implements PropertyNameResolver {
private final static String DEFAULT_NAME = "##default";
 
@Override
public String resolve(int parameterIdx, Constructor<?> fromConstructor) {
return null;
}
 
@Override
public String resolve(int parameterIdx, Method fromMethod) {
return null;
}
 
@Override
public String resolve(Field fromField) {
return extractName(fromField);
}
 
@Override
public String resolve(Method fromMethod) {
return extractName(fromMethod);
}
 
private String extractName(AccessibleObject object) {
String name = null;
XmlAttribute attr = object.getAnnotation(XmlAttribute.class);
if (attr != null)
name = attr.name();
else {
XmlElement el = object.getAnnotation(XmlElement.class);
if (el != null) name = el.name();
}
return DEFAULT_NAME.equals(name) ? null : name;
}
}
 
private class JaxbAnnotationsResolver extends BeanMutatorAccessorResolver.PropertyBaseResolver {
@Override
public Trilean isAccessor(Field field, Class<?> fromClass) {
if (ignore(field, field.getType(), fromClass)) return Trilean.FALSE;
if (include(field, field.getType(), fromClass)) return Trilean.TRUE;
return shouldResolveField(field, fromClass);
}
 
@Override
public Trilean isMutator(Field field, Class<?> fromClass) {
if (ignore(field, field.getType(), fromClass)) return Trilean.FALSE;
if (include(field, field.getType(), fromClass)) return Trilean.TRUE;
return shouldResolveField(field, fromClass);
}
 
@Override
public Trilean isAccessor(Method method, Class<?> fromClass) {
if (ignore(method, method.getReturnType(), fromClass)) return Trilean.FALSE;
 
String name = null;
if (method.getName().startsWith("get") && method.getName().length() > 3)
name = method.getName().substring(3);
else if (method.getName().startsWith("is") && method.getName().length() > 2
&& method.getReturnType() == boolean.class
|| method.getReturnType() == Boolean.class)
name = method.getName().substring(2);
 
if (name != null) {
if (include(method, method.getReturnType(), fromClass)) return Trilean.TRUE;
if (find(XmlTransient.class, fromClass, "set" + name, method.getReturnType()) != null)
return Trilean.FALSE;
 
 
return shouldResolveMethod(method, fromClass);
}
 
return Trilean.FALSE;
}
 
@Override
public Trilean isMutator(Method method, Class<?> fromClass) {
Class<?> paramClass = method.getParameterTypes().length == 1 ? method
.getParameterTypes()[0] : Object.class;
if (ignore(method, paramClass, fromClass)) return Trilean.FALSE;
 
if (method.getName().startsWith("set") && method.getName().length() > 3) {
if (include(method, method.getReturnType(), fromClass)) return Trilean.TRUE;
 
String name = method.getName().substring(3);
 
// Exclude it if there is a corresponding accessor annotated with XmlTransient
if (find(XmlTransient.class, fromClass, "get" + name) != null) return Trilean.FALSE;
if (paramClass.equals(boolean.class) || paramClass.equals(Boolean.class)) {
if (find(XmlTransient.class, fromClass, "is" + name) != null)
return Trilean.FALSE;
}
 
 
return shouldResolveMethod(method, fromClass);
}
 
return Trilean.FALSE;
}
 
private Trilean shouldResolveField(Field field, Class<?> fromClass) {
XmlAccessorType ann = find(XmlAccessorType.class, field, fromClass);
 
if (isDefaultVisibilityMember(field, ann) || isValidPublicMember(field, ann) || isValidFieldMember(field, ann)) {
return Trilean.TRUE;
} else {
return Trilean.FALSE;
}
}
 
private Trilean shouldResolveMethod(Method m, Class<?> fromClass) {
XmlAccessorType ann = find(XmlAccessorType.class, m, fromClass);
 
if (isDefaultVisibilityMember(m, ann) || isValidPropertyMember(m, ann) || isValidPublicMember(m, ann)) {
return Trilean.TRUE;
} else {
return Trilean.FALSE;
}
}
 
private boolean isDefaultVisibilityMember(Member m, XmlAccessorType xmlAccessTypeAnn) {
return xmlAccessTypeAnn == null && VisibilityFilter.PACKAGE_PUBLIC.isVisible(m);
}
 
private boolean isValidFieldMember(Member m, XmlAccessorType ann) {
return ann != null && ann.value() == XmlAccessType.FIELD && VisibilityFilter.PRIVATE.isVisible(m);
}
 
private boolean isValidPublicMember(Member m, XmlAccessorType ann) {
return ann != null && ann.value() == XmlAccessType.PUBLIC_MEMBER && VisibilityFilter.PACKAGE_PUBLIC.isVisible(m);
}
 
private boolean isValidPropertyMember(Member m, XmlAccessorType ann) {
return ann != null && ann.value() == XmlAccessType.PROPERTY && VisibilityFilter.PACKAGE_PUBLIC.isVisible(m);
}
 
private boolean ignore(AccessibleObject property, Class<?> ofType, Class<?> fromClass) {
XmlTransient xmlTransientAnn = find(XmlTransient.class, property, ofType);
if (xmlTransientAnn != null) return true;
 
return false;
}
 
private boolean include(AccessibleObject property, Class<?> ofType, Class<?> fromClass) {
if (find(XmlAttribute.class, property, ofType) != null
|| find(XmlElement.class, property, ofType) != null) return true;
 
return false;
}
}
 
private <A extends Annotation> A find(Class<A> annotation, AccessibleObject onObject,
Class<?> onClass) {
A ann = onObject.getAnnotation(annotation);
if (ann != null) return ann;
return find(annotation, onClass);
}
 
private <A extends Annotation> A find(Class<A> annotation, Class<?> onClass) {
A ann = onClass.getAnnotation(annotation);
if (ann == null && onClass.getPackage() != null)
ann = onClass.getPackage().getAnnotation(annotation);
return ann;
}
 
private <A extends Annotation> A find(Class<A> annotation, Class<?> inClass, String methodName,
Class<?>... parameterTypes) {
A ann = null;
for (Class<?> clazz = inClass; clazz != null; clazz = clazz.getSuperclass()) {
try {
for (Method m : clazz.getDeclaredMethods())
if (m.getName().equals(methodName)
&& Arrays.equals(m.getParameterTypes(), parameterTypes))
if (m.isAnnotationPresent(annotation))
return m.getAnnotation(annotation);
else
break;
 
} catch (SecurityException e) {
throw new RuntimeException(e);
}
}
return ann;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/ext/package-info.java
New file
0,0 → 1,4
/**
* This package contains features simplifying Genson integration into existing components.
*/
package com.owlike.genson.ext;
/branches/grupo4/impl/src/java/com/owlike/genson/ThreadLocalHolder.java
New file
0,0 → 1,48
package com.owlike.genson;
 
import static com.owlike.genson.Operations.checkNotNull;
 
import java.util.HashMap;
import java.util.Map;
 
/**
* Just another data holder that stores data in a threadlocal map.
* If you only want to share data across serializers and deserializers prefer using {@link Context}.
* Internally Genson uses it for the spring webmvc integration, so it can pass method signatures and
* extract its annotations, etc.
*
* @author eugen
* @see Context
* @see com.owlike.genson.ext.spring.ExtendedReqRespBodyMethodProcessor ExtendedReqRespBodyMethodProcessor
* @see com.owlike.genson.ext.spring.GensonMessageConverter GensonMessageConverter
*/
public final class ThreadLocalHolder {
private final static ThreadLocal<Map<String, Object>> _data = new ThreadLocal<Map<String, Object>>();
 
public static Object store(String key, Object parameter) {
checkNotNull(key);
return getPutIfMissing().put(key, parameter);
}
 
public static <T> T remove(String key, Class<T> valueType) {
checkNotNull(key, valueType);
Map<String, Object> map = getPutIfMissing();
T value = valueType.cast(map.get(key));
map.remove(key);
return value;
}
 
public static <T> T get(String key, Class<T> valueType) {
checkNotNull(key, valueType);
return valueType.cast(getPutIfMissing().get(key));
}
 
private static Map<String, Object> getPutIfMissing() {
Map<String, Object> map = _data.get();
if (map == null) {
map = new HashMap<String, Object>();
_data.set(map);
}
return map;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/Wrapper.java
New file
0,0 → 1,102
package com.owlike.genson;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
 
import com.owlike.genson.reflect.TypeUtil;
 
 
/**
* Wrapper class must be extended by decorated converters that wrap other converters. This allows to
* access merged class information of wrapped converter and the converter itself. So instead of
* doing myObject.getClass().isAnnotationPresent(..) you will do myObject.isAnnotationPresent(..),
* where myObject is an instance of Wrapper. For example to check if a converter (or any another
* encapsulated converter and so on) has annotation @HandleNull you will do it that way:
* <p/>
* <pre>
* Wrapper.toAnnotatedElement(converter).isAnnotationPresent(HandleNull.class);
* </pre>
* <p/>
* In the future there may be other methods to access other kind of class information.
*
* @author eugen
*/
public abstract class Wrapper<T> implements AnnotatedElement {
private AnnotatedElement wrappedElement;
protected T wrapped;
 
protected Wrapper() {
}
 
protected Wrapper(T wrappedObject) {
if (wrappedObject == null)
throw new IllegalArgumentException("Null not allowed!");
decorate(wrappedObject);
}
 
public Annotation[] getAnnotations() {
return Operations.union(Annotation[].class, wrappedElement.getAnnotations(), getClass()
.getAnnotations());
}
 
public <A extends Annotation> A getAnnotation(Class<A> aClass) {
A ann = wrappedElement.getAnnotation(aClass);
return ann == null ? getClass().getAnnotation(aClass) : ann;
}
 
public Annotation[] getDeclaredAnnotations() {
return Operations.union(Annotation[].class, wrappedElement.getDeclaredAnnotations(),
getClass().getDeclaredAnnotations());
}
 
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return wrappedElement.isAnnotationPresent(annotationClass)
|| getClass().isAnnotationPresent(annotationClass);
}
 
// package visibility as a convenience for CircularClassReferenceConverter
protected void decorate(T object) {
if (wrappedElement != null)
throw new IllegalStateException("An object is already wrapped!");
if (object instanceof AnnotatedElement)
this.wrappedElement = (AnnotatedElement) object;
else
this.wrappedElement = object.getClass();
this.wrapped = object;
}
 
public T unwrap() {
return wrapped;
}
 
/**
* This method acts as an adapter to AnnotatedElement, use it when you need to work on a
* converter annotations. In fact "object" argument will usually be of type converter. If this
* class is a wrapper than it will cast it to annotatedElement (as Wrapper implements
* AnnotatedElement). Otherwise we will return the class of this object.
*
* @param object may be an instance of converter for example
* @return an annotatedElement that allows us to get annotations from this object and it's
* wrapped classes if it is a Wrapper.
*/
public static AnnotatedElement toAnnotatedElement(Object object) {
if (object == null)
return null;
if (isWrapped(object))
return (AnnotatedElement) object;
else
return object.getClass();
}
 
public static boolean isWrapped(Object object) {
return object instanceof Wrapper;
}
 
/**
* @return true if this object or its wrapped object (if the object extends Wrapper) is of type clazz.
*/
public static boolean isOfType(Object object, Class<?> clazz) {
return TypeUtil.match(object.getClass(), clazz, false) ||
(isWrapped(object) && Wrapper.isOfType(((Wrapper<?>) object).unwrap(), clazz));
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/EncodingAwareReaderFactory.java
New file
0,0 → 1,108
package com.owlike.genson;
 
import java.io.*;
 
/**
* This is an internal class that might evolve in the future into a JsonReader Factory and be moved
* to the stream package.
*/
public final class EncodingAwareReaderFactory {
 
static enum UTFEncoding {
UTF_32BE(4), UTF_32LE(4), UTF_16BE(2), UTF_16LE(2), UTF_8(1), UNKNOWN(-1);
 
final int bytes;
 
private UTFEncoding(int bytes) {
this.bytes = bytes;
}
 
public String encoding() {
return name().replace('_', '-');
}
}
 
/**
* Creates java.io.Reader instances with detected encoding from the input stream
* using BOM if present or JSON spec.
*
* Some links:
* http://www.herongyang.com/Unicode/
* http://www.ietf.org/rfc/rfc4627.txt
*
* @throws IOException
* @throws UnsupportedEncodingException
*/
public Reader createReader(InputStream is) throws IOException {
byte[] bytes = new byte[4];
int len = fetchBytes(bytes, is);
 
if (len < 1) return new InputStreamReader(is);
 
// read first 4 bytes if available
int bits_32 = (bytes[0] & 0xFF) << 24
| (bytes[1] & 0xFF) << 16
| (bytes[2] & 0xFF) << 8
| (bytes[3] & 0xFF);
 
UTFEncoding encoding = UTFEncoding.UNKNOWN;
boolean hasBOM = false;
 
// try to detect the encoding from those 4 bytes if BOM is used
if (len == 4) encoding = detectEncodingFromBOM(bits_32);
 
// no BOM then fall back to JSON spec
if (encoding == UTFEncoding.UNKNOWN) {
encoding = detectEncodingUsingJSONSpec(bits_32);
} else hasBOM = true;
 
// should not happen as we default to UTF-8
if (encoding == UTFEncoding.UNKNOWN) {
throw new UnsupportedEncodingException("The encoding could not be detected from the stream.");
}
 
int usedBOMBytes = hasBOM ? len - (4 - encoding.bytes) : 0;
int bytesToUnread = len - usedBOMBytes;
 
// small optimization to avoid encapsulation when there is nothing to unread
if (bytesToUnread == 0) {
return new InputStreamReader(is, encoding.encoding());
} else {
PushbackInputStream pis = new PushbackInputStream(is, bytesToUnread);
pis.unread(bytes, usedBOMBytes, bytesToUnread);
return new InputStreamReader(pis, encoding.encoding());
}
}
 
private UTFEncoding detectEncodingFromBOM(int bits_32) {
int bits_16 = bits_32 >>> 16;
 
if (bits_32 == 0x0000FEFF) return UTFEncoding.UTF_32BE;
else if (bits_32 == 0xFFFE0000) return UTFEncoding.UTF_32LE;
else if (bits_16 == 0xFEFF) return UTFEncoding.UTF_16BE;
else if (bits_16 == 0xFFFE) return UTFEncoding.UTF_16LE;
else if (bits_32 >>> 8 == 0xEFBBBF) return UTFEncoding.UTF_8;
else return UTFEncoding.UNKNOWN;
}
 
private UTFEncoding detectEncodingUsingJSONSpec(int bits_32) {
int bits_16 = bits_32 >>> 16;
 
if (bits_32 >>> 8 == 0) return UTFEncoding.UTF_32BE;
else if ((bits_32 & 0x00FFFFFF) == 0) return UTFEncoding.UTF_32LE;
else if ((bits_16 & 0xFF00) == 0) return UTFEncoding.UTF_16BE;
else if ((bits_16 & 0x00FF) == 0) return UTFEncoding.UTF_16LE;
else return UTFEncoding.UTF_8;
}
 
private int fetchBytes(byte[] bytes, InputStream is) throws IOException {
int start = 0;
int bytesRead;
 
while(start < bytes.length-1 && (bytesRead = is.read(bytes, start, bytes.length-start)) > -1) {
start += bytesRead;
}
 
return start;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/Deserializer.java
New file
0,0 → 1,25
package com.owlike.genson;
 
import java.io.IOException;
 
import com.owlike.genson.stream.ObjectReader;
 
/**
* Deserializers handle deserialization by reading data form {@link com.owlike.genson.stream.ObjectReader
* ObjectReader} and constructing java objects of type T. Genson Deserializers work like classic
* deserializers from other libraries.
*
* @param <T> the type of objects this deserializer can deserialize.
* @author eugen
* @see Converter
*/
public interface Deserializer<T> {
/**
* @param reader used to read data from.
* @param ctx the current context.
* @return an instance of T or a subclass of T.
* @throws com.owlike.genson.JsonBindingException
* @throws com.owlike.genson.stream.JsonStreamException
*/
public T deserialize(ObjectReader reader, Context ctx) throws Exception;
}
/branches/grupo4/impl/src/java/com/owlike/genson/JsonBindingException.java
New file
0,0 → 1,12
package com.owlike.genson;
 
public class JsonBindingException extends RuntimeException {
 
public JsonBindingException(String message) {
super(message);
}
 
public JsonBindingException(String message, Throwable cause) {
super(message, cause);
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/Operations.java
New file
0,0 → 1,36
package com.owlike.genson;
 
import java.lang.reflect.Array;
 
public final class Operations {
public static <T> T[] union(Class<T[]> tClass, T[]... values) {
int size = 0;
for (T[] value : values)
size += value.length;
T[] arr = tClass.cast(Array.newInstance(tClass.getComponentType(), size));
for (int i = 0, len = 0; i < values.length; len += values[i].length, i++)
System.arraycopy(values[i], 0, arr, len, values[i].length);
return arr;
}
 
public static byte[] expandArray(byte[] array, int idx, double factor) {
if (idx >= array.length) {
byte[] tmpArray = new byte[(int) (array.length * factor)];
System.arraycopy(array, 0, tmpArray, 0, array.length);
return tmpArray;
} else return array;
}
 
public static byte[] truncateArray(byte[] array, int size) {
if (size < array.length) {
byte[] tmpArray = new byte[size];
System.arraycopy(array, 0, tmpArray, 0, size);
return tmpArray;
} else return array;
}
 
public static void checkNotNull(Object... values) {
for (Object value : values)
if (value == null) throw new IllegalArgumentException("Null not allowed!");
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/Context.java
New file
0,0 → 1,109
package com.owlike.genson;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import static com.owlike.genson.Operations.checkNotNull;
 
/**
* The context class is intended to be a statefull class shared across a single execution. Its main
* purpose is to hold local data and to pass it to others contributors of the
* serialization/deserialization chain.
* <p/>
* For example if you have computed in a first serializer a value and you need it later in another
* one, you can put it in the context by using {@link Context#store(String, Object)} method and
* later retrieve it with {@link #get(String, Class)} or remove it with {@link #remove(String, Class)}.
* <p/>
* You can achieve the same thing with {@link ThreadLocalHolder} that stores the data in a thread
* local map but it is cleaner to use this Context class as you wont have to worry about removing
* values from it. Indeed java web servers reuse created threads, so if you store data in a thread
* local variable and don't remove it, it will still be present when another request comes in and is
* bound to that thread! This can also lead to memory leaks! Don't forget the
* try-store-finally-remove block if you stick with ThreadLocalHolder.
* <p/>
* <p/>
* This class stores also the views present in the current context, those views will be applied to
* the matching objects during serialization and deserialization.
*
* @author eugen
* @see com.owlike.genson.BeanView BeanView
* @see com.owlike.genson.convert.BeanViewConverter BeanViewConverter
* @see com.owlike.genson.ThreadLocalHolder ThreadLocalHolder
*/
public class Context {
public final Genson genson;
private List<Class<? extends BeanView<?>>> views;
private Map<String, Object> _ctxData = new HashMap<String, Object>();
 
public Context(Genson genson) {
this(genson, null);
}
 
public Context(Genson genson, List<Class<? extends BeanView<?>>> views) {
checkNotNull(genson);
this.genson = genson;
this.views = views;
}
 
public boolean hasViews() {
return views != null && !views.isEmpty();
}
 
public Context withView(Class<? extends BeanView<?>> view) {
if (views == null) views = new ArrayList<Class<? extends BeanView<?>>>();
views.add(view);
return this;
}
 
public List<Class<? extends BeanView<?>>> views() {
return views;
}
 
/**
* Puts the object o in the current context indexed by key.
*
* @param key must be not null
* @param o
* @return the old object associated with that key or null.
*/
public Object store(String key, Object o) {
checkNotNull(key);
Object old = _ctxData.get(key);
_ctxData.put(key, o);
return old;
}
 
/**
* Returns the value mapped to key in this context or null. If the value is not of type
* valueType then an exception is thrown.
*
* @param key must be not null
* @param valueType the type of the value, null not allowed
* @return the mapping for key or null
* @throws ClassCastException if the value mapped to key is not of type valueType.
*/
public <T> T get(String key, Class<T> valueType) {
checkNotNull(key, valueType);
return valueType.cast(_ctxData.get(key));
}
 
/**
* Removes the mapping for this key from the context. If there is no mapping for that key, null
* is returned. If the value mapped to key is not of type valueType an ClassCastException is
* thrown and the mapping is not removed.
*
* @param key must be not null
* @param valueType the type of the value, null not allowed
* @return the value associated to this key
* @throws ClassCastException if the value mapped to key is not of type valueType.
* @see com.owlike.genson.Context#get(String, Class)
*/
public <T> T remove(String key, Class<T> valueType) {
checkNotNull(key, valueType);
T value = valueType.cast(_ctxData.get(key));
_ctxData.remove(key);
return value;
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/package-info.java
New file
0,0 → 1,5
/**
* This package contains Genson base classes, to start
* with have a look at {@link com.owlike.genson.Genson Genson}.
*/
package com.owlike.genson;
/branches/grupo4/impl/src/java/com/owlike/genson/Genson.java
New file
0,0 → 1,619
package com.owlike.genson;
 
import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
 
import com.owlike.genson.reflect.BeanDescriptor;
import com.owlike.genson.reflect.BeanDescriptorProvider;
import com.owlike.genson.reflect.RuntimePropertyFilter;
import com.owlike.genson.stream.*;
 
/**
* <p/>
* Main class of the library. Instances of Genson are thread safe and should be reused.
* You can instantiate it multiple times but it is better to have an instance per configuration
* so you can benefit of better performances.
* <p/>
* For more examples have a look at the <a
* href="http://owlike.github.io/genson/">online documentation</a>.
* <p/>
* <p/>
* To create a new instance of Genson you can use the default no arg constructor or the
* {@link GensonBuilder} class to have control over Gensons configuration. <br>
* A basic usage of Genson would be:
* <p/>
* <pre>
* Genson genson = new Genson();
* String json = genson.serialize(new int[] { 1, 2, 3 });
* int[] arrayOfInt = genson.deserialize(json, int[].class);
* // (multi-dimensional arrays are also supported)
*
* // genson can also deserialize primitive types without class information
* Number[] arrayOfNumber = genson.deserialize(&quot;[1, 2.03, 8877463]&quot;, Number[].class);
* // or even
* Object[] arrayOfUnknownTypes = genson
* .deserialize(&quot;[1, false, null, 4.05, \&quot;hey this is a string!\&quot;]&quot;, Object[].class);
* // it can also deserialize json objects of unknown types to standard java types such as Map, Array, Long etc.
* Map&lt;String, Object&gt; map = (Map&lt;String, Object&gt;) genson.deserialize(&quot;{\&quot;foo\&quot;:1232}&quot;, Object.class);
* </pre>
* <p/>
*
* Every object serialized with Genson, can be deserialized back into its concrete type! Just enable
* it via the builder {@link com.owlike.genson.GensonBuilder#useClassMetadata(boolean)}.
*
* You can also deserialize to objects that don't provide a default constructor with no arguments
* {@link com.owlike.genson.GensonBuilder#useConstructorWithArguments(boolean)}.
*
* @author eugen
*/
public final class Genson {
/**
* Default genson configuration, the default configuration (sers, desers, etc) will be shared
* accros all default Genson instances.
*/
private final static Genson _default = new GensonBuilder().create();
private final static Charset UTF8_CHARSET = Charset.forName("UTF-8");
 
private final ConcurrentHashMap<Type, Converter<?>> converterCache = new ConcurrentHashMap<Type, Converter<?>>();
private final Factory<Converter<?>> converterFactory;
private final BeanDescriptorProvider beanDescriptorFactory;
private final Map<Class<?>, String> classAliasMap;
private final Map<String, Class<?>> aliasClassMap;
private final boolean skipNull;
private final boolean htmlSafe;
private final boolean withClassMetadata;
private final boolean withMetadata;
private final boolean strictDoubleParse;
private final boolean indent;
private final boolean failOnMissingProperty;
private final EncodingAwareReaderFactory readerFactory = new EncodingAwareReaderFactory();
private final Map<Class<?>, Object> defaultValues;
private final RuntimePropertyFilter runtimePropertyFilter;
 
/**
* The default constructor will use the default configuration provided by the {@link GensonBuilder}.
* In most cases using this default constructor will suffice.
*/
public Genson() {
this(_default.converterFactory, _default.beanDescriptorFactory,
_default.skipNull, _default.htmlSafe, _default.aliasClassMap,
_default.withClassMetadata, _default.strictDoubleParse, _default.indent,
_default.withMetadata, _default.failOnMissingProperty, _default.defaultValues, _default.runtimePropertyFilter);
}
 
/**
* Instead of using this constructor you should use {@link GensonBuilder}.
* @param converterFactory providing instance of converters.
* @param beanDescProvider providing instance of {@link BeanDescriptor
* BeanDescriptor} used during bean serialization and deserialization.
* @param skipNull indicates whether null values should be serialized. False by default, null values
* will be serialized.
* @param htmlSafe indicates whether \,<,>,&,= characters should be replaced by their Unicode
* representation.
* @param classAliases association map between classes and their aliases, used if withClassMetadata is
* true.
* @param withClassMetadata indicates whether class name should be serialized and used during deserialization
* to determine the type. False by default.
* @param strictDoubleParse indicates whether to use or not double approximation. If false (by default) it
* enables Genson custom double parsing algorithm, that is an approximation of
* Double.parse but is a lot faster. If true, Double.parse method will be usead
* instead. In most cases you should be fine with Genson algorithm, but if for some
* reason you need to have 100% match with Double.parse, then enable strict parsing.
* @param indent true if outputed json must be indented (pretty printed).
* @param withMetadata true if ObjectReader instances must be configured with metadata feature enabled.
* if withClassMetadata is true withMetadata will be automatically true.
* @param failOnMissingProperty throw a JsonBindingException when a key in the json stream does not match a property in the Java Class.
* @param defaultValues contains a mapping from the raw class to the default value that should be used when the property is missing.
* @param runtimePropertyFilter is used to define what bean properties should be excluded from ser/de at runtime.
*/
public Genson(Factory<Converter<?>> converterFactory, BeanDescriptorProvider beanDescProvider,
boolean skipNull, boolean htmlSafe, Map<String, Class<?>> classAliases, boolean withClassMetadata,
boolean strictDoubleParse, boolean indent, boolean withMetadata, boolean failOnMissingProperty,
Map<Class<?>, Object> defaultValues, RuntimePropertyFilter runtimePropertyFilter) {
this.converterFactory = converterFactory;
this.beanDescriptorFactory = beanDescProvider;
this.skipNull = skipNull;
this.htmlSafe = htmlSafe;
this.aliasClassMap = classAliases;
this.withClassMetadata = withClassMetadata;
this.defaultValues = defaultValues;
this.runtimePropertyFilter = runtimePropertyFilter;
this.classAliasMap = new HashMap<Class<?>, String>(classAliases.size());
for (Map.Entry<String, Class<?>> entry : classAliases.entrySet()) {
classAliasMap.put(entry.getValue(), entry.getKey());
}
this.strictDoubleParse = strictDoubleParse;
this.indent = indent;
this.withMetadata = withClassMetadata || withMetadata;
this.failOnMissingProperty = failOnMissingProperty;
}
 
/**
* Provides an instance of Converter capable of handling objects of type forType.
*
* @param forType the type for which a converter is needed.
* @return the converter instance.
* @throws com.owlike.genson.JsonBindingException if a problem occurs during converters lookup/construction.
*/
@SuppressWarnings("unchecked")
public <T> Converter<T> provideConverter(Type forType) {
if (Boolean.TRUE.equals(ThreadLocalHolder.get("__GENSON$DO_NOT_CACHE_CONVERTER", Boolean.class))) {
return (Converter<T>) converterFactory.create(forType, this);
} else {
Converter<T> converter = (Converter<T>) converterCache.get(forType);
if (converter == null) {
converter = (Converter<T>) converterFactory.create(forType, this);
if (converter == null)
throw new JsonBindingException("No converter found for type " + forType);
converterCache.putIfAbsent(forType, converter);
}
return converter;
}
}
 
/**
* Serializes the object into a json string.
*
* @param object object to be serialized.
* @return the serialized object as a string.
* @throws com.owlike.genson.JsonBindingException if there was any kind of error during serialization.
* @throws JsonStreamException if there was a problem during writing of the object to the output.
*/
public String serialize(Object object) {
StringWriter sw = new StringWriter();
ObjectWriter writer = createWriter(sw);
 
if (object == null) serializeNull(writer);
else serialize(object, object.getClass(), writer, new Context(this));
 
return sw.toString();
}
 
/**
* Serializes the object using the type of GenericType instead of using its runtime type.
*
* @param object object to be serialized.
* @param type the type of the object to be serialized.
* @return json string representation.
* @throws com.owlike.genson.JsonBindingException
* @throws JsonStreamException
*/
public String serialize(Object object, GenericType<?> type) {
StringWriter sw = new StringWriter();
ObjectWriter writer = createWriter(sw);
 
if (object == null) serializeNull(writer);
else serialize(object, type.getType(), writer, new Context(this));
 
return sw.toString();
}
 
/**
* Serializes the object using the specified BeanViews.
*
* @param object
* @param withViews the BeanViews to apply during this serialization.
* @return the json string representing this object
* @throws com.owlike.genson.JsonBindingException
* @throws com.owlike.genson.stream.JsonStreamException
* @see BeanView
*/
public String serialize(Object object, Class<? extends BeanView<?>> firstView, Class<? extends BeanView<?>>... withViews) {
StringWriter sw = new StringWriter();
ObjectWriter writer = createWriter(sw);
 
List<Class<? extends BeanView<?>>> views = new ArrayList(withViews.length);
for (Class<? extends BeanView<?>> view : withViews) views.add(view);
views.add(firstView);
 
if (object == null) serializeNull(writer);
else serialize(object, object.getClass(), writer, new Context(this, views));
 
return sw.toString();
}
 
/**
* Serializes this object to the passed Writer, as Genson did not instantiate it, you are
* responsible of calling close on it.
*/
public void serialize(Object object, Writer writer) {
ObjectWriter objectWriter = createWriter(writer);
 
if (object == null) serializeNull(objectWriter);
else serialize(object, object.getClass(), objectWriter, new Context(this));
}
 
/**
* Serializes this object to the passed OutputStream, as Genson did not instantiate it, you are
* responsible of calling close on it.
*/
public void serialize(Object object, OutputStream output) {
ObjectWriter objectWriter = createWriter(output);
 
if (object == null) serializeNull(objectWriter);
else serialize(object, object.getClass(), objectWriter, new Context(this));
}
 
/**
* Serializes this object to its json form in a byte array.
*/
public byte[] serializeBytes(Object object) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectWriter objectWriter = createWriter(baos);
 
if (object == null) serializeNull(objectWriter);
else serialize(object, object.getClass(), objectWriter, new Context(this));
 
return baos.toByteArray();
}
 
/**
* Serializes this object and writes its representation to writer. As you are providing the
* writer instance you also must ensure to call flush and close on it when you are done.
*
* @param object
* @param writer into which to write the serialized object.
* @throws com.owlike.genson.JsonBindingException
* @throws JsonStreamException
*/
public void serialize(Object object, ObjectWriter writer, Context ctx) {
if (object == null) serializeNull(writer);
else serialize(object, object.getClass(), writer, ctx);
}
 
/**
* Serializes this object and writes its representation to writer. As you are providing the
* writer instance you also must ensure to call close on it when you are done.
*/
public void serialize(Object object, Type type, ObjectWriter writer, Context ctx) {
Serializer<Object> ser = provideConverter(type);
try {
ser.serialize(object, writer, ctx);
writer.flush();
} catch (Exception e) {
throw new JsonBindingException("Failed to serialize object of type " + type, e);
}
}
 
private void serializeNull(ObjectWriter writer) {
try {
writer.writeNull();
writer.flush();
} catch (Exception e) {
throw new JsonBindingException("Could not serialize null value.", e);
}
}
 
/**
* Deserializes fromSource String into an instance of toClass.
*
* @param fromSource source from which to deserialize.
* @param toClass type into which to deserialize.
* @throws com.owlike.genson.JsonBindingException
* @throws JsonStreamException
*/
public <T> T deserialize(String fromSource, Class<T> toClass) {
return deserialize(GenericType.of(toClass), createReader(new StringReader(fromSource)),
new Context(this));
}
 
/**
* Deserializes to an instance of T. GenericType is useful when you want to deserialize to a
* list or map (or any other type with generics).
*
* @param fromSource
* @param toType
* @throws com.owlike.genson.JsonBindingException
* @throws JsonStreamException
* @see GenericType
*/
public <T> T deserialize(String fromSource, GenericType<T> toType) {
return deserialize(toType, createReader(new StringReader(fromSource)), new Context(this));
}
 
/**
* Deserializes the incoming json stream into an instance of T.
* Genson did not create the instance of Reader so it will not be closed
*/
public <T> T deserialize(Reader reader, GenericType<T> toType) {
return deserialize(toType, createReader(reader), new Context(this));
}
 
/**
* Deserializes the incoming json stream into an instance of T.
* Genson did not create the instance of Reader so it will not be closed
*/
public <T> T deserialize(Reader reader, Class<T> toType) {
return deserialize(GenericType.of(toType), createReader(reader), new Context(this));
}
 
/**
* Deserializes the incoming json stream into an instance of T.
* Genson did not create the instance of InputStream so it will not be closed
*/
public <T> T deserialize(InputStream input, Class<T> toType) {
return deserialize(GenericType.of(toType), createReader(input), new Context(this));
}
 
/**
* Deserializes the incoming json stream into an instance of T.
* Genson did not create the instance of InputStream so it will not be closed.
*/
public <T> T deserialize(InputStream input, GenericType<T> toType) {
return deserialize(toType, createReader(input), new Context(this));
}
 
/**
* Deserializes the incoming json byte array into an instance of T.
*/
public <T> T deserialize(byte[] input, Class<T> toType) {
return deserialize(GenericType.of(toType), createReader(input), new Context(this));
}
 
/**
* Deserializes the incoming json byte array into an instance of T.
*/
public <T> T deserialize(byte[] input, GenericType<T> toType) {
return deserialize(toType, createReader(input), new Context(this));
}
 
public <T> T deserialize(String fromSource, GenericType<T> toType, Class<? extends BeanView<?>>... withViews) {
StringReader reader = new StringReader(fromSource);
return deserialize(toType, createReader(reader),
new Context(this, Arrays.asList(withViews)));
}
 
public <T> T deserialize(String fromSource, Class<T> toType, Class<? extends BeanView<?>>... withViews) {
StringReader reader = new StringReader(fromSource);
return deserialize(GenericType.of(toType), createReader(reader),
new Context(this, Arrays.asList(withViews)));
}
 
public <T> T deserialize(GenericType<T> type, Reader reader, Class<? extends BeanView<?>>... withViews) {
return deserialize(type, createReader(reader), new Context(this, Arrays.asList(withViews)));
}
 
public <T> T deserialize(GenericType<T> type, ObjectReader reader, Context ctx) {
Deserializer<T> deser = provideConverter(type.getType());
try {
return deser.deserialize(reader, ctx);
} catch (Exception e) {
throw new JsonBindingException("Could not deserialize to type " + type.getRawClass(), e);
}
}
 
/**
* @see #deserializeInto(com.owlike.genson.stream.ObjectReader, Object, Context)
*/
public <T> T deserializeInto(String json, T object) {
return deserializeInto(createReader(new StringReader(json)), object, new Context(this));
}
 
/**
* @see #deserializeInto(com.owlike.genson.stream.ObjectReader, Object, Context)
*/
public <T> T deserializeInto(byte[] jsonBytes, T object) {
return deserializeInto(createReader(jsonBytes), object, new Context(this));
}
 
/**
* @see #deserializeInto(com.owlike.genson.stream.ObjectReader, Object, Context)
*/
public <T> T deserializeInto(InputStream is, T object) {
return deserializeInto(createReader(is), object, new Context(this));
}
 
/**
* @see #deserializeInto(com.owlike.genson.stream.ObjectReader, Object, Context)
*/
public <T> T deserializeInto(Reader reader, T object) {
return deserializeInto(createReader(reader), object, new Context(this));
}
 
/**
* Deserializes the stream in the existing object. Note however that this works only for Pojos
* and doesn't handle nested objects (will be overridden by the values from the stream).
*
* @return the object enriched with the properties from the stream.
*/
public <T> T deserializeInto(ObjectReader reader, T object, Context ctx) {
BeanDescriptor<T> bd = (BeanDescriptor<T>) getBeanDescriptorProvider().provide(object.getClass(), this);
bd.deserialize(object, reader, ctx);
return object;
}
 
/**
* @see #deserializeValues(com.owlike.genson.stream.ObjectReader, GenericType)
*/
public <T> Iterator<T> deserializeValues(final InputStream is, final Class<T> type) {
return deserializeValues(createReader(is), GenericType.of(type));
}
 
/**
* This can be used to deserialize in an efficient streaming fashion a sequence of objects.
* Note that you can use this method when your values are wrapped in an array (valid json) but also
* when they all are root values (not enclosed in an array). For example:
*
* <pre>
* Genson genson = new Genson();
* ObjectReader reader = genson.createReader(json);
*
* for (Iterator&lt;LogEntry> it = genson.deserializeValues(reader, GenericType.of(LogEntry.class));
* it.hasNext(); ) {
* // do something
* LogEntry p = it.next();
* }
* </pre>
* @param reader an instance of the ObjectReader to use (obtained with genson.createReader(...) for ex.),
* note that you are responsible of closing it.
* @param type to deserialize to
* @param <T>
* @return an iterator of T
*/
public <T> Iterator<T> deserializeValues(final ObjectReader reader, final GenericType<T> type) {
final boolean isArray = reader.getValueType() == ValueType.ARRAY;
if (isArray == true) {
reader.beginArray();
}
 
return new Iterator<T>() {
final Converter<T> converter = provideConverter(type.getType());
final Context ctx = new Context(Genson.this);
 
@Override
public boolean hasNext() {
boolean hasMore = reader.hasNext();
if (isArray && !hasMore) reader.endArray();
return hasMore;
}
 
@Override
public T next() {
if (!hasNext()) throw new NoSuchElementException();
reader.next();
try {
return converter.deserialize(reader, ctx);
} catch (Exception e) {
throw new JsonBindingException("Could not deserialize to type " + type.getRawClass(), e);
}
}
 
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
 
/**
* Searches if an alias has been registered for clazz. If not will take the class full name and
* use it as alias. This method never returns null.
*/
public <T> String aliasFor(Class<T> clazz) {
String alias = classAliasMap.get(clazz);
if (alias == null) {
alias = clazz.getName();
classAliasMap.put(clazz, alias);
}
return alias;
}
 
/**
* Searches for the class matching this alias, if none will try to use the alias as the class
* name.
*
* @param alias
* @return The class matching this alias.
* @throws ClassNotFoundException thrown if no class has been registered for this alias and the alias it self does
* not correspond to the full name of a class.
*/
public Class<?> classFor(String alias) throws ClassNotFoundException {
Class<?> clazz = aliasClassMap.get(alias);
if (clazz == null) {
clazz = Class.forName(alias);
aliasClassMap.put(alias, clazz);
}
return clazz;
}
 
/**
* Creates a new ObjectWriter with this Genson instance configuration and default encoding to
* UTF8.
*/
public ObjectWriter createWriter(OutputStream os) {
return new JsonWriter(new OutputStreamWriter(os, UTF8_CHARSET), skipNull, htmlSafe, indent);
}
 
/**
* Creates a new ObjectWriter with this Genson instance configuration.
*/
public ObjectWriter createWriter(OutputStream os, Charset charset) {
return createWriter(new OutputStreamWriter(os, charset));
}
 
/**
* Creates a new ObjectWriter with this Genson instance configuration.
*/
public ObjectWriter createWriter(Writer writer) {
return new JsonWriter(writer, skipNull, htmlSafe, indent);
}
 
/**
* @see #createReader(java.io.InputStream)
*/
public ObjectReader createReader(byte[] in) {
try {
return createReader(readerFactory.createReader(new ByteArrayInputStream(in)));
} catch (IOException e) {
throw new JsonStreamException("Failed to detect encoding.", e);
}
}
 
/**
* Creates a new ObjectReader with this Genson instance configuration and tries to detect the encoding
* from the stream content.
*/
public ObjectReader createReader(InputStream is) {
try {
return createReader(readerFactory.createReader(is));
} catch (IOException e) {
throw new JsonStreamException("Failed to detect encoding.", e);
}
}
 
/**
* Creates a new ObjectReader with this Genson instance configuration.
*/
public ObjectReader createReader(InputStream is, Charset charset) {
return createReader(new InputStreamReader(is, charset));
}
 
/**
* Creates a new ObjectReader with this Genson instance configuration.
*/
public ObjectReader createReader(Reader reader) {
return new JsonReader(reader, strictDoubleParse, withMetadata);
}
 
public boolean isSkipNull() {
return skipNull;
}
 
public boolean isHtmlSafe() {
return htmlSafe;
}
 
public boolean isWithClassMetadata() {
return withClassMetadata;
}
 
public BeanDescriptorProvider getBeanDescriptorProvider() {
return beanDescriptorFactory;
}
 
public boolean failOnMissingProperty() {
return this.failOnMissingProperty;
}
 
/**
* @return the defined default value for type clazz or null if none is defined. Intended for internal use.
*/
public <T> T defaultValue(Class<T> clazz) {
return (T) defaultValues.get(clazz);
}
 
public RuntimePropertyFilter runtimePropertyFilter() {
return runtimePropertyFilter;
}
 
/**
* @deprecated use GensonBuilder
*/
@Deprecated
public static class Builder extends GensonBuilder {
 
}
}
/branches/grupo4/impl/src/java/com/owlike/genson/annotation/JsonDateFormat.java
New file
0,0 → 1,31
package com.owlike.genson.annotation;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.text.SimpleDateFormat;
 
/**
* Can be used on java.util.Date and java.util.Calendar to indicate the pattern or lang to
* use when working with this date field. The pattern format are the standard ones from
* {@link SimpleDateFormat}.
*
* @author eugen
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface JsonDateFormat {
/**
* The pattern to use.
*/
String value() default "";
 
boolean asTimeInMillis() default false;
 
String lang() default "";
}
/branches/grupo4/impl/src/java/com/owlike/genson/annotation/JsonConverter.java
New file
0,0 → 1,26
package com.owlike.genson.annotation;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
import com.owlike.genson.Converter;
 
/**
* This annotation is useful when you want to use a specific Converter for a property in a class,
* but do not want to use it for all properties of that type. When you put this annotation on a
* field, constructor parameter or setter/getter, Genson will use this Converter instead of any other.
* <b>The Converter must have a default no arg constructor.</b>
*
* @author eugen
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface JsonConverter {
Class<? extends Converter<?>> value();
}
/branches/grupo4/impl/src/java/com/owlike/genson/annotation/HandleClassMetadata.java
New file
0,0 → 1,31
package com.owlike.genson.annotation;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
* Annotated Serializer/Deserializer/Converter with @HandleClassMetadata indicate that they will
* handle @class metadata during serialization and deserialization. By default it is handled by the
* library in {@link com.owlike.genson.convert.ClassMetadataConverter ClassMetadataConverter}. Default
* converters from {@link com.owlike.genson.convert.DefaultConverters DefaultConverters} annotated with @HandleClassMetadata
* do not serialize type information nor do they use it during deserialization. For security reasons
* class metadata is disabled by default. To enable it
* {@link com.owlike.genson.GensonBuilder#useClassMetadata(boolean)}
* GensonBuilder.useClassMetadata(true)}
*
* @author eugen
* @see com.owlike.genson.convert.ClassMetadataConverter ClassMetadataConverter
* @see com.owlike.genson.GensonBuilder#useClassMetadata(boolean)
* Genson.Builder.setWithClassMetadata(true)
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HandleClassMetadata {
 
}
/branches/grupo4/impl/src/java/com/owlike/genson/annotation/package-info.java
New file
0,0 → 1,4
/**
* This package provides useful annotations to configure some features used during serialization and deserialization.
*/
package com.owlike.genson.annotation;
/branches/grupo4/impl/src/java/com/owlike/genson/annotation/HandleNull.java
New file
0,0 → 1,27
package com.owlike.genson.annotation;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
* Similar to {@link HandleClassMetadata}, put this annotation on your Converters, Serializers and
* Deserializers to disable Genson default null handling (
* {@link com.owlike.genson.convert.NullConverter NullConverter}). In that case you will have to
* write the code that handles nulls during serialization and deserialization of your type (and not
* of its content). This feature is mainly for internal use.
*
* @author eugen
* @see HandleClassMetadata
* @see com.owlike.genson.convert.NullConverter NullConverter
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HandleNull {
 
}
/branches/grupo4/impl/src/java/com/owlike/genson/annotation/JsonCreator.java
New file
0,0 → 1,33
package com.owlike.genson.annotation;
 
import java.lang.annotation.*;
 
/**
* Static methods annotated with @JsonCreator annotation will act as method factories. These methods can
* take arguments that match properties from the json stream. If you use default configuration you
* must annotate each argument with {@link com.owlike.genson.annotation.JsonProperty JsonProperty} and
* define a name. However Genson is also able to use the names from the method signature, but by
* default it is disabled. To enable this feature use
* <p/>
* <pre>
* new GensonBuilder().useConstructorWithArguments(true).create();
* </pre>
* <p/>
* It will register {@link com.owlike.genson.reflect.ASMCreatorParameterNameResolver
* ASMCreatorParameterNameResolver} name resolver, that will use the debug symbols generated during
* compilation to resolve the names.
* <p/>
* By default if a object contains constructors and methods annotated with @JsonCreator the factory
* methods will be privileged.
*
* @author eugen
* @see com.owlike.genson.annotation.JsonProperty JsonProperty
* @see com.owlike.genson.reflect.BeanMutatorAccessorResolver.StandardMutaAccessorResolver
* StandardMutaAccessorResolver
*/
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface JsonCreator {
}
/branches/grupo4/impl/src/java/com/owlike/genson/annotation/HandleBeanView.java
New file
0,0 → 1,23
package com.owlike.genson.annotation;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
* Annotated Serializer/Deserializer/Converter will be excluded from the BeanView mechanism.
* Most default converters are annotated with HandleBeanView (IntegerConverter, BooleanConverter etc).
*
* @author eugen
* @see com.owlike.genson.convert.BeanViewConverter BeanViewConverter
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HandleBeanView {
 
}
/branches/grupo4/impl/src/java/com/owlike/genson/annotation/WithBeanView.java
New file
0,0 → 1,26
package com.owlike.genson.annotation;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
import com.owlike.genson.BeanView;
 
/**
* Annotation used actually only in spring web integration
* {@link com.owlike.genson.ext.spring.GensonMessageConverter GensonMessageConverter} to indicate
* at runtime what BeanView must be used. Its intended to be used in conjunction
* with springs @ResponseBody/@RequestBody and @RequestMapping annotations.
*
* @author eugen
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface WithBeanView {
Class<? extends BeanView<?>>[] views() default {};
}
/branches/grupo4/impl/src/java/com/owlike/genson/annotation/JsonIgnore.java
New file
0,0 → 1,35
package com.owlike.genson.annotation;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
* You can annotate with @JsonIgnore the methods, fields and creators that must be ignored during
* serialization AND deserialization. To exclude property from only deserialization and keep it
* during serialization use @JsonIgnore(serialize=true), for example if you annotate a field with
* &#64;JsonIgnore(serialize=true,deserialize=true) it will have no effect!
*
* @author eugen
* @see com.owlike.genson.annotation.JsonProperty JsonProperty
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface JsonIgnore {
/**
* Whether to include this property in serialization. False by default, the property won't be
* serialized.
*/
boolean serialize() default false;
 
/**
* Whether to include this property in deserialization. False by default, the property won't be
* deserialized.
*/
boolean deserialize() default false;
}
/branches/grupo4/impl/src/java/com/owlike/genson/annotation/JsonProperty.java
New file
0,0 → 1,50
package com.owlike.genson.annotation;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
* JsonProperty annotation can be used to define the name of a property. You can apply it on fields
* and methods. In that case this name will be used instead of the conventional one computed from
* the signature. You can also use this annotation on parameters of creator methods and on
* constructor parameters. In that case Genson during deserialization will try to use those names to
* match the properties from the json stream. By default it is used in
* {@link com.owlike.genson.reflect.PropertyNameResolver.AnnotationPropertyNameResolver
* AnnotationPropertyNameResolver}.
*
* @author eugen
* @see com.owlike.genson.reflect.PropertyNameResolver.AnnotationPropertyNameResolver
* AnnotationPropertyNameResolver
* @see com.owlike.genson.annotation.JsonCreator JsonCreator
* @see com.owlike.genson.annotation.JsonIgnore JsonIgnore
*/
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface JsonProperty {
/**
* The name of that property.
*/
String value() default "";
 
/**
* A list of aliases to use during deserialization for this property. Note that during serialization this is not used.
*/
String[] aliases() default {};
 
/**
* Whether this property must be serialized. Default is true, the property will be serialized.
*/
boolean serialize() default true;
 
/**
* Whether this property must be deserialized. Default is true, the property will be
* deserialized.
*/
boolean deserialize() default true;
}
/branches/grupo4/impl/src/java/com/owlike/genson/Trilean.java
New file
0,0 → 1,34
package com.owlike.genson;
 
/**
* A boolean with 3 states : true, false and unknown.
*
* @author eugen
*/
public enum Trilean {
TRUE() {
@Override
public boolean booleanValue() {
return true;
}
},
FALSE {
@Override
public boolean booleanValue() {
return false;
}
},
UNKNOWN {
@Override
public boolean booleanValue() {
throw new IllegalStateException(
"Unknown state can not be converter to a boolean, only TRUE AND FALSE can!");
}
};
 
public static Trilean valueOf(boolean value) {
return value ? TRUE : FALSE;
}
 
public abstract boolean booleanValue();
}
/branches/grupo4/impl/src/hbm/pt/estgp/estgweb/domain/Course.hbm.xml
79,6 → 79,10
<property name="separatedTurmas" type="boolean">
<column name="separatedTurmas" default="false"/>
</property>
<!-- Ponto 1 Criaçao de Variavel-->
<property name="courseReportDocument" type="string">
<column name="courseReportDocument" sql-type="LONGTEXT"/>
</property>
<many-to-one name="course" class="pt.estgp.estgweb.domain.Course" outer-join="true" lazy="false" column="course_id"/>
<subclass name="pt.estgp.estgweb.domain.CourseYearImpl" discriminator-value="CourseYearImpl"/>
</class>
/branches/grupo4/impl/src/web/hello.jsp
File deleted
/branches/grupo4/impl/src/web/user/courses/courseReportEdit.jsp
314,30 → 314,9
}
}
 
$scope.save = function()
{
 
widgetCallWithActionParameters(
"<%=request.getContextPath()%>/user/courseReport.do",
"save",
{
"report" : BacoJS.stringifyOrdered($scope.report)
},
"#courseReportApp",
function(resposta)
{
$scope.report = resposta;
alert(resposta.courseName);
$scope.$apply();
},
function(){}
);
 
}
 
 
 
 
});
</script>
 
352,7 → 331,6
 
</div>
 
<button ng-click="save()" class="btn btn-success">Salvar</button>
<!-- <pre class="code">{{ report | json }}</pre>-->
 
 
/branches/grupo4/impl/libs.xml
98,7 → 98,7
</fileset>
<fileset dir="${common.lib.dir}/json">
<include name="**/*.jar"/>
<!--<exclude name="genson-1.4.jar"/>-->
<exclude name="genson-1.4.jar"/>
<exclude name="genson-0.97.jar"/>
</fileset>
<fileset dir="${common.lib.dir}/jsoup">
/branches/grupo4/impl/build.xml
66,6 → 66,7
<target name="initDirs">
<mkdir dir="${log.dir}"/>
<mkdir dir="${data.dir}"/>
<mkdir dir="${tmp.dir}"/>
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.dir.classes}"/>
<mkdir dir="${build.dir.war}"/>
299,7 → 300,7
<fileset dir="${common.lib.dir}/json">
<include name="**/*.jar"/>
<exclude name="genson-0.97.jar"/>
<!--<exclude name="genson-1.4.jar"/>-->
<exclude name="genson-1.4.jar"/>
</fileset>
<fileset dir="${common.lib.dir}/jsoup">
<include name="**/*.jar"/>
/branches/grupo4/impl/gen/java/pt/estgp/estgweb/domain/CourseYear.java
2,12 → 2,13
// Generated 4/nov/2017 19:35:42 by Hibernate Tools 3.2.0.b9
 
 
import java.io.Serializable;
import java.util.Date;
 
/**
* CourseYear generated by hbm2java
*/
public abstract class CourseYear extends pt.estgp.estgweb.domain.DomainSerializableObject implements java.io.Serializable {
public abstract class CourseYear extends DomainSerializableObject implements Serializable {
 
 
private long id;
16,7 → 17,16
private String importYear;
private boolean separatedTurmas;
private Course course;
private String courseReportDocument;
 
public String getCourseReportDocument() {
return courseReportDocument;
}
 
public void setCourseReportDocument(String courseReportDocument) {
this.courseReportDocument = courseReportDocument;
}
 
public CourseYear() {
}
 
/branches/grupo17529/impl/conf/berserk/sd.xml
4048,6 → 4048,20
</filterChains>
</service>
 
<service>
<name>CourseReportSave</name>
<implementationClass>pt.estgp.estgweb.services.courses.CourseReportServices</implementationClass>
<description>
@reportCourseDocumento faz save de um documento alterado
</description>
<isTransactional>true</isTransactional>
<defaultMethod>saveCourseReport</defaultMethod>
<filterChains>
<chain name="Logger"/>
<chain name="Session"/>
</filterChains>
</service>
 
 
 
</serviceDefinitions>
/branches/grupo17529/impl/src/java/pt/estgp/estgweb/services/courses/CourseReportServices.java
634,18 → 634,21
}
}
 
//save
public String saveCourseReport(String reportDocumentJson,UserSession session){
 
CourseReportDocument reportDocument = CourseReportDocument.fromJson(reportDocumentJson);
 
 
 
return null;
 
}
 
 
 
 
 
 
 
public static void main(String[] args) throws IOException, JSONException {
AbstractDao.getCurrentSession().beginTransaction();
 
/branches/grupo17529/impl/src/hbm/pt/estgp/estgweb/domain/Course.hbm.xml
79,6 → 79,10
<property name="separatedTurmas" type="boolean">
<column name="separatedTurmas" default="false"/>
</property>
<!-- Ponto 1 Criaçao de Variavel-->
<property name="courseReportDocument" type="string">
<column name="courseReportDocument" sql-type="LONGTEXT"/>
</property>
<many-to-one name="course" class="pt.estgp.estgweb.domain.Course" outer-join="true" lazy="false" column="course_id"/>
<subclass name="pt.estgp.estgweb.domain.CourseYearImpl" discriminator-value="CourseYearImpl"/>
</class>
/branches/grupo17529/impl/build.xml
66,6 → 66,7
<target name="initDirs">
<mkdir dir="${log.dir}"/>
<mkdir dir="${data.dir}"/>
<mkdir dir="${tmp.dir}"/>
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.dir.classes}"/>
<mkdir dir="${build.dir.war}"/>
/branches/grupo17529/impl/gen/java/pt/estgp/estgweb/domain/CourseYear.java
2,12 → 2,13
// Generated 4/nov/2017 19:35:42 by Hibernate Tools 3.2.0.b9
 
 
import java.io.Serializable;
import java.util.Date;
 
/**
* CourseYear generated by hbm2java
*/
public abstract class CourseYear extends pt.estgp.estgweb.domain.DomainSerializableObject implements java.io.Serializable {
public abstract class CourseYear extends DomainSerializableObject implements Serializable {
 
 
private long id;
16,7 → 17,16
private String importYear;
private boolean separatedTurmas;
private Course course;
private String courseReportDocument;
 
public String getCourseReportDocument() {
return courseReportDocument;
}
 
public void setCourseReportDocument(String courseReportDocument) {
this.courseReportDocument = courseReportDocument;
}
 
public CourseYear() {
}
 
/branches/grupo11/impl/conf/WEB-INF/struts/struts-courses.xml
164,7 → 164,8
 
<action path="/user/courseReportTools" forward="page.course.report.tools"/>
<action path="/user/loadCourseReportTools" forward="page.course.report.tools.load"/>
<action path="/user/editCourseReport" forward="page.course.report.edit"/>
<!--Chama o servico de edição -->
<action path="/user/editCourseReport" forward="/user/courseReport.do?dispatch=loadReportDocument"/>
 
<action path="/user/courseReport"
type="pt.estgp.estgweb.web.controllers.courses.CoursesServicesController"
173,9 → 174,15
parameter="dispatch"
validate="true"
input="page.widget.json.fail.validations">
<!--Dispacho para a mesma pagina de edição -->
<forward name="editReport" path="page.course.report.edit"/>
</action>
 
 
 
 
 
 
</action-mappings>
 
</struts-config>
/branches/grupo11/impl/conf/berserk/sd.xml
4022,11 → 4022,14
<defaultMethod>loadPlanYearForCourseUnitCode</defaultMethod>
<filterChains>
<chain name="Logger"/>
<chain name="Session"/>
<chain name="CoordinatorCourse"/>
</filterChains>
</service>
 
 
 
 
<!-- SERVICOS DE GERACAO DE RELATORIO DE CURSO -->
 
 
4045,9 → 4048,50
<filterChains>
<chain name="Logger"/>
<chain name="Session"/>
 
 
</filterChains>
</service>
 
 
 
<!-- ServicosExameES -->
 
<service>
<name>CourseReportDocumentSave</name>
<implementationClass>pt.estgp.estgweb.services.courses.CourseReportServices</implementationClass>
<description>
@reportCourseDocument documento course report em JSON
Servico para guardar um courseReport na base de dados
Guarda o documento do curso
 
</description>
<filterChains>
<chain name="Logger"/> <!--Log dos acessos -->
<!-- chain name "Session" /> -->
<!-- chain name="CoordinatorCourse"/>/ -->
</filterChains>
<isTransactional>true</isTransactional>
<defaultMethod>saveReportDocument</defaultMethod>
</service>
 
 
<service>
<name>CourseReportDocumentLoad</name>
<implementationClass>pt.estgp.estgweb.services.courses.CourseReportServices</implementationClass>
<description>
@courseCode código do curso
@year import year ( ano do report)
Servico para fazer load a um courseReport da base de dados
Carrega o documento do curso
</description>
<filterChains>
<chain name = "Logger"/>
<chain name = "Session"/>
<chain name = "CoordinatorCourse"/>
</filterChains>
<isTransactional>true</isTransactional>
<defaultMethod>loadReportDocument</defaultMethod>
</service>
 
</serviceDefinitions>
/branches/grupo11/impl/conf/berserk/fd.xml
100,6 → 100,7
</description>
<isTransactional>false</isTransactional>
</filter>
 
<filter>
<name>IsTeacherInCourseUnitUsersClass</name>
<implementationClass>pt.estgp.estgweb.filters.filters.IsTeacherInCourseUnitUsersClass</implementationClass>
182,7 → 183,7
<name>LogAccess</name>
<implementationClass>pt.estgp.estgweb.filters.filters.AccessLogger</implementationClass>
<description>Writes accesses to a file</description>
<isTransactional>false</isTransactional>
<isTransactional>false</isTransactional>f
</filter>
<filter>
<name>SessionLoad</name>
/branches/grupo11/impl/conf/berserk/fcd.xml
56,7 → 56,15
<invocationTiming>1</invocationTiming>
<filterClass>pt.estgp.estgweb.filters.chains.AdminControlFilter</filterClass>
</filterChain>
<!-- My Filter Chain -->
<filterChain>
<name>CoordinatorCourse</name>
<expression>AuthenticatedUsers &amp;&amp; RoleUsers("teacher,courseCoordinator") || RoleUsers("super")</expression>
<description>Validate if user is authenticated and is a teacher or a super</description>
<invocationTiming>1</invocationTiming>
<filterClass>pt.estgp.estgweb.filters.chains.AdminControlFilter</filterClass>
</filterChain>
<filterChain>
<name>DirectorsCoordinators</name>
<expression>AuthenticatedUsers</expression>
<description>Validate if a user is coordinator or director</description>
/branches/grupo11/impl/src/java/pt/estgp/estgweb/services/courses/CourseReportServices.java
9,6 → 9,10
import org.json.JSONObject;
import pt.estgp.estgweb.domain.*;
import pt.estgp.estgweb.domain.dao.DaoFactory;
import pt.estgp.estgweb.domain.dao.DaoUtils;
import pt.estgp.estgweb.domain.dao.impl.CourseDao;
import pt.estgp.estgweb.domain.dao.impl.CourseDaoImpl;
import pt.estgp.estgweb.domain.dao.impl.CourseYearDaoImpl;
import pt.estgp.estgweb.filters.chains.ResourceAccessControlEnum;
import pt.estgp.estgweb.services.courses.coursereport.CourseReportUtils;
import pt.estgp.estgweb.services.courses.coursereport.documentmodel.*;
29,8 → 33,10
import pt.estgp.estgweb.web.controllers.utils.FileUploaded;
import pt.utl.ist.berserk.logic.serviceManager.IService;
 
import javax.swing.text.View;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
337,6 → 343,8
for(CourseUnit cu :units)
{
CourseUnitDtpStat statFound = CourseReportUtils.findCourseUnitDtpStat(statsLoaded, (CourseUnitImpl) cu);
 
 
if(statFound == null)
{
statFound = CourseReportUtils.createCourseUnitDtpStat(cu);
450,9 → 458,78
 
 
 
/* Save Method */
 
public String saveReportDocument (String reportDocumentJson,UserSession session){
 
CourseReportDocument reportDocument = CourseReportDocument.fromJson(reportDocumentJson);
List<CourseYear> cyList = DaoFactory.getCourseYearDaoImpl().findCourseYear(reportDocument.getCourseCode(),reportDocument.getYear());
 
if(cyList!= null){
 
 
 
for (CourseYear courseYear : cyList) {
 
courseYear.setCourseReportDocument(reportDocument.toJson());
 
 
}
 
DaoFactory.getCourseYearDaoImpl().save(cyList);
}
else
{
CourseYear cy = DomainObjectFactory.createCourseYearImpl();
cy.setCourseReportDocument(reportDocument.toJson());
Course course = DaoFactory.getCourseDaoImpl().findCourseByCodeAndYear(reportDocument.getCourseCode(),reportDocument.getYear());
cy.setImportYear(reportDocument.getYear());
cy.setSaveDate(session.getSaveDate());
course.getCourseYears().add(cy);
cy.setCourse(course);
DaoFactory.getCourseYearDaoImpl().save(cy);
}
 
 
return reportDocumentJson;
}
 
 
/* LOAD METHOD */
 
 
public String loadReportDocument(String courseCode, String year, UserSession session){
 
CourseYear cy = DaoFactory.getCourseYearDaoImpl().findCourseYear(courseCode,year).get(0);
CourseReportDocument reportDocument = null;
String reportDocumentJson = null;
 
if(cy!= null){
reportDocumentJson = cy.getCourseReportDocument();
 
}
else{
try {
reportDocument = createNewCourseReportDocument(courseCode,year);
saveReportDocument(reportDocumentJson,session);
reportDocumentJson = reportDocument.toJson();
 
 
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
 
 
return reportDocumentJson;
 
 
}
 
 
 
/****************************************************************************/
/*
 
641,11 → 718,6
 
 
 
 
 
 
 
 
public static void main(String[] args) throws IOException, JSONException {
AbstractDao.getCurrentSession().beginTransaction();
 
/branches/grupo11/impl/src/java/pt/estgp/estgweb/web/controllers/courses/CoursesServicesController.java
1,7 → 1,13
package pt.estgp.estgweb.web.controllers.courses;
 
import jomm.dao.impl.AbstractDao;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.json.JSONObject;
import pt.estgp.estgweb.domain.CourseImpl;
import pt.estgp.estgweb.domain.dao.DaoFactory;
import pt.estgp.estgweb.services.courses.coursereport.documentmodel.CourseReportDocument;
import pt.estgp.estgweb.web.controllers.utils.AbstractWidgetAjaxController;
import pt.estgp.estgweb.web.utils.RequestUtils;
import pt.utl.ist.berserk.logic.serviceManager.IServiceManager;
43,4 → 49,30
}
 
 
public ActionForward loadReportDocument(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Throwable{
 
String courseCode = request.getParameter("courseCode");
String year = request.getParameter("year");
 
AbstractDao.getCurrentSession().beginTransaction();
 
CourseImpl courseImpl = DaoFactory.getCourseDaoImpl().findCourseByCode(courseCode);
request.setAttribute("course",courseImpl);
 
 
IServiceManager sm = ServiceManager.getInstance();
String[] names = new String[]{courseCode,year};
Object[] args = new Object[] {courseCode,year};
 
 
String documentJson = (String) sm.execute(RequestUtils.getRequester(request,response),"loadReportDocument", args,names);
 
request.setAttribute("courseDocumentJson",documentJson);
 
AbstractDao.getCurrentSession().getTransaction().commit();
 
return mapping.findForward("editReport");
}
 
 
}
/branches/grupo11/impl/src/hbm/pt/estgp/estgweb/domain/Course.hbm.xml
79,6 → 79,9
<property name="separatedTurmas" type="boolean">
<column name="separatedTurmas" default="false"/>
</property>
<property name="courseReportDocument" type="string">
<column name="courseReportDocument" sql-type="LONGTEXT"/>
</property>
<many-to-one name="course" class="pt.estgp.estgweb.domain.Course" outer-join="true" lazy="false" column="course_id"/>
<subclass name="pt.estgp.estgweb.domain.CourseYearImpl" discriminator-value="CourseYearImpl"/>
</class>
/branches/grupo11/impl/src/web/user/courses/courseReportEdit.jsp
1,12 → 1,5
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="jomm.dao.impl.AbstractDao" %>
<%@ page import="pt.estgp.estgweb.domain.CourseImpl" %>
<%@ page import="pt.estgp.estgweb.domain.dao.DaoFactory" %>
<%@ page import="pt.estgp.estgweb.utils.documentBuilder.TextComponent" %>
<%@ page import="pt.estgp.estgweb.utils.documentBuilder.ImageComponent" %>
<%@ page import="pt.estgp.estgweb.services.courses.CourseReportServices" %>
<%@ page import="pt.estgp.estgweb.services.courses.coursereport.documentmodel.CourseReportDocument" %>
<%@ page import="org.json.JSONException" %>
 
<%@ taglib uri="/WEB-INF/tlds/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/tlds/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/tlds/jomm.tld" prefix="jomm" %>
15,335 → 8,5
<%@ taglib uri="/WEB-INF/tlds/baco.tld" prefix="baco" %>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>
 
<link rel="stylesheet" href="<%=request.getContextPath()%>/js/jquery-ui-1.12.1/jquery-ui.css">
<script src="<%=request.getContextPath()%>/js/jquery-ui-1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="<%=request.getContextPath()%>/css/flora-commons/flora.resizable.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.2/jspdf.min.js"></script>
<script>
function demoFromHTML() {
var pdf = new jsPDF('p', 'pt', 'letter');
// source can be HTML-formatted string, or a reference
// to an actual DOM element from which the text will be scraped.
source = $('#courseReportApp')[0];
 
// we support special element handlers. Register them with jQuery-style
// ID selector for either ID or node name. ("#iAmID", "div", "span" etc.)
// There is no support for any other type of selectors
// (class, of compound) at this time.
specialElementHandlers = {
// element with id of "bypass" - jQuery style selector
'#bypassme': function (element, renderer) {
// true = "handled elsewhere, bypass text extraction"
return true
}
};
margins = {
top: 80,
bottom: 60,
left: 40,
width: 522
};
// all coords and widths are in jsPDF instance's declared units
// 'inches' in this case
pdf.fromHTML(
source, // HTML string or DOM elem ref.
margins.left, // x coord
margins.top, { // y coord
'width': margins.width, // max width of content on PDF
'elementHandlers': specialElementHandlers
},
 
function (dispose) {
// dispose: object with X, Y of the last line add to the PDF
// this allow the insertion of new lines after html
//var pdfDocument = pdf.save('Test.pdf');
var pdfDocument = pdf.output();
 
var boundary = '---------------------------';
boundary += Math.floor(Math.random()*32768);
boundary += Math.floor(Math.random()*32768);
boundary += Math.floor(Math.random()*32768);
 
var body = '';
body += '--' + boundary + '\r\n' +
'Content-Disposition: form-data; name="filesInputId-UPLOAD[]"; filename="20170530_210340.pdf"' + '\r\n';
body += 'Content-Type: application/pdf';
body += '\r\n\r\n';
body += pdfDocument;
body += '\r\n'
body += '--' + boundary + '--';
 
 
 
$.ajax({
type: "POST",
cache: false,
url: "<%=request.getContextPath()%>/filesUpload",
data: body ,
processData: false,
contentType : 'multipart/form-data; boundary=' + boundary,
success: function (data) {
alert('success');
return false;
}
});
}, margins
);
}
</script>
 
<%
 
String courseCode = request.getParameter("courseCode");
String year = request.getParameter("year");
AbstractDao.getCurrentSession().beginTransaction();
CourseImpl courseImpl = DaoFactory.getCourseDaoImpl().findCourseByCode(courseCode);
request.setAttribute("course",courseImpl);
CourseReportDocument courseReport = null;
try {
courseReport = new CourseReportServices().createNewCourseReportDocument(courseCode, year);
} catch (Throwable e) {
System.out.println(e);
e.printStackTrace();
}
String courseReportJson = courseReport.toJson();
request.setAttribute("courseDocumentJson",courseReportJson);
request.setAttribute("courseDocument",courseReport);
 
%>
<%--<a href="javascript:demoFromHTML()" class="button">Run Code</a>--%>
 
<div class="container-fluid">
 
<style>
.separatorSection
{
border: 1px solid #ddd;
}
</style>
 
 
<!-- Apresentacao da Unidade -->
 
<div class="panel panel-default">
<div class="panel-heading">
Relatório Anual do curso: ${course.name}
</div>
<div class="panel-body">
 
<p><b class="label-info">Tipo de Curso:</b> <bean:message key="course.${course.degree}"/></p>
<p><b class="label-info">Ano Lectivo:</b> ${course.importYear}</p>
<p><b class="label-info">Departamento:</b> ${course.department.name}</p>
<p><b class="label-info">Escola:</b> ${course.department.courseSchool.name}</p>
 
 
 
 
<script>
 
//Especifico da aplicacao
var courseReportApp = angular.module('courseReportApp', ['ui.tree']);
GLOBAL_BacoAngularAppDependencies.push('courseReportApp');
 
 
courseReportApp.directive('resizable', function () {
return {
restrict: 'A',
scope: {
callback: '&onResize'
},
link: function postLink(scope, elem, attrs) {
elem.resizable();
elem.on('resize', function (evt, ui, comp) {
scope.$apply(function() {
if (scope.callback) {
scope.callback({$evt: evt, $ui: ui, $comp: comp });
}
})
});
}
};
});
 
 
courseReportApp.controller('courseReportAppController', function($scope)
{
 
$scope.docAppSelector = "#courseReportApp";
$scope.report = <%=courseReportJson%>
 
$scope.resize = function(evt,ui,comp) {
//console.log (evt,ui);
comp.width = ui.size.width;
comp.height = ui.size.height;
}
 
/**
* @classe class to match
* @superClasses array of strings
* */
$scope.contains = function(obj,classe)
{
if(obj['@class'] && obj['@class'] == classe)
return true;
if(obj.allSuperClasses)
{
for(var i in obj.allSuperClasses)
{
if(classe == obj.allSuperClasses[i])
return true;
}
}
return false;
}
 
$scope.showSep = function(section,subSection)
{
var s;
for(s in section.sections)
{
section.sections[s].active = false;
}
/*$(".separatorSectionNav").each(function()
{
angular.element($(this)).scope().section.active = false;
});*/
subSection.active = true;
}
 
/**
* Este metodo devolve o template mais profundo na hierarquia de classes
* permitindo emular o override, quanto mais especifica for a classe
* e caso exista template é esse o template devolvido
* procura um script com o id da classe e se nao existir
* vai subindo nas super classes
* @param obj
* @returns {*}
*/
$scope.class2id = function(obj)
{
var objClassId = obj["@class"].replaceAll(".","_");
if($("script#" + objClassId).length > 0)
{
return objClassId;
}
if(obj.allSuperClasses)
{
var s;
for(s in obj.allSuperClasses)
{
var superClass = obj.allSuperClasses[s];
var superClassId = superClass.replaceAll(".","_");
if($("script#" + superClassId).length > 0)
{
return superClassId;
}
}
}
return obj["@class"].replaceAll(".","_");
}
 
$scope.addText = function(parentCustomPane)
{
$scope.addSimpleDocComponent(parentCustomPane,"pt.estgp.estgweb.utils.documentBuilder.TextComponent")
}
 
$scope.addImage = function(parentCustomPane)
{
$scope.addSimpleDocComponent(parentCustomPane,"pt.estgp.estgweb.utils.documentBuilder.ImageComponent")
}
 
$scope.addSimpleDocComponent = function(parentCustomPane,classComponent)
{
if(!parentCustomPane.components)
{
parentCustomPane.components = [];
}
parentCustomPane.components.push(
{
"@class" : classComponent
}
);
}
$scope.removeComponent = function(index,array)
{
array.splice(index,1);
}
 
$scope.callbackUploadedFiles = function(filesUploadResult,token,targetElement)
{
var modelObject = BacoAngularUtils.getAngularElementModel(targetElement);
 
if(modelObject.image && modelObject.image.identifier)
{
widgetCallWithActionParameters(
"<%=request.getContextPath()%>/user/json/repository.do",
"replaceRepositoryFileFromTempPrivateDomain",
{
"identifier" : modelObject.image.identifier,
"fileUploaded" : BacoJS.stringifyOrdered(filesUploadResult.uploadedFiles[0])
},
"#courseReportApp",
function(repositoryFile4JsonView)
{
modelObject.image = repositoryFile4JsonView;
//image URL is generated on reimport just to avoid caching
modelObject.imageUrl = "<%=request.getContextPath()%>/repositoryStream/" + modelObject.image.identifier + "?" + new Date().getTime();
angular.element($("#courseReportApp")).scope().$apply();
},
function(){}
);
}
else
{
widgetCallWithActionParameters(
"<%=request.getContextPath()%>/user/json/repository.do",
"saveRepositoryFileFromTempPrivateDomain",
{
"fileUploaded" : BacoJS.stringifyOrdered(filesUploadResult.uploadedFiles[0])
},
"#courseReportApp",
function(repositoryFile4JsonView)
{
modelObject.image = repositoryFile4JsonView;
modelObject.imageUrl = "<%=request.getContextPath()%>/repositoryStream/" + modelObject.image.identifier + "?" + new Date().getTime();
angular.element($("#courseReportApp")).scope().$apply();
},
function(){}
);
}
}
 
 
 
 
});
</script>
 
<!--TEMPLATES FOR DOCUMENT BUILDER-->
<jsp:include page="../utils/documentsBuilder.jsp"/>
<jsp:include page="../utils/reportEdit.jsp"/>
<jsp:include page="coursereport/templates.jsp"/>
 
<div class="form-vertical">
<div id="courseReportApp" ng-app="courseReportApp" ng-controller="courseReportAppController">
 
<div ng-init="section=report;" ng-include="'pt_estgp_estgweb_utils_documentBuilder_DocumentSection'">
 
</div>
 
<!-- <pre class="code">{{ report | json }}</pre>-->
 
 
 
</div><!--App-->
</div> <!--form-->
 
</div><!--Panel Body-->
 
</div><!--Panel-->
 
</div><!--container-fluid-->
 
<%
AbstractDao.getCurrentSession().getTransaction().commit();
%>
/branches/grupo11/impl/src/web/user/utils/reportEdit.jsp
New file
0,0 → 1,320
<%--
Created by IntelliJ IDEA.
User: Pedro
Date: 01/02/2018
Time: 18:05
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
 
 
<link rel="stylesheet" href="<%=request.getContextPath()%>/js/jquery-ui-1.12.1/jquery-ui.css">
<script src="<%=request.getContextPath()%>/js/jquery-ui-1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="<%=request.getContextPath()%>/css/flora-commons/flora.resizable.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.2/jspdf.min.js"></script>
<script>
function demoFromHTML() {
var pdf = new jsPDF('p', 'pt', 'letter');
// source can be HTML-formatted string, or a reference
// to an actual DOM element from which the text will be scraped.
source = $('#courseReportApp')[0];
 
// we support special element handlers. Register them with jQuery-style
// ID selector for either ID or node name. ("#iAmID", "div", "span" etc.)
// There is no support for any other type of selectors
// (class, of compound) at this time.
specialElementHandlers = {
// element with id of "bypass" - jQuery style selector
'#bypassme': function (element, renderer) {
// true = "handled elsewhere, bypass text extraction"
return true
}
};
margins = {
top: 80,
bottom: 60,
left: 40,
width: 522
};
// all coords and widths are in jsPDF instance's declared units
// 'inches' in this case
pdf.fromHTML(
source, // HTML string or DOM elem ref.
margins.left, // x coord
margins.top, { // y coord
'width': margins.width, // max width of content on PDF
'elementHandlers': specialElementHandlers
},
 
function (dispose) {
// dispose: object with X, Y of the last line add to the PDF
// this allow the insertion of new lines after html
//var pdfDocument = pdf.save('Test.pdf');
var pdfDocument = pdf.output();
 
var boundary = '---------------------------';
boundary += Math.floor(Math.random()*32768);
boundary += Math.floor(Math.random()*32768);
boundary += Math.floor(Math.random()*32768);
 
var body = '';
body += '--' + boundary + '\r\n' +
'Content-Disposition: form-data; name="filesInputId-UPLOAD[]"; filename="20170530_210340.pdf"' + '\r\n';
body += 'Content-Type: application/pdf';
body += '\r\n\r\n';
body += pdfDocument;
body += '\r\n'
body += '--' + boundary + '--';
 
 
 
$.ajax({
type: "POST",
cache: false,
url: "<%=request.getContextPath()%>/filesUpload",
data: body ,
processData: false,
contentType : 'multipart/form-data; boundary=' + boundary,
success: function (data) {
alert('success');
return false;
}
});
}, margins
);
}
</script>
 
 
<%--<a href="javascript:demoFromHTML()" class="button">Run Code</a>--%>
 
<div class="container-fluid">
 
<style>
.separatorSection
{
border: 1px solid #ddd;
}
</style>
 
 
<!-- Apresentacao da Unidade -->
 
<div class="panel panel-default">
<div class="panel-heading">
Relatório Anual do curso: ${course.name}
</div>
<div class="panel-body">
 
<p><b class="label-info">Tipo de Curso:</b> <bean:message key="course.${course.degree}"/></p>
<p><b class="label-info">Ano Lectivo:</b> ${course.importYear}</p>
<p><b class="label-info">Departamento:</b> ${course.department.name}</p>
<p><b class="label-info">Escola:</b> ${course.department.courseSchool.name}</p>
 
 
 
 
<script>
 
//Especifico da aplicacao
var courseReportApp = angular.module('courseReportApp', ['ui.tree']);
GLOBAL_BacoAngularAppDependencies.push('courseReportApp');
 
 
courseReportApp.directive('resizable', function () {
return {
restrict: 'A',
scope: {
callback: '&onResize'
},
link: function postLink(scope, elem, attrs) {
elem.resizable();
elem.on('resize', function (evt, ui, comp) {
scope.$apply(function() {
if (scope.callback) {
scope.callback({$evt: evt, $ui: ui, $comp: comp });
}
})
});
}
};
});
 
 
courseReportApp.controller('courseReportAppController', function($scope)
{
 
$scope.docAppSelector = "#courseReportApp";
$scope.report = ${courseDocumentJson};
 
$scope.resize = function(evt,ui,comp) {
//console.log (evt,ui);
comp.width = ui.size.width;
comp.height = ui.size.height;
}
 
/**
* @classe class to match
* @superClasses array of strings
* */
$scope.contains = function(obj,classe)
{
if(obj['@class'] && obj['@class'] == classe)
return true;
if(obj.allSuperClasses)
{
for(var i in obj.allSuperClasses)
{
if(classe == obj.allSuperClasses[i])
return true;
}
}
return false;
}
 
$scope.showSep = function(section,subSection)
{
var s;
for(s in section.sections)
{
section.sections[s].active = false;
}
/*$(".separatorSectionNav").each(function()
{
angular.element($(this)).scope().section.active = false;
});*/
subSection.active = true;
}
 
/**
* Este metodo devolve o template mais profundo na hierarquia de classes
* permitindo emular o override, quanto mais especifica for a classe
* e caso exista template é esse o template devolvido
* procura um script com o id da classe e se nao existir
* vai subindo nas super classes
* @param obj
* @returns {*}
*/
$scope.class2id = function(obj)
{
var objClassId = obj["@class"].replaceAll(".","_");
if($("script#" + objClassId).length > 0)
{
return objClassId;
}
if(obj.allSuperClasses)
{
var s;
for(s in obj.allSuperClasses)
{
var superClass = obj.allSuperClasses[s];
var superClassId = superClass.replaceAll(".","_");
if($("script#" + superClassId).length > 0)
{
return superClassId;
}
}
}
return obj["@class"].replaceAll(".","_");
}
 
$scope.addText = function(parentCustomPane)
{
$scope.addSimpleDocComponent(parentCustomPane,"pt.estgp.estgweb.utils.documentBuilder.TextComponent")
}
 
$scope.addImage = function(parentCustomPane)
{
$scope.addSimpleDocComponent(parentCustomPane,"pt.estgp.estgweb.utils.documentBuilder.ImageComponent")
}
 
$scope.addSimpleDocComponent = function(parentCustomPane,classComponent)
{
if(!parentCustomPane.components)
{
parentCustomPane.components = [];
}
parentCustomPane.components.push(
{
"@class" : classComponent
}
);
}
$scope.removeComponent = function(index,array)
{
array.splice(index,1);
}
 
$scope.callbackUploadedFiles = function(filesUploadResult,token,targetElement)
{
var modelObject = BacoAngularUtils.getAngularElementModel(targetElement);
 
if(modelObject.image && modelObject.image.identifier)
{
widgetCallWithActionParameters(
"<%=request.getContextPath()%>/user/json/repository.do",
"replaceRepositoryFileFromTempPrivateDomain",
{
"identifier" : modelObject.image.identifier,
"fileUploaded" : BacoJS.stringifyOrdered(filesUploadResult.uploadedFiles[0])
},
"#courseReportApp",
function(repositoryFile4JsonView)
{
modelObject.image = repositoryFile4JsonView;
//image URL is generated on reimport just to avoid caching
modelObject.imageUrl = "<%=request.getContextPath()%>/repositoryStream/" + modelObject.image.identifier + "?" + new Date().getTime();
angular.element($("#courseReportApp")).scope().$apply();
},
function(){}
);
}
else
{
widgetCallWithActionParameters(
"<%=request.getContextPath()%>/user/json/repository.do",
"saveRepositoryFileFromTempPrivateDomain",
{
"fileUploaded" : BacoJS.stringifyOrdered(filesUploadResult.uploadedFiles[0])
},
"#courseReportApp",
function(repositoryFile4JsonView)
{
modelObject.image = repositoryFile4JsonView;
modelObject.imageUrl = "<%=request.getContextPath()%>/repositoryStream/" + modelObject.image.identifier + "?" + new Date().getTime();
angular.element($("#courseReportApp")).scope().$apply();
},
function(){}
);
}
}
 
 
 
 
});
</script>
 
<!--TEMPLATES FOR DOCUMENT BUILDER-->
<jsp:include page="../utils/documentsBuilder.jsp"/>
 
 
<div class="form-vertical">
<div id="courseReportApp" ng-app="courseReportApp" ng-controller="courseReportAppController">
 
<div ng-init="section=report;" ng-include="'pt_estgp_estgweb_utils_documentBuilder_DocumentSection'">
 
</div>
 
<!-- <pre class="code">{{ report | json }}</pre>-->
 
 
 
</div><!--App-->
</div> <!--form-->
 
</div><!--Panel Body-->
 
</div><!--Panel-->
 
</div><!--container-fluid-->
/branches/grupo11/impl/build.xml
66,6 → 66,7
<target name="initDirs">
<mkdir dir="${log.dir}"/>
<mkdir dir="${data.dir}"/>
<mkdir dir="${tmp.dir}"/>
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.dir.classes}"/>
<mkdir dir="${build.dir.war}"/>
/branches/grupo11/impl/gen/java/pt/estgp/estgweb/domain/CourseYear.java
2,12 → 2,13
// Generated 4/nov/2017 19:35:42 by Hibernate Tools 3.2.0.b9
 
 
import java.io.Serializable;
import java.util.Date;
 
/**
* CourseYear generated by hbm2java
*/
public abstract class CourseYear extends pt.estgp.estgweb.domain.DomainSerializableObject implements java.io.Serializable {
public abstract class CourseYear extends DomainSerializableObject implements Serializable {
 
 
private long id;
16,7 → 17,16
private String importYear;
private boolean separatedTurmas;
private Course course;
private String courseReportDocument;
 
public String getCourseReportDocument() {
return courseReportDocument;
}
 
public void setCourseReportDocument(String courseReportDocument) {
this.courseReportDocument = courseReportDocument;
}
 
public CourseYear() {
}