Spring Mongodb Query ArrayIndexOutOfBoundsException

874 views Asked by At

I have following Spring MongoDB repository class. When I am trying to access this method I am getting following exception. Could you please let me know what's wrong with this one or how to populate Table from JSON? I am using Java 8, Spring 4 and Spring-mongo 1.9. None of the parameters is null. Is is something wrong with persisting/ converting Table interface?

@Repository
public interface OrganizationAttributeMetadataRepository extends MongoRepository<OrganizationAttributeMetaData, String> {

    @Query(value="{ 'orgHierachyIdentifier' : ?0,'uniquecode': ?1}",fields="{'htmlAttributes':1}")
    public Optional<OrganizationAttributeMetaData> findByOrgHierachyIdentifierAndUniquecode(String orgHierachyIdentifier,String uniquecode);

}

Part of the Document class

public class OrganizationAttributeMetaData extends CommonDomainAttributes implements Cloneable, Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    private String attributeName;
    private int orgid;
    private String uniquecode; //3 Character unique code to uniquely identify
    Table<Integer, String, HTMLInputTag> htmlAttributes = null; //row,identifier and HTML
}


public abstract class CommonDomainAttributes {
    @Id
    protected String id;

    protected String orgHierachyIdentifier;

    @CreatedDate
    protected Date createDate;

    @LastModifiedDate
    protected Date lastModifiedDate;
    @CreatedBy
    protected String createdBy;
    @LastModifiedBy
    protected String lastModifiedBy;
}

Exeption

%PARSER_ERROR[stack]web - 2016-12-31 13:17:06,867 [localhost-startStop-1] DEBUG o.s.d.m.r.q.StringBasedMongoQuery - Created query { "orgHierachyIdentifier" : "-999" , "uniquecode" : "ORG"} for null fields.
%PARSER_ERROR[stack]web - 2016-12-31 13:17:06,868 [localhost-startStop-1] DEBUG o.s.d.m.c.MongoTemplate - find using query: { "orgHierachyIdentifier" : "-999" , "uniquecode" : "ORG"} fields: null for class: class com.debopam.amsapp.model.OrganizationAttributeMetaData in collection: OrganizationAttributeMetaData
%PARSER_ERROR[stack]web - 2016-12-31 13:17:06,868 [localhost-startStop-1] DEBUG o.s.d.m.c.MongoDbUtils - Getting Mongo Database name=[amsapp]
%PARSER_ERROR[stack]web - 2016-12-31 13:17:06,890 [localhost-startStop-1] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'delegatingApplicationListener'
%PARSER_ERROR[stack]web - 2016-12-31 13:17:06,890 [localhost-startStop-1] DEBUG o.s.d.m.c.i.MongoPersistentEntityIndexCreator - Analyzing class interface com.google.common.base.Supplier for index information.
%PARSER_ERROR[stack]web - 2016-12-31 13:17:06,904 [localhost-startStop-1] DEBUG o.s.d.m.c.i.MongoPersistentEntityIndexCreator - Analyzing class interface com.google.common.collect.Table$Cell for index information.
%PARSER_ERROR[stack]web - 2016-12-31 13:17:06,906 [localhost-startStop-1] DEBUG o.s.d.m.c.i.MongoPersistentEntityIndexCreator - Analyzing class class com.google.common.collect.HashBasedTable for index information.
%PARSER_ERROR[stack]web - 2016-12-31 13:17:06,915 [localhost-startStop-1] DEBUG o.s.d.m.c.i.MongoPersistentEntityIndexCreator - Analyzing class class com.debopam.amsapp.model.HTMLAttribute for index information.
%PARSER_ERROR[stack]web - 2016-12-31 13:17:06,916 [localhost-startStop-1] DEBUG o.s.d.m.c.i.MongoPersistentEntityIndexCreator - Analyzing class class com.debopam.amsapp.model.HTMLInputTag for index information.
    java.lang.ArrayIndexOutOfBoundsException: 1
        at org.springframework.data.util.TypeDiscoverer.createInfo(TypeDiscoverer.java:121)
        at org.springframework.data.util.ParentTypeAwareTypeInformation.createInfo(ParentTypeAwareTypeInformation.java:73)
        at org.springframework.data.util.TypeDiscoverer.specialize(TypeDiscoverer.java:513)
        at org.springframework.data.util.ParentTypeAwareTypeInformation.specialize(ParentTypeAwareTypeInformation.java:28)
        at org.springframework.data.convert.DefaultTypeMapper.readType(DefaultTypeMapper.java:159)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:202)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1197)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.access$200(MappingMongoConverter.java:79)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1145)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1108)
        at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:78)
        at org.springframework.data.mapping.model.SpELExpressionParameterValueProvider.getParameterValue(SpELExpressionParameterValueProvider.java:63)
        at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:71)
        at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:83)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:252)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:232)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1197)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.access$200(MappingMongoConverter.java:79)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1145)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getValueInternal(MappingMongoConverter.java:871)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter$1.doWithPersistentProperty(MappingMongoConverter.java:284)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter$1.doWithPersistentProperty(MappingMongoConverter.java:272)
        at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:312)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:272)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:232)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:192)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:188)
        at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:79)
        at org.springframework.data.mongodb.core.MongoTemplate$ReadDbObjectCallback.doWith(MongoTemplate.java:2295)
        at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:1949)
        at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:1767)
        at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:1750)
        at org.springframework.data.mongodb.core.MongoTemplate.find(MongoTemplate.java:624)
        at org.springframework.data.mongodb.core.MongoTemplate.findOne(MongoTemplate.java:589)
        at org.springframework.data.mongodb.repository.query.MongoQueryExecution$SingleEntityExecution.execute(MongoQueryExecution.java:166)
        at org.springframework.data.mongodb.repository.query.MongoQueryExecution$ResultProcessingExecution.execute(MongoQueryExecution.java:345)
        at org.springframework.data.mongodb.repository.query.AbstractMongoQuery.execute(AbstractMongoQuery.java:91)
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:482)
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy70.findByOrgHierachyIdentifierAndUniquecode(Unknown Source)
        at com.debopam.amsapp.service.OrganizationAttributeMetaDataService.createOrganizationAttributeMetaData(OrganizationAttributeMetaDataService.java:54)
        at com.debopam.amsapp.config.SetupDataLoader.onApplicationEvent(SetupDataLoader.java:78)
        at com.debopam.amsapp.config.SetupDataLoader.onApplicationEvent(SetupDataLoader.java:1)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:166)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138)
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:383)
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:337)
        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:882)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545)
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:444)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:326)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4725)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5189)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1404)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1394)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
1

There are 1 answers

0
Debopam On

I have written a custom converter to solve this problem. Here is the code sample

public class HTMLInputTag implements Serializable, Cloneable {

    /**
     *
     */
    public static final long serialVersionUID = 1L;

    private String label; //input label
    private String id; //input id
    private String tagName; //tag name input, select etc.
    private String type; //input type i.e. text, email,phone etc.
    private Set<HTMLAttribute> attributes; //minlength, maxlenght, readonly etc.
    private Set<HTMLInputTag> nestedTags; 
}

public class HTMLAttribute implements Serializable, Cloneable {

    /**
     *
     */
    public static final long serialVersionUID = 1L;

    @Indexed(sparse=true,background=true,name="ATT_NAME")
    private String name;
    private String value;
    private String valueRef; //If it refers to some static data

}

public class TableSeserializer implements Converter<Table, DBObject>{

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public DBObject convert(Table value) {
        DBObject dbo = new BasicDBObject();
        value.rowMap().forEach((i,map) ->{

            DBObject rowdbobject = new BasicDBObject();
            ((Map)map).forEach((k,v)->{
                Object object = ((Map)map).get(k);
                if (object instanceof HTMLInputTag) {
                    HTMLInputTag inputTag = (HTMLInputTag) object;
                    rowdbobject.put(inputTag.getId(), convertHTMLInputTag(inputTag));
                }else{
                    rowdbobject.put(object.toString(),object);
                }
            });
            dbo.put(""+i, rowdbobject);
        });
        return dbo;
    }

    private DBObject convertHTMLInputTag(HTMLInputTag inputTag){
        DBObject dbo = new BasicDBObject();
        dbo.put("class", ClassUtils.getDescriptiveType(inputTag));
        ReflectionUtils.doWithFields(HTMLInputTag.class, new FieldCallback() {

            @Override
            @SuppressWarnings("unchecked")
            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                // make the field accessible if defined private
                ReflectionUtils.makeAccessible(field);
                Object value = field.get(inputTag);
                if(null != value){
                    List<DBObject> listsOfData = new LinkedList<>();
                    if (Collection.class.isAssignableFrom(field.getType())) {
                        ((Collection)value).forEach(item -> {
                            if(item instanceof HTMLAttribute){
                                listsOfData.add(convertHTMLAttribute((HTMLAttribute)item));
                            }else if(item instanceof HTMLInputTag){
                                listsOfData.add(convertHTMLInputTag((HTMLInputTag)item));
                            }
                        });
                        dbo.put(field.getName(),listsOfData);
                    }else{
                        dbo.put(field.getName(), value);
                    }
                }

            }
        });

        return dbo;
    }

    private DBObject convertHTMLAttribute(HTMLAttribute htmlAttribute){
        DBObject attributes = new BasicDBObject();
        attributes.put("class", ClassUtils.getDescriptiveType(htmlAttribute));
        ReflectionUtils.doWithFields(HTMLAttribute.class, field -> {
            ReflectionUtils.makeAccessible(field);
            attributes.put(field.getName(), field.get(htmlAttribute));
        });

        return attributes;
    }
}


public class TableDeserializer implements Converter<DBObject, Table>{

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public Table convert(DBObject source) {
        Table table = HashBasedTable.<Integer, String, HTMLInputTag>create();
        Map m = source.toMap();

        m.forEach((k,v) -> {
            Map temp = (Map) v;
            temp.forEach((s,t) -> {
                Map inputTagMap =  ((DBObject)t).toMap();
                final String className = (String)inputTagMap.get("class");
                HTMLInputTag inputTagOriginal = null;

                try {
                    inputTagOriginal = (HTMLInputTag) Class.forName(className).newInstance();
                } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
                    e.printStackTrace();
                    inputTagOriginal = new HTMLInputTag();
                }
                final HTMLInputTag inputTag = inputTagOriginal.clone();
                inputTagMap.keySet().forEach(fieldname -> {

                    Field field = null;
                    if(className.equals(HTMLJustTag.class.getName()))   {
                        field = ReflectionUtils.findField(HTMLJustTag.class, (String) fieldname);
                    }else{
                        field = ReflectionUtils.findField(HTMLInputTag.class, (String) fieldname);
                    }

                    if(null != field){
                        if(!ReflectionUtils.isPublicStaticFinal(field)){
                            ReflectionUtils.makeAccessible(field);
                            if (Collection.class.isAssignableFrom(field.getType())) {
                                Type cls = null;
                                Class rawTypeClass = null;
                                Type type = field.getGenericType();
                                if (type instanceof ParameterizedType) {
                                    ParameterizedType pType = (ParameterizedType)type;
                                    rawTypeClass = pType.getRawType().getClass();
                                    cls = pType.getActualTypeArguments()[0];

                                } else {
                                    cls = field.getType();
                                }


                                final Set collectionData = new LinkedHashSet<>();

                                Object value = inputTagMap.get(fieldname);
                                if(value instanceof BasicDBList){
                                    BasicDBList values = (BasicDBList)value;

                                    values.forEach(e -> {
                                        if(e instanceof BasicDBObject){
                                            String nestedClassName = ((BasicDBObject)e).getString("class");
                                            Object ncls = (((BasicDBObject)e).toMap()).get("class");
                                            try {
                                                if(nestedClassName.equals(HTMLJustTag.class.getName())) {
                                                    collectionData.add(objectMapper.readValue(e.toString(), new TypeReference<HTMLJustTag>() { }));
                                                }else if(nestedClassName.equals(HTMLAttribute.class.getName())){
                                                    collectionData.add(objectMapper.readValue(e.toString(), new TypeReference<HTMLAttribute>() { }));
                                                }else{
                                                    collectionData.add(objectMapper.readValue(e.toString(), new TypeReference<HTMLInputTag>() { }));
                                                }
                                            } catch (IOException e1) {
                                                e1.printStackTrace();
                                            }
                                        }
                                    });
                                }else{
                                    ReflectionUtils.setField(field, inputTag, inputTagMap.get(fieldname));
                                }

                                ReflectionUtils.setField(field, inputTag, collectionData);
                            }else{
                                ReflectionUtils.setField(field, inputTag, inputTagMap.get(fieldname));
                            }
                        }
                    }
                });

                if(k instanceof String){
                    table.put(Integer.parseInt((String)k), s, inputTag);
                }else{
                    table.put(k, s, inputTag);
                }

            });
        });

        return table;
    }

    /**
     * @return the objectMapper
     */
    public ObjectMapper getObjectMapper() {
        if(null == objectMapper){
            objectMapper = new ObjectMapper();
            objectMapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            //objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
            //objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
            //objectMapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
        }
        return objectMapper;
    }

}