/* * Copyright 2017 requery.io * * 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 io.requery.jackson; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.ObjectIdGenerators; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.databind.AnnotationIntrospector; import com.fasterxml.jackson.databind.PropertyName; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.introspect.AnnotatedClass; import com.fasterxml.jackson.databind.introspect.AnnotatedMember; import com.fasterxml.jackson.databind.introspect.ObjectIdInfo; import io.requery.Column; import io.requery.Table; import io.requery.Transient; import io.requery.View; import io.requery.meta.Attribute; import io.requery.meta.EntityModel; import io.requery.meta.Type; import io.requery.proxy.EntityProxy; import io.requery.proxy.PropertyState; import java.lang.reflect.Field; /** * Implementation of {@link AnnotationIntrospector} that creates Object id type and reference * information for entity types annotated with requery annotations. * * @author Nikhil Purushe */ class EntityAnnotationIntrospector extends AnnotationIntrospector { private final EntityModel model; private final Version version; private boolean useTableNames; EntityAnnotationIntrospector(EntityModel model, Version version) { this.model = model; this.version = version; this.useTableNames = false; } @Override public Version version() { return version; } @Override public ObjectIdInfo findObjectIdInfo(Annotated annotated) { Class<?> rawClass = annotated.getType().getRawClass(); for (Type<?> type : model.getTypes()) { if (type.getClassType() == rawClass && type.getSingleKeyAttribute() != null) { Attribute<?, ?> attribute = type.getSingleKeyAttribute(); String name = removePrefix(attribute.getPropertyName()); if (useTableNames) { name = attribute.getName(); } // if the name is overridden use that Class<?> superClass = rawClass.getSuperclass(); while (superClass != Object.class && superClass != null) { try { Field field = superClass.getDeclaredField(attribute.getPropertyName()); JsonProperty jsonProperty = field.getAnnotation(JsonProperty.class); if (jsonProperty != null) { name = jsonProperty.value(); break; } } catch (NoSuchFieldException ignored) { } superClass = superClass.getSuperclass(); } return new ObjectIdInfo(new PropertyName(name), rawClass, ObjectIdGenerators.PropertyGenerator.class, EntityStoreResolver.class); } } return super.findObjectIdInfo(annotated); } private String removePrefix(String name) { String[] prefixes = { "get", "is" }; for (String prefix : prefixes) { if (name.startsWith(prefix) && name.length() > prefix.length()) { StringBuilder sb = new StringBuilder(name.substring(prefix.length())); sb.setCharAt(0, Character.toLowerCase(sb.charAt(0))); return sb.toString(); } } return name; } @Override public PropertyName findNameForDeserialization(Annotated annotated) { if (useTableNames) { return getMappedName(annotated); } else { return super.findNameForDeserialization(annotated); } } @Override public PropertyName findNameForSerialization(Annotated annotated) { if (useTableNames) { return getMappedName(annotated); } else { return super.findNameForSerialization(annotated); } } private PropertyName getMappedName(Annotated annotated) { if (annotated.hasAnnotation(Table.class)) { Table table = annotated.getAnnotation(Table.class); return new PropertyName(table.name()); } if (annotated.hasAnnotation(View.class)) { View view = annotated.getAnnotation(View.class); return new PropertyName(view.name()); } else if (annotated.hasAnnotation(Column.class)) { Column column = annotated.getAnnotation(Column.class); return new PropertyName(column.name()); } else { return null; } } @Override public boolean hasIgnoreMarker(AnnotatedMember member) { return member.hasAnnotation(Transient.class); } @Override public Boolean isIgnorableType(AnnotatedClass annotatedClass) { return PropertyState.class.isAssignableFrom(annotatedClass.getAnnotated()) || EntityProxy.class.isAssignableFrom(annotatedClass.getAnnotated()); } }