Java tutorial
/* * Copyright The Sett Ltd, 2005 to 2014. * * 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.thesett.catalogue.impl.standalone; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.criterion.Conjunction; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Expression; import org.hibernate.criterion.ProjectionList; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Property; import org.hibernate.criterion.Restrictions; import org.hibernate.transform.ResultTransformer; import com.thesett.aima.attribute.impl.HierarchyAttribute; import com.thesett.aima.attribute.impl.HierarchyAttributeFactory; import com.thesett.aima.attribute.impl.HierarchyType; import com.thesett.aima.state.Attribute; import com.thesett.aima.state.ComponentType; import com.thesett.aima.state.Type; import com.thesett.catalogue.config.CatalogueConfigBean; import com.thesett.catalogue.config.CatalogueConfigBeanImpl; import com.thesett.catalogue.core.CatalogueManipulatorBase; import com.thesett.catalogue.hibernate.HibernateUtil; import com.thesett.catalogue.model.Catalogue; import com.thesett.catalogue.model.CatalogueManagerService; import com.thesett.catalogue.model.ComponentInstance; import com.thesett.catalogue.model.EntityInstance; import com.thesett.catalogue.model.EntityType; import com.thesett.catalogue.model.ExternalId; import com.thesett.catalogue.model.ExternallyIdentified; import com.thesett.catalogue.model.HierarchyInstance; import com.thesett.catalogue.model.InternalId; import com.thesett.catalogue.model.PagingResult; import com.thesett.catalogue.model.ViewInstance; import com.thesett.catalogue.model.ViewType; import com.thesett.catalogue.model.base.EntityViewInstanceBase; import com.thesett.catalogue.model.impl.InternalIdImpl; import com.thesett.common.config.ConfigBeanContext; import com.thesett.common.config.ConfigException; import com.thesett.common.config.Configurator; import com.thesett.common.util.ReflectionUtils; import com.thesett.common.util.StringUtils; import com.thesett.index.Index; import com.thesett.index.IndexUnknownKeyException; /** * CatalogueManagerServiceImpl provides a standalone implementation of the {@link CatalogueManagerService} that does not * run under an application server and handles its own transactions. * * <pre><p/><table id="crc"><caption>CRC Card</caption> * <tr><th> Responsibilities <th> Collaborations * <tr><td> Perform CRUD operations on dimension elements. * <tr><td> Perform catalogue queries by hierarchical attributes. * <tr><td> Perform free text catalogue searches. * <tr><td> Perform element searches by name. * <tr><td> Generate long-lived external ids. * </table></pre> * * @author Rupert Smith * @todo Remove the hard coding of the results list block size. Make it a configurable property. */ public class CatalogueManagerServiceImpl extends CatalogueManipulatorBase implements CatalogueManagerService { /** Used for logging. */ private static final Logger log = Logger.getLogger(CatalogueManagerServiceImpl.class); /** Temporary hard coding of the block size for query result lists. */ protected static final int BLOCK_SIZE = 20; /** Creates a standalone instance of the {@link CatalogueManagerService}. */ public CatalogueManagerServiceImpl() { // Get the configurator and extract the required catalogue config bean from it. ConfigBeanContext configBeanContext = Configurator.lookupConfigurator(); // Extract and keep the catalogue from the catalogue config bean. try { CatalogueConfigBean catalogueBean = (CatalogueConfigBean) configBeanContext .getConfiguredBean(CatalogueConfigBeanImpl.class.getName()); setCatalogue(catalogueBean.getCatalogue()); } catch (ConfigException e) { throw new IllegalStateException(e); } } /** {@inheritDoc} */ public void createHierarchyInstance(HierarchyInstance hierarchy) { log.debug("public void createHierarchyInstance(State hierarchy): called"); log.debug("hierarchy = " + hierarchy); Session session = HibernateUtil.getCurrentSession(); HibernateUtil.beginTransaction(); session.save(hierarchy); } /** {@inheritDoc} */ public void deleteHierarchyInstance(HierarchyType type, InternalId id) { log.debug( "public void deleteHierarchyInstance(HierarchyAttribute.HierarchyType type, InternalId id): called"); Session session = HibernateUtil.getCurrentSession(); HibernateUtil.beginTransaction(); // Cast the id to expose its known implementation type. InternalIdImpl idImpl = (InternalIdImpl) id; // Look the hierarchy instance up in the normalized online database by its id. String hierarchyClassName = StringUtils.toCamelCaseUpper(type.getName()); Class hierarchyClass = ReflectionUtils.forName(getCatalogue().getModelPackage() + "." + hierarchyClassName); HierarchyInstance result = (HierarchyInstance) session.get(hierarchyClass, idImpl.getValue()); log.debug("hierarchy instance to delete = " + result); session.delete(result); } /** {@inheritDoc} */ public List<HierarchyInstance> retreiveHierarchyInstances(HierarchyInstance hierarchy, boolean queryChildren) { List<HierarchyInstance> result = new LinkedList<HierarchyInstance>(); // Get name of hierarchy type to query. String hierarchyTypeName = hierarchy.getHierarchyType().getName(); // Work out the database table name for the hierarchy. String databaseEntityName = getCatalogue().getModelPackage() + "." + StringUtils.toCamelCaseUpper(hierarchyTypeName); Session session = HibernateUtil.getCurrentSession(); HibernateUtil.beginTransaction(); Criteria selectCriteria = session.createCriteria(databaseEntityName); // Build up the query criteria. Conjunction subCriterion = Restrictions.conjunction(); // Get the level names in the hierarchy. HierarchyAttribute hierarchyAttribute = hierarchy.getHierarchy(); HierarchyAttributeFactory factory = hierarchyAttribute.getFactory(); String[] levelNames = factory.getLevelNames(); // Build up the property matching clause for this restriction. Levels defined in the restricting // hierarchy must be matched exactly on the joined hierarchy property. for (String level : levelNames) { String value = hierarchyAttribute.getValueAtLevel(level); // Only add restrictions for non null values specified in the grouping hierarchy. if (value != null) { subCriterion.add(Restrictions.eq(StringUtils.toCamelCase(hierarchyTypeName) + "." + level, value)); } } selectCriteria.add(subCriterion); return selectCriteria.list(); } /** {@inheritDoc} */ public void createEntityInstance(EntityInstance element) { log.debug("public void createEntityInstance(DimensionElement element): called"); log.debug("element = " + element); Session session = HibernateUtil.getCurrentSession(); HibernateUtil.beginTransaction(); // Set up its external id if it requires one. if (element.getComponentType().isExternalId()) { if (((ExternallyIdentified) element).getExternalId() == null) { // Store the dimension name as the external ids resource type. String resourceName = element.getComponentType().getName(); // Create a new external id with a null primary key as hibernate will generate that. ExternalId externalId = new ExternalId(null, resourceName); // Set up the new external if on the dimension element and save it. ((ExternallyIdentified) element).setExternalId(externalId); session.save(externalId); } } // Store the new dimension element in the normalized online database. session.save(element.getComponentType().getName() + Catalogue.ONLINE_TABLE_EXT, element); // Check if it needs indexing and index it if so. List<String> indexes = getCatalogue().getIndexesForDimension(element.getComponentType().getName()); if (indexes != null) { for (String index : indexes) { addToIndex(index, ((ExternallyIdentified) element).getExternalId(), element); } } } /** {@inheritDoc} */ public EntityInstance retrieveEntityInstance(EntityType entityType, InternalId id) { Session session = HibernateUtil.getCurrentSession(); HibernateUtil.beginTransaction(); // Cast the id to expose its known implementation type. InternalIdImpl idImpl = (InternalIdImpl) id; // Look the dimension element up in the normalized online database by its id. return (EntityInstance) session.get(entityType.getName() + Catalogue.ONLINE_TABLE_EXT, idImpl.getValue()); } /** {@inheritDoc} */ public void updateEntityInstance(EntityInstance element) { log.debug("public void updateEntityInstance(EntityInstance element): called"); log.debug("element = " + element); Session session = HibernateUtil.getCurrentSession(); HibernateUtil.beginTransaction(); // Store the new dimension element in the normalized online database. session.saveOrUpdate(element.getComponentType().getName() + Catalogue.ONLINE_TABLE_EXT, element); // Check if it needs indexing and index it if so. List<String> indexes = getCatalogue().getIndexesForDimension(element.getComponentType().getName()); if (indexes != null) { try { for (String index : indexes) { updateIndex(index, ((ExternallyIdentified) element).getExternalId(), element); } } catch (IndexUnknownKeyException e) { throw new IllegalStateException(e); } } } /** {@inheritDoc} */ public void deleteEntityInstance(EntityType dimension, InternalId id) { log.debug("public void deleteEntityInstance(EntityType dimension, InternalId id): called"); Session session = HibernateUtil.getCurrentSession(); HibernateUtil.beginTransaction(); // Cast the id to expose its known implementation type. InternalIdImpl idImpl = (InternalIdImpl) id; // Look the dimension element up in the normalized online database by its id. EntityInstance result = (EntityInstance) session.get(dimension.getName() + Catalogue.ONLINE_TABLE_EXT, idImpl.getValue()); session.delete(result); // Check if it needs indexing and index it if so. List<String> indexes = getCatalogue().getIndexesForDimension(dimension.getName()); if (indexes != null) { try { for (String index : indexes) { removeFromIndex(index, ((ExternallyIdentified) result).getExternalId()); } } catch (IndexUnknownKeyException e) { throw new IllegalStateException(e); } } } /** {@inheritDoc} */ public Map<EntityType, List<ViewInstance>> browse(Map<String, Attribute> matchings, String viewTypeName) { log.debug( "public Map<EntityType, List<ViewInstance>> browse(Map<String, Attribute> groupings, ViewType view): called"); // Ensure that a view type has been specified. if (viewTypeName == null) { throw new IllegalArgumentException("The 'view' parameter must not be null."); } HibernateUtil.beginTransaction(); ViewType viewType = getCatalogue().getViewType(viewTypeName); // Get all entities in the catalogue and then filter down to just those that match the specified set of field // names and types, and conform to the specified view type. Collection<EntityType> allEntities = getCatalogue().getAllEntityTypes(); Collection<EntityType> entitiesMatchingFields = filterEntitiesMatchingFields(allEntities, matchings); Collection<EntityType> entitiesMatchingViews = filterEntitiesMatchingViews(entitiesMatchingFields, viewType); // Run a query against each matching entity type to build up the results. Map<EntityType, List<ViewInstance>> results = new HashMap<EntityType, List<ViewInstance>>(); for (EntityType nextEntityType : entitiesMatchingViews) { List<ViewInstance> nextResult = browse(nextEntityType, matchings, viewTypeName); // Check that it actually contains some matches before adding it to the results. if (!nextResult.isEmpty()) { results.put(nextEntityType, nextResult); log.debug("Got results for dimension: " + nextEntityType + "."); } } return results; } /** {@inheritDoc} */ public List<ViewInstance> browse(EntityType entityType, Map<String, Attribute> matchings, String viewTypeName) { HibernateUtil.beginTransaction(); // Ensure that a view type has been specified. if (viewTypeName == null) { throw new IllegalArgumentException("The 'viewTypeName' parameter must not be null."); } ViewType viewType = getCatalogue().getViewType(viewTypeName); // Get the name of the entity table to fetch the matching entity from. String entityTableName = entityType.getName() + Catalogue.ONLINE_TABLE_EXT; String entityTypeName = entityType.getName(); // Check that the specified entity type contains attributes of the correct type to match the query. for (String propName : matchings.keySet()) { // Get the type name of the attribute in the parameter. Attribute attribute = matchings.get(propName); String attributeTypeName = attribute.getType().getName(); // Get the type name of the field in the entity. Type type = entityType.getPropertyType(propName); if (type != null) { String fieldTypeName = type.getName(); // Check that they are compatible. if (!attributeTypeName.equals(fieldTypeName)) { throw new IllegalArgumentException("The type of query parameter " + propName + " is " + attributeTypeName + " which is not compatibale with the field of type " + fieldTypeName + " on entity type " + entityType.getName()); } } else { throw new IllegalArgumentException("The query parameter " + propName + " does not match any field name of entity type " + entityType.getName()); } } // Get the hibernate query criterions for the requested attribute matchings. Map<String, Criterion> joins = getByAttributeCriterions(matchings); // Build a paged list to fetch the results on demand. SummaryList results = new SummaryList(0, BLOCK_SIZE, entityTableName, entityTypeName, viewTypeName, null, joins, this, isLocal()); // Ensure that the first page is pre-fetched in the list. // The use local flag is forced on for this call as obviously a local call can be made to this class at // this point in time. boolean useLocal = results.isUseLocal(); results.setUseLocal(true); results.cacheBlock(0); results.setUseLocal(useLocal); return results; } /** {@inheritDoc} */ public List<ViewInstance> freeTextSearch(String indexName, String query, ViewType view) { log.debug( "public Map<Dimension, List<DimensionElementSummary>> freeTextSearch(String indexName, String query): called"); // Get an index, or index connection for the named index. Index<ExternalId, ComponentInstance, ViewInstance> index = getIndex(indexName); // Pass the free text query to it. Map<ExternalId, ViewInstance> searchResults = index.search(query); // Return the results as a list. return new ArrayList<ViewInstance>(searchResults.values()); } /** {@inheritDoc} */ public Map<ComponentType, List<ViewInstance>> freeTextSearchByEntityType(String indexName, String query, ViewType view) { log.debug( "public Map<Dimension, List<DimensionElementSummary>> freeTextSearch(String indexName, String query): called"); // Get an index, or index connection for the named index. Index<ExternalId, ComponentInstance, ViewInstance> index = getIndex(indexName); // Pass the free text query to it. Map<ExternalId, ViewInstance> searchResults = index.search(query); // Re-organize the results by dimension. Map<ComponentType, List<ViewInstance>> results = new HashMap<ComponentType, List<ViewInstance>>(); for (ViewInstance summary : searchResults.values()) { // Get the entity type from the summary. ComponentType componentType = summary.getComponentType(); // Insert the dimension into the results if not there already. List<ViewInstance> listToAddTo = results.get(componentType); if (listToAddTo == null) { listToAddTo = new ArrayList<ViewInstance>(); results.put(componentType, listToAddTo); } // Add the result to the list for the dimension. listToAddTo.add(summary); } return results; } /** {@inheritDoc} */ public PagingResult executePagedQuery(int from, int number, String databaseEntityName, String entityTypeName, String viewTypeName, Criterion criterion, Map<String, Criterion> joins) { log.debug("public PagingResult executePagedQuery(int from = " + from + ", int number = " + number + ", String databaseEntityName = " + databaseEntityName + ", String entityTypeName = " + entityTypeName + ", String viewTypeName = " + viewTypeName + ", Criterion criterion, " + "Map<String, Criterion> joins): called"); Session session = HibernateUtil.getCurrentSession(); HibernateUtil.beginTransaction(); // Project the id and external id properties and just the remaining properties that are required to project // the results onto the specified view type. ProjectionList properties = Projections.projectionList().add(Projections.id()) .add(Property.forName("externalId")); ViewType viewType = getCatalogue().getViewType(viewTypeName); for (String fieldName : viewType.getAllPropertyTypes().keySet()) { properties.add(Property.forName(fieldName)); } // Create the selection criteria for the block. Criteria selectCriteria = session.createCriteria(databaseEntityName); if (criterion != null) { selectCriteria.add(criterion); } if (joins != null) { for (Map.Entry<String, Criterion> entry : joins.entrySet()) { String joinEntity = entry.getKey(); Criterion joinCriterion = entry.getValue(); selectCriteria.createCriteria(joinEntity).add(joinCriterion); } } selectCriteria.setProjection(properties).setFirstResult(from).setMaxResults(number) .setResultTransformer(new ViewInstanceTransformer(viewType, entityTypeName)); // Create the count criteria. Criteria countCriteria = session.createCriteria(databaseEntityName); if (criterion != null) { countCriteria.add(criterion); } if (joins != null) { for (Map.Entry<String, Criterion> entry : joins.entrySet()) { String joinEntity = entry.getKey(); Criterion joinCriterion = entry.getValue(); countCriteria.createCriteria(joinEntity).add(joinCriterion); } } countCriteria.setProjection(Projections.rowCount()); // Run a query to find out how many results there will be and update the list size. int count = (Integer) countCriteria.uniqueResult(); // Execute the query to get the block. List<ViewInstance> results = selectCriteria.list(); return new PagingResult(count, results); } /** * Looks up an external id and resolves it into the dimension element with that id. * * @param externalId The external dimension element id. * * @return A the dimension element with matching external id, or null if no match can be found. */ public EntityInstance retrieveByExternalId(String externalId) { Session session = HibernateUtil.getCurrentSession(); HibernateUtil.beginTransaction(); // Look up the external id by its string representation. ExternalId id = (ExternalId) session.get(ExternalId.class, externalId); // Check that a matching external id was found. if (id != null) { // Get the dimension that the external id's resource class matches. ComponentType dimension = getCatalogue().getComponentType(id.getResource()); // Create a query on the dimension for the matching external id. Criteria selectCriteria = session.createCriteria(dimension.getName() + Catalogue.ONLINE_TABLE_EXT) .createAlias("externalId", "e").add(Expression.eq("e.id", id.getId())); // Return the unique result or null if there are no matches. return (EntityInstance) selectCriteria.uniqueResult(); } else { return null; } } /** * Causes all indexes in the catalogue to be emptied and re-built from their dimensional data. * * <p/>A fetch size could be set on the selectCriteria to batch fetch dimensional data in chunks in the most * efficient way by experimenting with different sizes. This should already be set to an optimal value on the * underlying JDBC driver so this is not done. In any case, list is used rather than iterate as iterate would use an * N + 1 strategy. */ public void rebuildIndexes() { log.debug("public void rebuildIndexes(): called"); Session session = HibernateUtil.getCurrentSession(); HibernateUtil.beginTransaction(); rebuildIndexesInSession(session); } /** * Build a map of entity field names and criterion to apply to them in order to select entities by the specified * attributes. * * @param matchings The attributes to match. * * @return A map of entity field names and criterion to apply to them. */ protected Map<String, Criterion> getByAttributeCriterions(Map<String, Attribute> matchings) { Map<String, Criterion> criterions = new HashMap<String, Criterion>(); // Loop over all the attribute matchings to create criterions for. for (String propName : matchings.keySet()) { // Get the attribute type name of the parameter to match against. Attribute attribute = matchings.get(propName); String attributeTypeName = attribute.getType().getName(); if (attribute instanceof HierarchyAttribute) { // Create join criterions for selecting entities by hierarchies. // One join criterion, plus entity name, will be created for each property to be restricted by hierarchy. HierarchyAttribute hierarchyAttribute = (HierarchyAttribute) attribute; HierarchyAttributeFactory factory = hierarchyAttribute.getFactory(); // Get the next property to restrict by attribute value and create a criterion to restrict on that property. Conjunction subCriterion = Restrictions.conjunction(); criterions.put(propName, subCriterion); // Get the level names in the hierarchy. String[] levelNames = factory.getLevelNames(); // Build up the property matching clause for this restriction. Levels defined in the restricting // hierarchy must be matched exactly on the joined hierarchy property. for (String level : levelNames) { String value = hierarchyAttribute.getValueAtLevel(level); // Only add restrictions for non null values specified in the grouping hierarchy. if (value != null) { subCriterion.add(Restrictions.eq(attributeTypeName + "." + level, value)); } } } } return criterions; } /** * Creates the criterion for querying dimension elements by a particular name. * * @param name The name to query for. * * @return A criterion to restrict to the specified name. */ protected Criterion getByNameCriterion(String name) { // Create the criterion for selecting dimension element summaries by name. Criterion byNameCriterion = Expression.eq("name", name); return byNameCriterion; } /** * Reports whether or not this service is local. * * @return Always <tt>true</tt>. */ protected boolean isLocal() { return true; } /** * Filters a collection of entities down to those that have fields of matching name and type to a specified set of * fields. * * @param entities The set of entities to filter. * @param matchings The set of field names and types to match. * * @return A collection of entities from the original set that match the specified fields. */ private Collection<EntityType> filterEntitiesMatchingFields(Iterable<EntityType> entities, Map<String, Attribute> matchings) { log.debug( "private Collection<EntityType> filterEntitiesMatchingFields(Collection<EntityType> entities, Map<String, Attribute> matchings): called"); // Build a list of all entity types that contain the named attributes as field with matching name and type. Collection<EntityType> results = new ArrayList<EntityType>(); for (EntityType entityType : entities) { // Loop over all the properties and their attributes. An entity must match all before it is added to // the query. Start by assuming that the entity does match. boolean match = true; for (String propName : matchings.keySet()) { // Get the attribute type name of the attribute in the parameter. Attribute attribute = matchings.get(propName); String attributeTypeName = attribute.getType().getName(); // Get the attribute type name of the attribute in the entity. Type type = entityType.getPropertyType(propName); if (type != null) { String entityTypeName = type.getName(); // Check that they are compatible. if (!attributeTypeName.equals(entityTypeName)) { // The entity parameter type does not match the type of the query. match = false; break; } } else { // The entity does not have a field with name matching the attribute name in the query. match = false; break; } } // Check if the entity type matched the query and add it to the list if so. if (match) { results.add(entityType); log.debug("Matched entity type: " + entityType + "."); } } return results; } /** * Filters a collection of entities down to those that conform to a specified view type. * * @param entities The set of entities to filter. * @param view The view type to filter to. * * @return A collection of entities from the original set that conform to the specified view type. */ private Collection<EntityType> filterEntitiesMatchingViews(Iterable<EntityType> entities, ComponentType view) { log.debug( "private Collection<EntityType> filterEntitiesMatchingViews(Collection<EntityType> entities, ViewType view): called"); // Build a list of all entity types that conform to the specified view type. Collection<EntityType> results = new ArrayList<EntityType>(); for (EntityType entityType : entities) { Set<ComponentType> ancestors = entityType.getImmediateAncestors(); if (ancestors.contains(view)) { results.add(entityType); log.debug("Matched entity type: " + entityType + "."); } } return results; } /** * ViewInstanceTransformer transforms results sets containing an Object array, consisting of a long id, external id, * and the fields that make up a particular view instance into a sub-class {@link ViewInstance} implementing the * specified view type. */ public static class ViewInstanceTransformer implements ResultTransformer { /** Holds the view type to project onto. */ ViewType viewType; /** The name of the dimension that the summary belongs to. */ String entityTypeName; /** * Creates a result transformer to transform tuples from result sets into view instances. * * @param viewType The view type to project onto. * @param entityTypeName The name of the entity type that the view is of. */ public ViewInstanceTransformer(ViewType viewType, String entityTypeName) { this.viewType = viewType; this.entityTypeName = entityTypeName; } /** * Returns the input list with no transformation applied to it. * * @param collection The input list. * * @return The input list untouched. */ public List transformList(List collection) { return collection; } /** * Transforms the object tuple, { id, external id, ... } into a {@link ViewInstance} object. * * @param tuple The object tuple. * @param aliases The alias names for the fields in the tuple. Ignored. * * @return An instance of ViewInstance. */ public Object transformTuple(Object[] tuple, String[] aliases) { log.debug("public Object transformTuple(Object[] tuple, String[] aliases): called"); Class viewImplClass = viewType.getBaseClass(); log.debug("viewImplClass = " + viewImplClass); Class[] constructorArgTypes = new Class[tuple.length]; /*for (int i = 0; i < (tuple.length); i++) { Object arg = tuple[i]; log.debug("arg = " + arg); constructorArgTypes[i] = arg.getClass(); log.debug("constructorArgTypes[ " + i + "] = " + constructorArgTypes[i]); }*/ constructorArgTypes[0] = Long.class; constructorArgTypes[1] = ExternalId.class; int i = 2; for (Type argType : viewType.getAllPropertyTypes().values()) { Object arg = tuple[i]; if (null == arg) { constructorArgTypes[i] = argType.getBaseClass(); } else { constructorArgTypes[i] = arg.getClass(); } log.debug("constructorArgTypes[ " + i + "] = " + constructorArgTypes[i]); i++; } Constructor constructor = ReflectionUtils.getConstructor(viewImplClass, constructorArgTypes); EntityViewInstanceBase instance = (EntityViewInstanceBase) ReflectionUtils.newInstance(constructor, tuple); //return new EntityViewInstanceBase(entityTypeName, (Long) tuple[0], (ExternalId) tuple[1]); return instance; } } }