All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jsimpledb..ReferencePath.swp Maven / Gradle / Ivy

There is a newer version: 3.6.1
Show newest version
b0VIM 7.4?zXVg?	m|archieretina.dellroad.org~archie/proj/jsimpledb/jsimpledb/jsimpledb-main/src/main/java/org/jsimpledb/ReferencePath.javautf-8
U3210#"! Utp
^_1a	!??
?(????FMad?^???????{N"???????cJ*)%?
?
?
,
	
?90-&?)?
?
?
s
P
M
F
?	[	??????=:1?????O??????qnE???i?z1??x????/,??????    final Class startType;public class ReferencePath { */ * @see JSimpleDB#parseReferencePath JSimpleDB.parseReferencePath() * * Reference paths are created via {@link JSimpleDB#parseReferencePath JSimpleDB.parseReferencePath()}. * 

* * the storage ID may be explicitly specified as a suffix, for example, {@code "name#123"}. * In cases where multiple sub-types of a common super-type type have fields with the same name but different storage IDs, *

* * {@code friendNameChanged()} necessarily has generic type {@code NamedPerson}, not {@code Person}. * {@link org.jsimpledb.change.SimpleFieldChange} parameter to the method * with a field named {@code "name"}. Note also in the example above the * still work as long as there is no ambiguity, i.e., in this example, there are no other sub-types of {@code Person} * has type {@code Person}, and {@code "name"} is a field of {@code NamedPerson}, not {@code Person}. However, this will * Here the path {@code "friends.element.name"} is technically incorrect because {@code "friends.element"} *

* } * public abstract void setName(String name); * public abstract String getName(); * @JSimpleField(storageId = 21) * * public class NamedPerson extends Person { * @JSimpleClass(storageId = 20) * * } * } * // ... do whatever * private void friendNameChanged(SimpleFieldChange<NamedPerson, String> change) { * @OnChange("friends.element.name") * * public abstract Set<Person> getFriends(); * @JSimpleSetField(storageId = 11) * * public class Person { * @JSimpleClass(storageId = 10) *
 * * In some cases, a field may not exist in a Java object type, but it does exist in a some sub-type of that type. For example: * 

* * Fields of Sub-Types *

* * named {@code "element"}, while for map fields the sub-fields are named {@code "key"} and {@code "value"}. * being traversed should appear, e.g., {@code "mymap.key.somefield"}. For set and list fields, the (only) sub-field is * When a complex field appears in a reference path, both the name of the complex field and the specific sub-field *

* * the parent of a {@code Person}. * For example, path {@code "parent.age"} starting from object type {@code Person} might refer to the age of *

* * All of the fields except the last must be reference fields. * fields and final target field in a {@link String} form consisting of field names separated by period ({@code "."}) characters. * Reference paths can be described by the combination of (a) the starting Java object type, and (b) the path of reference *

* * * instance of the target type can be reached from an instance of the starting type. *

  • An intermediate chain of zero or more {@linkplain #getReferenceFields reference fields} through which an * within that type, and
  • *
  • A final {@linkplain #getTargetType target object type} and {@linkplain #getTargetField target field} *
  • A {@linkplain #getStartType starting Java object type},
  • *
      * A Reference path consists of: *

      * * Reference paths./**import org.slf4j.LoggerFactory;import org.slf4j.Logger;import org.jsimpledb.util.CastFunction;import java.util.Map;import java.util.HashMap;import java.util.ArrayList;import java.util.ArrayDeque;import com.google.common.reflect.TypeToken;import com.google.common.collect.Iterables;import com.google.common.base.Preconditions;import com.google.common.base.Function;package org.jsimpledb; */ * Copyright (C) 2015 Archie L. Cobbs. All rights reserved./*ad?-F??????~]WVN? ? ? | 9 3 2 * ? ? ? d ]   ? ? ? ? ? 3 ? ? ^ V / ? ? ? ? ? | q "   ?2+???xD??????}oP60.-'?????>10* ???dc7} } } return jclass.type; } } } } return jclass.type; public Class apply(JClass} } }} } } return jclass.type;} } } r} } } } } } } } return jfield.typeToken; public TypeToken apply(JReferenceField } } }} } } return jfield.typeToken; } } } return} } } } } return this.path; public String toString() { @Override */ * Get the {@link String} form of the path associated with this instance. /** } return storageIds; storageIds[i] = this.referenceFieldInfos.get(i).storageId; for (int i = 0; i < storageIds.length; i++) final int[] storageIds = new int[this.referenceFieldInfos.size()]; public int[] getReferenceFields() { */ * @return zero or more reference field storage IDs * * the last field is field in some object type that refers to the {@linkplain #getTargetType target object type}. * Otherwise, the first field is a field in the {@linkplain #getStartType starting object type} and *

      * * The path may be empty, i.e., zero references are traversed in the path. *

      * * Get the storage IDs of the reference fields in this path. /** } return this.targetSuperFieldInfo != null ? this.targetSuperFieldInfo.storageId : 0; public int getTargetSuperField() { */ * @return target field's complex super-field storage ID, or zero if the target field is not a complex sub-field * * a sub-field, in the case that the target field is a sub-field of a complex field. * Get the storage ID associated with the complex field containing the {@linkplain #getTargetField target field} /** } return this.targetFieldInfo.storageId; public int getTargetField() { */ * @return the storage ID of the field at which this reference path ends * * This is just the storage ID of the last field in the path. *

      * * Get the storage ID associated with the target field in the {@linkplain #getTargetType target object type}. /** } return this.targetFieldInfo.getTypeToken(this.targetType); public TypeToken getTargetFieldType() { */ * @return the type of the field at which this reference path ends * * Get the Java type corresponding to the field at which this path ends. /** } return this.targetTypes; public Set> getTargetTypes() { */ * @return the Java type(s) at which this reference path ends * * at which this patch ends. * type exists, otherwise it will contain multiple mutually incompatible supertypes of the object types * The returned type(s) will be maximally narrow. The set will contain only one element if a unique such *

      ad? ?h@??8`I? ? | P ? ? G 9 ? ? g ? ? ? ? 8 7 ? ? @ ? ?edM"??wT???u1?xbG5??>(??&?? ?UGF] } this.log.debug("RefPath: [" + searchName + "." + subFieldName + "] new matching fields=" + matchingFields); if (this.log.isDebugEnabled()) // Logging entry.setValue(((JComplexField)entry.getValue()).getSubField(subFieldName)); for (Map.Entry, JField> entry : matchingFields.entrySet()) // Update matching fields to match sub-field } throw new IllegalArgumentException(errorPrefix + "invalid " + description + ": " + e.getMessage(), e); } catch (IllegalArgumentException e) { fieldInfo = complexFieldInfo.getSubFieldInfo(subFieldName); try { description = "sub-field `" + subFieldName + "' of complex " + description; final String subFieldName = fieldNames.removeFirst(); // Get sub-field superFieldInfo = complexFieldInfo; } break; } + "; a sub-field of must be specified"); throw new IllegalArgumentException(errorPrefix + "path may not end on complex " + description if (lastIsSubField != null && lastIsSubField) { if (fieldNames.isEmpty()) { // Last field? final JComplexFieldInfo complexFieldInfo = (JComplexFieldInfo)fieldInfo; if (fieldInfo instanceof JComplexFieldInfo) { superFieldInfo = null; // Handle complex fields this.log.debug("RefPath: updated currentType=" + currentType + " fieldType=" + fieldInfo.getTypeToken(currentType)); if (this.log.isDebugEnabled()) // Logging Iterables.transform(matchingFields.keySet(), new JClassTypeFunction())).getRawType(); currentType = Util.findLowestCommonAncestorOfClasses( // Select the most desirable candidate Iterables.transform(matchingFields.keySet(), new JClassTypeFunction())); final Set> candidateTypes = Util.findLowestCommonAncestorsOfClasses( // Get common supertype of all types containing the field fieldInfo = jdb.getJFieldInfo(fieldStorageId, JFieldInfo.class); } } + fieldName + "' in sub-types of type " + currentType); throw new IllegalArgumentException(errorPrefix + "there are multiple, non-equal fields named `" if (jfield.storageId != fieldStorageId) { for (JField jfield : matchingFields.values()) { final int fieldStorageId = matchingFields.values().iterator().next().storageId; } + " in (any sub-type of) " + currentType); + (explicitStorageId != 0 ? " with storage ID " + explicitStorageId : "") throw new IllegalArgumentException(errorPrefix + "there is no field named `" + searchName + "'" if (matchingFields.isEmpty()) { // Check matching fields and verify they all have the same storage ID this.log.debug("RefPath: ma matchingFields.put(jclass, jfield); assert !matchingField.containsKey(jclass) || jfield.equals(matchingField.get(jclass)); continue; if (explicitStorageId != 0 && jfield.storageId != explicitStorageId) continue; if (jfield == null) final JField jfield = jclass.jfieldsByName.get(searchName); for (JClass jclass : jdb.getJClasses(currentType)) {ad?????7 ?????^&? D % ?  w    ? z : ? ? ? c I H  ? ? ? x P ?????0?????uP??_UT7??UT%????p?sa&????('?sr final HashMap, JField> matchingFields = new HashMap<>(); // Find all JFields matching 'fieldName' in some JClass whose type matches 'currentType' this.log.debug("RefPath: [" + searchName + "] currentType=" + currentType + " storageId=" + explicitStorageId); if (this.log.isDebugEnabled()) // Logging searchName = fieldName; } else searchName = fieldName.substring(0, hash); } throw new IllegalArgumentException(errorPrefix + "invalid field name `" + fieldName + "'"); } catch (NumberFormatException e) { explicitStorageId = Integer.parseInt(fieldName.substring(hash + 1)); try { if (hash != -1) { final String searchName; int explicitStorageId = 0; final int hash = fieldName.indexOf('#'); // Get explicit storage ID, if any String description = "field `" + fieldName + "' in type " + currentType; final String fieldName = fieldNames.removeFirst(); while (!fieldNames.isEmpty()) { assert !fieldNames.isEmpty(); // Parse field names } + " lastIsSubField=" + lastIsSubField); this.log.debug("RefPath: START: startType=" + this.startType + " path=" + fieldNames if (this.log.isDebugEnabled()) { JComplexFieldInfo superFieldInfo = null; JFieldInfo fieldInfo = null; Class currentType = this.startType; // Initialize loop state } path = path.substring(dot + 1); fieldNames.add(path.substring(0, dot)); throw new IllegalArgumentException(errorPrefix + "contains an empty path component"); if (dot == 0) } break; fieldNames.add(path); throw new IllegalArgumentException(errorPrefix + "ends in `.'"); if (path.length() == 0) if (dot == -1) { final int dot = path.indexOf('.'); while (true) { final ArrayDeque fieldNames = new ArrayDeque<>(); // Split the path into field names this.path = path; this.startType = startType; throw new IllegalArgumentException(errorPrefix + "path is empty"); if (path.length() == 0) final String errorPrefix = "invalid path `" + path + "': "; Preconditions.checkArgument(path != null, "null path"); Preconditions.checkArgument(startType != null, "null startType"); Preconditions.checkArgument(jdb != null, "null jdb"); // Sanity check ReferencePath(JSimpleDB jdb, Class startType, String path, Boolean lastIsSubField) { */ * @throws IllegalArgumentException if {@code path} is invalid * @throws IllegalArgumentException if {@code jdb}, {@code startType}, or {@code path} is null * or null for don't care * @param lastIsSubField true if the last field can be a complex sub-field but not a complex field, false for the reverse, * @param path dot-separated path of zero or more reference fields, followed by a target field * @param startType starting Java type for the path * @param jdb {@link JSimpleDB} against which to resolve object and field names * * Constructor. /** private final Logger log = LoggerFactory.getLogger(this.getClass()); final String path; final ArrayList referenceFieldInfos = new ArrayList<>(); final JComplexFieldInfo targetSuperF final Class targetType; final Set> targetTypes;ad`x???g????~<? ? 7 6 ? ? ? ? i , ? ? ? ? 1 ' &  ? o E   ? ? e ??{utl*#?H ??????}=6+?G?x?_????d(?pi * * if the target field exists only in a sub-type. * equal the Java type of the {@linkplain #getStartType starting * * {@link * {@link Util# * {@link Util * {@link Util#findLowestCommonAncestorOfClasses Util.fi * {@link Util#findLowestCommonAn * {@l * * {@link Util#findLowestCommonAncestorOfClasses Util.findLowestCommonAncestorOfClasses()} on the resu * {@link * {@link Util#findLowestCommonAncestorOfClasses Util.findLowestCommonAn * {@link Util#findLowestCommonAncestorOfClasses Util.findLowestCommo * {@link Util#findLowestCommonAncestorOfClasses Util.findLowestCommonAncestorOfClasses()} on the result). * {@link Util#findLowestCommonAncestorOfClasses Util.fi * {@link Util#findLowestComm * {@link Util#findLowestCommonAncestorOfClasses Util.findLowestCommonAncestorOfClasses()} on the result). * To retrieve all such target types, use {@link #getTargetTypes} (this method just invokes * possible for there to be multiple candidates for "target type", none of which is a sub-type of any other. * The returned type will be as narrow as possible while still including all possibilities, but note that it's *

      * * Get the Java type of the object at which this path ends. /** } return this.startType; public Class getStartType() { */ * @return the Java type at which this reference path starts * * field exists only in a sub-type. * equal the {@linkplain #getTargetType target object type}, or possibly a super-type if the target * If there are zero {@linkplain #getReferenceFields reference fields} in this path, then this will *

      * * Get the Java type of the object at which this path starts. /** } } + " targetFieldType=" + this.getTargetFieldType() + " references=" + this.referenceFieldInfos); + " targetFieldInfo=" + this.targetFieldInfo + " targetSuperFieldInfo=" + this.targetSuperFieldInfo this.log.debug("RefPath: DONE: targetTypes=" + this.targetTypes + " targetType=" + this.targetType if (this.log.isDebugEnabled()) { // Logging this.targetSuperFieldInfo = superFieldInfo; this.targetFieldInfo = fieldInfo; this.targetType = Util.findLowestCommonAncestorOfClasses(this.targetTypes).getRawType(); this.targetTypes = Collections.unmodifiableSet(currentTypes); // Done } this.log.debug("RefPath: step through reference, new currentTypes=" + currentTypes); if (this.log.isDebugEnabled()) // Logging currentTypes.add(((JReferenceField)jfield).typeToken.getRawType(); for (JField jfield : matchingFields.values()) currentTypes.clear(); // Advance through the reference this.referenceFieldInfos.add(referenceFieldInfo); // Add reference field to the reference field list final JReferenceFieldInfo referenceFieldInfo = (JReferenceFieldInfo)fieldInfo; throw new IllegalArgumentException(errorPrefix + description + " is not a reference field"); if (!(fieldInfo instanceof JReferenceFieldInfo)) // Field is not last, so it must be a reference field } break; } + "; specify the complex field itself instead"); throw new IllegalArgumentException(errorPrefix + "path may not end on " + description if (superFieldInfo != null && Boolean.FALSE.equals(lastIsSubField)) { if (fieldNames.isEmpty()) { // Last field?ad? ? ????lfe] ?"? ? ? d * * if the target field exis * * if the target field exi * * if the target field exists only in a sub-type. * return only the Java typ * * if the target field exists only in a sub-type. * return only the Java type of the {@linkplain #getStartType starting object type}, or possibly a sub-type * If there are zero {@linkplain #getReferenceFields reference fields} in this path, then this method will *

      * * Get the possible Java types of the object at which this path ends. /** } return this.targetType; public Class getTargetType() { */ * @return the Java type at which this reference path ends *adxX1??V?>?????}E? c D ? ? ? : 9 ! ? ? Y  ? ? ? h g < ? ? ? ? o  ????O?????XJ??YON1 ??ON????j?m[  ????"!?m final HashMap, JField> matchingFields = new HashMap<>(); // Find all JFields matching 'fieldName' in some JClass whose type matches 'currentType' this.log.debug("RefPath: [" + searchName + "] currentType=" + currentType + " storageId=" + explicitStorageId); if (this.log.isDebugEnabled()) // Logging searchName = fieldName; } else searchName = fieldName.substring(0, hash); } throw new IllegalArgumentException(errorPrefix + "invalid field name `" + fieldName + "'"); } catch (NumberFormatException e) { explicitStorageId = Integer.parseInt(fieldName.substring(hash + 1)); try { if (hash != -1) { final String searchName; int explicitStorageId = 0; final int hash = fieldName.indexOf('#'); // Get explicit storage ID, if any String description = "field `" + fieldName + "' in type " + currentType; final String fieldName = fieldNames.removeFirst(); while (!fieldNames.isEmpty()) { assert !fieldNames.isEmpty(); // Parse field names } + " lastIsSubField=" + lastIsSubField); this.log.debug("RefPath: START: startType=" + this.startType + " path=" + fieldNames if (this.log.isDebugEnabled()) { JComplexFieldInfo superF c currentTypes.add(this.startType); final HashSet> currentTypes = new HashSet<>(3); // Initialize loop state } path = path.substring(dot + 1); fieldNames.add(path.substring(0, dot)); throw new IllegalArgumentException(errorPrefix + "contains an empty path component"); if (dot == 0) } break; fieldNames.add(path); throw new IllegalArgumentException(errorPrefix + "ends in `.'"); if (path.length() == 0) if (dot == -1) { final int dot = path.indexOf('.'); while (true) { final ArrayDeque fieldNames = new ArrayDeque<>(); // Split the path into field names this.path = path; this.startType = startType; throw new IllegalArgumentException(errorPrefix + "path is empty"); if (path.length() == 0) final String errorPrefix = "invalid path `" + path + "': "; Preconditions.checkArgument(path != null, "null path"); Preconditions.checkArgument(startType != null, "null startType"); Preconditions.checkArgument(jdb != null, "null jdb"); // Sanity check ReferencePath(JSimpleDB jdb, Class startType, String path, Boolean lastIsSubField) { */ * @throws IllegalArgumentException if {@code path} is invalid * @throws IllegalArgumentException if {@code jdb}, {@code startType}, or {@code path} is null * or null for don't care * @param lastIsSubField true if the last field can be a complex sub-field but not a complex field, false for the reverse, * @param path dot-separated path of zero or more reference fields, followed by a target field * @param startType starting Java type for the path * @param jdb {@link JSimpleDB} against which to resolve object and field names * * Constructor. /** private final Logger log = LoggerFactory.getLogger(this.getClass()); final String path; final ArrayList referenceFieldInfos = new ArrayList<>(); final JComplexFieldInfo targetSuperFieldInfo; final JFieldInfo targetFieldInfo;adk !??? ?????t54? ? ? f P ? ? S A  ? ? ? ? ?   ? C ? + ?? for (Class currentType : currentTypes) { for (Class currentType : currentTypes) { f for (Class currentType : currentTypes) { final HashMap, JField> matchingFields = new HashMa for (Class currentType : currentTypes) { final HashMap, JFi for (Class currentType : currentTypes) { final HashMap, JField> matchingFields = new HashMap<>(); // Find all JFields matching 'fieldName' in some JClass whose type matches some type in 'currentTypes' this.log.debug("RefPath: [" + searchName + "] currentTypes=" + currentTypes + " storageId=" + explicitStorageId); if (this.log.isDebugEnabled()) // Logging searchName = fieldName; } else searchName = fieldName.substring(0, hash); } throw new IllegalArgumentException(errorPrefix + "invalid field name `" + fieldName + "'"); } catch (NumberFormatException e) { explicitStorageId = Integer.parseInt(fieldName.substring(hash + 1)); try { if (hash != -1) { final String searchName; int explicitStorageId = 0; final int hash = fieldName.indexOf('#'); // Get explicit storage ID, if any final String fieldName = fieldNames.removeFirst(); while (!fieldNames.isEmpty()) { assert !fieldNames.isEmpty(); // Parse field names } + " lastIsSubField=" + lastIsSubField); this.log.debug("RefPath: START: startType=" + this.startType + " path=" + fieldNames if (this.log.isDebugEnabled()) { JComplexFieldInfo superFieldInfo = null; JFieldInfo fieldInfo = null;adx  ?????N?nm?  # ? ? q 5 ? ? .   ? ? ? p 3  ? ? ? ? ? ? 8 7 ??A???s9????P???fT! ??]G??E32???>#?tfe } this.log.debug("RefPath: [" + searchName + "." + subFieldName + "] new matching fields=" + matchingFields); if (this.log.isDebugEnabled()) // Logging entry.setValue(((JComplexField)entry.getValue()).getSubField(subFieldName)); for (Map.Entry, JField> entry : matchingFields.entrySet()) // Update matching fields to match sub-field } throw new IllegalArgumentException(errorPrefix + "invalid " + description + ": " + e.getMessage(), e); } catch (IllegalArgumentException e) { fieldInfo = complexFieldInfo.getSubFieldInfo(subFieldName); try { description = "sub-field `" + subFieldName + "' of complex " + description; final String subFieldName = fieldNames.removeFirst(); // Get sub-field superFieldInfo = complexFieldInfo; } break; } + "; a sub-field of must be specified"); throw new IllegalArgumentException(errorPrefix + "path may not end on complex " + description if (lastIsSubField != null && lastIsSubField) { if (fieldNames.isEmpty()) { // Last field? final JComplexFieldInfo complexFieldInfo = (JComplexFieldInfo)fieldInfo; if (fieldInfo instanceof JComplexFieldInfo) { superFieldInfo = null; // Handle complex fields this.log.debug("RefPath: updated currentType=" + currentType + " fieldType=" + fieldInfo.getTypeToken(currentType)); if (this.log.isDebugEnabled()) // Logging } } return jclass.type; public Class apply(JClass jc } } return jclass.type; public Class apply(JClass } } return jclass.type; public Class apply(JClass } } } } return jclass.type; } } retu } } currentTypes.add(jclass.type); for (JClass jclass : matchingFields.keySet()) currentTypes.clear(); // Get types containing the field fieldInfo = jdb.getJFieldInfo(fieldStorageId, JFieldInfo.class); } } + fieldName + "' in sub-types of type " + currentTypeDescription); throw new IllegalArgumentException(errorPrefix + "there are multiple, non-equal fields named `" if (jfield.storageId != fieldStorageId) { for (JField jfield : matchingFields.values()) { final int fieldStorageId = matchingFields.values().iterator().next().storageId; } + " in (any sub-type of) " + currentTypeDescription); + (explicitStorageId != 0 ? " with storage ID " + explicitStorageId : "") throw new IllegalArgumentException(errorPrefix + "there is no field named `" + searchName + "'" if (matchingFields.isEmpty()) { // Check matching fields and verify they all have the same storage ID String description = "field `" + fieldName + "' in type " + currentTypeDescription; final String currentTypeDescription = Util.findLowestCommonAncestorOfClasses(currentTypes).getRawType().toString(); this.log.debug("RefPath: matching fields: " + matchingFields); if (this.log.isDebugEnabled()) // Logging } }ad?(???l"???87? ? 2 ? ? ? ? y x W  ? ? O  ? ? ? M ? ? ? { L ???:9 } this.log.debug(" } this.log.debug("RefPath: [" + s } } th } this.log.debug("RefPath: [" + searchName + "." + subFieldName + "] new matching fields=" + matchingFields); if (this.log.isDebugEnabled()) // Logging entry.setValue(((JComplexField)entry.getValue()).getSubField(subFieldName)); for (Map.Entry, JField> entry : matchingFields.entrySet()) // Update matching fields to match sub-field } throw new IllegalArgumentException(errorPrefix + "invalid " + description + ": " + e.getMessage(), e); } catch (IllegalArgumentException e) { fieldInfo = complexFieldInfo.getSubFieldInfo(subFieldName); try { description = "sub-field `" + subFieldName + "' of complex " + description; final String subFieldName = fieldNames.removeFirst(); // Get sub-field superFieldInfo = complexFieldInfo; } break; } + "; a sub-field of must be specified"); throw new IllegalArgumentException(errorPrefix + "path may not end on complex " + description if (lastIsSubField != null && lastIsSubField) { if (fieldNames.isEmpty()) { // Last field? final JComplexFieldInfo complexFieldInfo = (JComplexFieldInfo)fieldInfo; if (fieldInfo instanceof JComplexFieldInfo) { superFieldInfo = null; // Handle complex fields } + " fieldType=" + fieldInfo.getTypeToken(currentType)); this.log.debug("RefPath: updated currentTypes=" + currentTypes if (this.log.isDebugEnabled()) { // Logging





    © 2015 - 2025 Weber Informatics LLC | Privacy Policy