/** * Copyright © 2006-2016 Web Cohesion (info@webcohesion.com) * * 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.webcohesion.enunciate.modules.jackson1.model; import com.webcohesion.enunciate.facets.Facet; import com.webcohesion.enunciate.facets.HasFacets; import com.webcohesion.enunciate.javac.decorations.TypeMirrorDecorator; import com.webcohesion.enunciate.javac.decorations.element.DecoratedElement; import com.webcohesion.enunciate.javac.decorations.type.DecoratedDeclaredType; import com.webcohesion.enunciate.javac.decorations.type.DecoratedTypeMirror; import com.webcohesion.enunciate.javac.decorations.type.TypeMirrorUtils; import com.webcohesion.enunciate.metadata.ClientName; import com.webcohesion.enunciate.metadata.qname.XmlQNameEnumRef; import com.webcohesion.enunciate.modules.jackson1.EnunciateJackson1Context; import com.webcohesion.enunciate.modules.jackson1.model.adapters.Adaptable; import com.webcohesion.enunciate.modules.jackson1.model.adapters.AdapterType; import com.webcohesion.enunciate.modules.jackson1.model.types.JsonType; import com.webcohesion.enunciate.modules.jackson1.model.types.JsonTypeFactory; import com.webcohesion.enunciate.modules.jackson1.model.util.JacksonUtil; import com.webcohesion.enunciate.modules.jackson1.model.util.MapType; import com.webcohesion.enunciate.util.HasClientConvertibleType; import com.webcohesion.enunciate.util.OptionalUtils; import javax.lang.model.element.Element; import javax.lang.model.type.MirroredTypeException; import javax.lang.model.type.TypeMirror; import java.util.LinkedList; import java.util.Set; import java.util.TreeSet; /** * An accessor for a field or method value into a type. * * @author Ryan Heaton */ @SuppressWarnings ( "unchecked" ) public abstract class Accessor extends DecoratedElement<javax.lang.model.element.Element> implements Adaptable, HasFacets, HasClientConvertibleType { final TypeDefinition typeDefinition; final AdapterType adapterType; final Set<Facet> facets = new TreeSet<Facet>(); final EnunciateJackson1Context context; public Accessor(javax.lang.model.element.Element delegate, TypeDefinition typeDef, EnunciateJackson1Context context) { super(delegate, context.getContext().getProcessingEnvironment()); this.typeDefinition = typeDef; this.facets.addAll(Facet.gatherFacets(delegate, context.getContext())); this.facets.addAll(typeDef.getFacets()); this.context = context; this.adapterType = JacksonUtil.findAdapterType(this, context); } /** * The name of the accessor. * * @return The name of the accessor. */ public abstract String getName(); /** * The simple name for client-side code generation. * * @return The simple name for client-side code generation. */ public String getClientSimpleName() { String clientSimpleName = this.delegate.getSimpleName().toString(); ClientName clientName = this.delegate.getAnnotation(ClientName.class); if (clientName != null) { clientSimpleName = clientName.value(); } return clientSimpleName; } /** * The type of the accessor. * * @return The type of the accessor. */ public DecoratedTypeMirror getAccessorType() { DecoratedTypeMirror accessorType = (DecoratedTypeMirror) asType(); accessorType = OptionalUtils.stripOptional(accessorType, this.context.getContext().getProcessingEnvironment()); accessorType = this.context.resolveSyntheticType(accessorType); DecoratedDeclaredType normalizedCollection = JacksonUtil.getNormalizedCollection(accessorType, this.context.getContext().getProcessingEnvironment()); if (normalizedCollection != null) { accessorType = normalizedCollection; } else { MapType mapType = MapType.findMapType(accessorType, this.context); if (mapType != null) { accessorType = mapType; } } return accessorType; } @Override public TypeMirror getClientConvertibleType() { return getAccessorType(); } /** * The bare (i.e. unwrapped) type of the accessor. * * @return The bare type of the accessor. */ public DecoratedTypeMirror getBareAccessorType() { return isCollectionType() ? getCollectionItemType() : getAccessorType(); } /** * The base json type of the accessor. The base type is either: * <p/> * <ol> * <li>The json type of the accessor type.</li> * <li>The json type of the component type of the accessor type if the accessor type is a collection type.</li> * </ol> * * @return The base type. */ public JsonType getJsonType() { JsonType jsonType = JsonTypeFactory.findSpecifiedType(this, this.context); return (jsonType != null) ? jsonType : JsonTypeFactory.getJsonType(getAccessorType(), this.context); } /** * The type definition for this accessor. * * @return The type definition for this accessor. */ public TypeDefinition getTypeDefinition() { return typeDefinition; } /** * Get the resolved accessor type for this accessor. * * @return the resolved accessor type for this accessor. */ public TypeMirror getResolvedAccessorType() { DecoratedTypeMirror accessorType = getAccessorType(); if (isAdapted()) { accessorType = (DecoratedTypeMirror) getAdapterType().getAdaptingType(accessorType, this.context.getContext()); } return accessorType; } /** * Whether the accessor type is a collection type. * * @return Whether the accessor type is a collection type. */ public boolean isCollectionType() { DecoratedTypeMirror accessorType = getAccessorType(); if (isAdapted()) { accessorType = (DecoratedTypeMirror) getAdapterType().getAdaptingType(accessorType, this.context.getContext()); } return accessorType.isArray() || accessorType.isCollection(); } /** * If this is a collection type, return the type parameter of the collection, or null if this isn't a * parameterized collection type. * * @return the type parameter of the collection. */ public DecoratedTypeMirror getCollectionItemType() { return TypeMirrorUtils.getComponentType(getAccessorType(), this.context.getContext().getProcessingEnvironment()); } // Inherited. public boolean isAdapted() { return this.adapterType != null; } // Inherited. public AdapterType getAdapterType() { return this.adapterType; } /** * Whether this accessor is a value. * * @return Whether this accessor is a value. */ public boolean isValue() { return false; } /** * Whether this QName accessor references a QName enum type. * * @return Whether this QName accessor references a QName enum type. */ public boolean isReferencesQNameEnum() { return getAnnotation(XmlQNameEnumRef.class) != null; } /** * The enum type containing the known qnames for this qname enum accessor, or null is this accessor doesn't reference a known qname type. * * @return The enum type containing the known qnames for this qname enum accessor. */ public DecoratedTypeMirror getQNameEnumRef() { XmlQNameEnumRef enumRef = getAnnotation(XmlQNameEnumRef.class); DecoratedTypeMirror qnameEnumType = null; if (enumRef != null) { try { qnameEnumType = TypeMirrorUtils.mirrorOf(enumRef.value(), this.env); } catch (MirroredTypeException e) { qnameEnumType = (DecoratedTypeMirror) TypeMirrorDecorator.decorate(e.getTypeMirror(), this.env); } } return qnameEnumType; } /** * Set of (human-readable) locations that this type definition is referenced from. * * @return The referenced-from list. */ public LinkedList<Element> getReferencedFrom() { LinkedList<Element> stack = new LinkedList<Element>(this.typeDefinition.getReferencedFrom()); stack.add(this); return stack; } /** * The facets here applicable. * * @return The facets here applicable. */ public Set<Facet> getFacets() { return facets; } public EnunciateJackson1Context getContext() { return context; } }