blob: bd9244cc23c54cc4b6c11713c1afce8dde6ce2c2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
* <p>
* Contributors:
* Dmitry Kornilov - initial implementation
******************************************************************************/
package org.eclipse.persistence.json.bind.model;
import org.eclipse.persistence.json.bind.internal.naming.CaseInsensitiveStrategy;
import javax.json.bind.config.PropertyNamingStrategy;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* A model for Java class.
*
* @author Dmitry Kornilov
*/
public class ClassModel {
private final Class<?> clazz;
private final ClassCustomization classCustomization;
private final ClassModel parentClassModel;
/**
* A map of all class properties, including properties from superclasses. Used to access by name.
*/
private Map<String, PropertyModel> properties;
/**
* Sorted properties according to sorting strategy. Used for serialization property ordering.
*/
private PropertyModel[] sortedProperties;
private final PropertyNamingStrategy propertyNamingStrategy;
/**
* Gets a property model by default (non customized) name
* @param name a name as parsed from field / getter / setter without annotation customizing
* @return property model
*/
public PropertyModel getPropertyModel(String name) {
return properties.get(name);
}
/**
* Create instance of class model.
* @param clazz class to model onto
* @param customization customization of the class parsed from annotations
* @param parentClassModel class model of parent class
* @param propertyNamingStrategy property naming strategy
*/
public ClassModel(Class<?> clazz, ClassCustomization customization, ClassModel parentClassModel, PropertyNamingStrategy propertyNamingStrategy) {
this.clazz = clazz;
this.classCustomization = customization;
this.parentClassModel = parentClassModel;
this.propertyNamingStrategy = propertyNamingStrategy;
}
/**
* Search for field in this class model and superclasses of its class.
* @param jsonReadName name as it appears in JSON during reading.
* @return PropertyModel if found.
*/
public PropertyModel findPropertyModelByJsonReadName(String jsonReadName) {
Objects.requireNonNull(jsonReadName);
return searchProperty(this, jsonReadName);
}
private PropertyModel searchProperty(ClassModel classModel, String jsonReadName) {
//Standard javabean properties without overridden name (most of the cases)
final PropertyModel result = classModel.getPropertyModel(jsonReadName);
if (result != null && result.getPropertyName().equals(result.getCustomization().getJsonReadName())) {
return result;
}
//Search for overridden name on setter with @JsonbProperty annotation
for (PropertyModel propertyModel : properties.values()) {
if (equalsReadName(jsonReadName, propertyModel)) {
return propertyModel;
}
}
//property not found
return null;
}
/**
* Check if name is equal according to property strategy. In case of {@link CaseInsensitiveStrategy} ignore case.
* User can provide own strategy implementation, cast to custom interface is not an option.
*/
private boolean equalsReadName(String jsonName, PropertyModel propertyModel) {
final String propertyReadName = propertyModel.getReadName();
if (propertyNamingStrategy instanceof CaseInsensitiveStrategy) {
return jsonName.equalsIgnoreCase(propertyReadName);
}
return jsonName.equalsIgnoreCase(propertyReadName);
}
public ClassCustomization getCustomization() {
return classCustomization;
}
public Class<?> getType() {
return clazz;
}
/**
* Introspected customization for a class.
* @return immutable class customization.
*/
public ClassCustomization getClassCustomization() {
return classCustomization;
}
/**
* Class model of parent class if present.
* @return class model of a parent
*/
public ClassModel getParentClassModel() {
return parentClassModel;
}
/**
* Get sorted class properties copy, combination of field and its getter / setter, javabeans alike.
* @return sorted class properties.
*/
public PropertyModel[] getSortedProperties() {
return sortedProperties;
}
public void setProperties(List<PropertyModel> parsedProperties) {
sortedProperties = parsedProperties.toArray(new PropertyModel[]{});
this.properties = parsedProperties.stream().collect(Collectors.toMap(PropertyModel::getPropertyName, (mod) -> mod));
}
/**
* Get class properties copy, combination of field and its getter / setter, javabeans alike.
* @return class properties.
*/
public Map<String, PropertyModel> getProperties() {
return Collections.unmodifiableMap(properties);
}
}