Skip to content

Commit

Permalink
Issue #8 Add support for mix-in annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
nmorel committed Jun 28, 2014
1 parent d76c5b1 commit e2cfc35
Show file tree
Hide file tree
Showing 50 changed files with 2,390 additions and 270 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public KeyTypeConfiguration<T> deserializer( Class<? extends KeyDeserializer> de

private final Map<Class, Class> mapTypeToKeyDeserializer = new HashMap<Class, Class>();

private final Map<Class, Class> mapMixInAnnotations = new HashMap<Class, Class>();

protected AbstractConfiguration() {
configure();
}
Expand Down Expand Up @@ -126,6 +128,21 @@ protected <T> KeyTypeConfiguration<T> key( Class<T> type ) {
return new KeyTypeConfiguration<T>( type );
}

/**
* Method to use for adding mix-in annotations to use for augmenting
* specified class or interface. All annotations from
* <code>mixinSource</code> are taken to override annotations
* that <code>target</code> (or its supertypes) has.
*
* @param target Class (or interface) whose annotations to effectively override
* @param mixinSource Class (or interface) whose annotations are to
* be "added" to target's annotations, overriding as necessary
*/
protected AbstractConfiguration addMixInAnnotations( Class<?> target, Class<?> mixinSource ) {
mapMixInAnnotations.put( target, mixinSource );
return this;
}

protected abstract void configure();

public Map<Class, Class> getMapTypeToSerializer() {
Expand All @@ -143,4 +160,8 @@ public Map<Class, Class> getMapTypeToKeySerializer() {
public Map<Class, Class> getMapTypeToKeyDeserializer() {
return mapTypeToKeyDeserializer;
}

public Map<Class, Class> getMapMixInAnnotations() {
return mapMixInAnnotations;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2014 Nicolas Morel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.github.nmorel.gwtjackson.client.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.fasterxml.jackson.annotation.JacksonAnnotation;
import com.github.nmorel.gwtjackson.client.ObjectMapper;
import com.github.nmorel.gwtjackson.client.ObjectReader;
import com.github.nmorel.gwtjackson.client.ObjectWriter;

/**
* Annotation used to define mix-in annotations specific to the annotated {@link ObjectMapper},
* {@link ObjectReader} or {@link ObjectWriter}.
*
* @author Nicolas Morel.
*/
@Target( {ElementType.TYPE} )
@Retention( RetentionPolicy.CLASS )
@JacksonAnnotation
public @interface JsonMixIns {

/**
* List of {@link JsonMixIn} annotations
*/
public JsonMixIn[] value();

/**
* Definition of a mix-in annotation.
*/
public @interface JsonMixIn {

/**
* Class targeted by the mix-in annotation
*/
public Class<?> target();

/**
* Mix-in class
*/
public Class<?> mixIn();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ public String create( JClassType beanType ) throws UnableToCompleteException {
enclosingType = enclosingType.getEnclosingType();
}

// if the type is specific to the mapper, we concatenate the name and hash of the mapper to it
if ( configuration.isSpecificToMapper( beanType ) ) {
JClassType rootMapperClass = configuration.getRootMapperClass();
builder.insert( 0, '_' ).insert( 0, configuration.getRootMapperHash() ).insert( 0, '_' ).insert( 0, rootMapperClass
.getSimpleSourceName() );
}

String simpleSerializerClassName = builder.toString() + "BeanJsonSerializerImpl";
String qualifiedSerializerClassName = packageName + "." + simpleSerializerClassName;
String simpleDeserializerClassName = builder.toString() + "BeanJsonDeserializerImpl";
Expand All @@ -139,7 +146,7 @@ public String create( JClassType beanType ) throws UnableToCompleteException {

if ( null == mapperInfo.getBeanInfo() ) {
// retrieve the informations on the beans and its properties
BeanInfo info = BeanInfo.process( logger, typeOracle, mapperInfo );
BeanInfo info = BeanInfo.process( logger, typeOracle, configuration, mapperInfo );
mapperInfo.setBeanInfo( info );

Map<String, PropertyInfo> properties = findAllProperties( info );
Expand Down Expand Up @@ -202,12 +209,12 @@ private Map<String, PropertyInfo> findAllProperties( BeanInfo info ) throws Unab
return result;
}

ImmutableMap<String, PropertyAccessors> fieldsMap = PropertyParser.findPropertyAccessors( logger, info );
ImmutableMap<String, PropertyAccessors> fieldsMap = PropertyParser.findPropertyAccessors( configuration, logger, info );

// Processing all the properties accessible via field, getter or setter
Map<String, PropertyInfo> propertiesMap = new LinkedHashMap<String, PropertyInfo>();
for ( PropertyAccessors field : fieldsMap.values() ) {
PropertyInfo property = PropertyInfo.process( logger, typeOracle, field, mapperInfo );
PropertyInfo property = PropertyInfo.process( logger, typeOracle, configuration, field, mapperInfo );
if ( !property.isVisible() ) {
logger.log( TreeLogger.Type.DEBUG, "Field " + field.getPropertyName() + " of type " + info.getType() + " is not visible" );
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,49 +32,49 @@
import com.google.gwt.core.ext.typeinfo.JType;

import static com.github.nmorel.gwtjackson.rebind.CreatorUtils.extractBeanType;
import static com.github.nmorel.gwtjackson.rebind.CreatorUtils.findAnnotationOnAnyAccessor;
import static com.github.nmorel.gwtjackson.rebind.CreatorUtils.findFirstEncounteredAnnotationsOnAllHierarchy;

/**
* @author Nicolas Morel
*/
public class BeanIdentityInfo {

public static BeanIdentityInfo process( TreeLogger logger, JacksonTypeOracle typeOracle,
public static BeanIdentityInfo process( TreeLogger logger, JacksonTypeOracle typeOracle, RebindConfiguration configuration,
JClassType type ) throws UnableToCompleteException {
return process( logger, typeOracle, type, null, false );
return process( logger, typeOracle, configuration, type, null, false );
}

public static BeanIdentityInfo process( TreeLogger logger, JacksonTypeOracle typeOracle, JType type,
PropertyAccessors propertyAccessors ) throws UnableToCompleteException {
public static BeanIdentityInfo process( TreeLogger logger, JacksonTypeOracle typeOracle, RebindConfiguration configuration,
JType type, PropertyAccessors propertyAccessors ) throws UnableToCompleteException {
JClassType classType = extractBeanType( logger, typeOracle, type );
if ( null == classType ) {
return null;
} else {
return process( logger, typeOracle, classType, propertyAccessors, true );
return process( logger, typeOracle, configuration, classType, propertyAccessors, true );
}
}

private static BeanIdentityInfo process( TreeLogger logger, JacksonTypeOracle typeOracle, JClassType type,
PropertyAccessors propertyAccessors, boolean property ) throws UnableToCompleteException {
private static BeanIdentityInfo process( TreeLogger logger, JacksonTypeOracle typeOracle, RebindConfiguration configuration,
JClassType type, PropertyAccessors propertyAccessors,
boolean property ) throws UnableToCompleteException {
JsonIdentityInfo jsonIdentityInfo = null;
JsonIdentityReference jsonIdentityReference = null;
if ( property ) {
jsonIdentityInfo = findAnnotationOnAnyAccessor( propertyAccessors, JsonIdentityInfo.class );
jsonIdentityReference = findAnnotationOnAnyAccessor( propertyAccessors, JsonIdentityReference.class );
jsonIdentityInfo = propertyAccessors.getAnnotation( JsonIdentityInfo.class );
jsonIdentityReference = propertyAccessors.getAnnotation( JsonIdentityReference.class );
if ( null == jsonIdentityInfo && null == jsonIdentityReference ) {
// no override on field
return null;
}
}

if ( null == jsonIdentityInfo ) {
jsonIdentityInfo = findFirstEncounteredAnnotationsOnAllHierarchy( type, JsonIdentityInfo.class );
jsonIdentityInfo = findFirstEncounteredAnnotationsOnAllHierarchy( configuration, type, JsonIdentityInfo.class );
}

if ( null != jsonIdentityInfo && ObjectIdGenerators.None.class != jsonIdentityInfo.generator() ) {
if ( null == jsonIdentityReference ) {
jsonIdentityReference = findFirstEncounteredAnnotationsOnAllHierarchy( type, JsonIdentityReference.class );
jsonIdentityReference = findFirstEncounteredAnnotationsOnAllHierarchy( configuration, type, JsonIdentityReference.class );
}
return new BeanIdentityInfo( jsonIdentityInfo.property(), null != jsonIdentityReference && jsonIdentityReference
.alwaysAsId(), jsonIdentityInfo.generator(), jsonIdentityInfo.scope(), typeOracle );
Expand Down
Loading

0 comments on commit e2cfc35

Please sign in to comment.