Why a Integer Set container fill with String element - java

I have a Set, it's generic type is Set. I get it from this code
Set<Integer> completeOrgTree = codeSetOfStores.stream().flatMap(item -> organizationDao.getUpstreamOrgByCode(item).stream()).collect(toSet());
the organizationDao.getUpstreamOrgByCode method is simple:
public Set<Integer> getUpstreamOrgByCode(String code){
return organizationMapper.getUpstreamOrgByCode(code);
}
codeSetOfStores is a normal Set,i get it from
Set<String> codeSetOfStores = organizationDao.listOrganizations(OrganizationQuery.getInstance().storeIdList(new ArrayList<>(searchBean.getStoreIdSet())).fields("code").turnOffPage())
.stream().map(OrganizationEntity::getCode).collect(toSet());
//对于业务组织,获取关联该批分店的组织
Set<String> codeSetOfAssociatedStore = orgStoreAssociatedDao.listOrgStoreAssociated(OrgStoreAssociatedQuery.getInstance().turnOffPage().withStoreIdSet(searchBean.getStoreIdSet()).withFields("orgCode"))
.stream().map(OrgStoreAssociatedEntity::getOrgCode).collect(toSet());
//集合业务组织和非业务组织,查询该批组织及其上级
codeSetOfStores.addAll(codeSetOfAssociatedStore);
I have described the background of completeOrgTree above.
My problem is that when want to operate the completeOrgTree, I found that this container filled with String !!!
So every operation about this container will cause a ClassCastException,even what i do just print it
completeOrgTree.stream().forEach(item -> System.out.println(item));
My JDK version is 1.8.0_131.
========================================================================
i found the answer.
what make this happen is the mybatis.
in the xml file , i have this methd
<select id="getUpstreamOrgByCode" resultType="String">
SELECT
id,
`CODE`
FROM
t_org_architecture
WHERE
LEFT (#{code}, LENGTH(`CODE`)) = `CODE`;
</select>
the resultType of this select is String.
int the java file , i have this corresponding method:
Set<Integer> getUpstreamOrgByCode(String code);
so,the mybatis put the string value into the set in spite of the type of this set is integer!!!
i guess mybatis do this by java reflection

You are a victim of non-reified generics. At runtime, it is perfectly possible to put any object into a collection, regardless of its declared generic type. Generic types are not enforced at runtime.
Here is an example where I add 3 different types to a List<Integer>, which will also produce a class cast exception when you try to iterate over it.
List<Integer> intList = new ArrayList<>();
List anyList = intList;
anyList.add(1);
anyList.add(new Object());
anyList.add("test");
intList.stream().forEach(item -> System.out.println(item));
So I suppose whoever is responsible for populating the set has screwed up somewhere. You should ideally fix it at the source.
If that's not possible then cast it to a Set<Object> (since we know that that's really what it is, for whatever reason).
List<Object> objList = (List<Object>) (List) intList;
objList.stream().forEach(item -> System.out.println(item));
If you want to do anything more complex than printing each item, you may need to check the type (instanceof) and then add some conditional logic for Strings and Integers.

i found the answer.
what make this happen is the mybatis.
in the xml file , i have this methd
<select id="getUpstreamOrgByCode" resultType="String">
SELECT
id,
`CODE`
FROM
t_org_architecture
WHERE
LEFT (#{code}, LENGTH(`CODE`)) = `CODE`;
</select>
the resultType of this select is String.
int the java file , i have this corresponding method:
Set<Integer> getUpstreamOrgByCode(String code);
so,the mybatis put the string value into the set in spite of the type of this set is integer!!!
i guess mybatis do this by java reflection

Related

How to use DSL.coalesce with lists of fields?

Using Jooq, I am trying to fetch from a table by id first, if no matches found, then fetch by handle again.
And I want all fields of the returned rows, not just one.
Field<?> firstMatch = DSL.select(Tables.MY_TABLE.fields())
.from(Tables.MY_TABLE.fields())
.where(Tables.MY_TABLE.ID.eq(id))
.asfield(); // This is wrong, because it supports only one field, but above we selected Tables.MY_TABLE.fields(), which is plural.
Field<?> secondMatch = DSL.select(Tables.MY_TABLE.fields())
.from(Tables.MY_TABLE.fields())
.where(Tables.MY_TABLE.HANDLE.eq(handle))
.asfield(); // Same as above.
dslContext.select(DSL.coalesce(firstMatch, secondMatch))
.fetchInto(MyClass.class);
Due to the mistake mentioned above in the code, the following error occurs:
Can only use single-column ResultProviderQuery as a field
I am wondering how to make firstMatch and secondMatch two lists of fields, instead of two fields?
I tried
Field<?>[] secondMatch = DSL.select(Tables.MY_TABLE.fields())
.from(Tables.MY_TABLE.fields())
.where(Tables.MY_TABLE.HANDLE.eq(handle))
.fields();
but the following error occurred in the line containing DSL.coalesce
Type interface org.jooq.Field is not supported in dialect DEFAULT
Thanks in advance!
This sounds much more like something you'd do with a simple OR?
dslContext.selectFrom(MY_TABLE)
.where(MY_TABLE.ID.eq(id))
// The ne(id) part might not be required...
.or(MY_TABLE.ID.ne(id).and(MY_TABLE.HANDLE.eq(handle))
.fetchInto(MyClass.class);
If the two result sets should be completely exclusive, then you can do this:
dslContext.selectFrom(MY_TABLE)
.where(MY_TABLE.ID.eq(id))
.or(MY_TABLE.HANDLE.eq(handle).and(notExists(
selectFrom(MY_TABLE).where(MY_TABLE.ID.eq(id))
)))
.fetchInto(MyClass.class);
If on your database product, a query using OR doesn't perform well, you can write an equivalent query with UNION ALL, which might perform better.

how to get value from entity with have in iterable

I have code like this for getting all data from my DB
Iterable<ProductParameter> result = service.getAllProductParameter();
I need to get value from one of productParameter Entity, how to get them? if I use iterable to get all data in my DB`
I have tried using this code
String uuid = result.getProductParameterId; but this got error
You should explain more details. But
Iterable<ProductParameter> result = service.getAllProductParameter();
return a list of object so you need to filter or loop to get what you need.For example:
result.forEach(x -> {System.out.println(x.getProductParameterId());});

Exception when geting distinct values of a field from Mongo collection using mongo Java Driver 3.0

I'm getting distinct values of field from mongodb.
When i run the following query in the commandline, it works good.
db.celldata.distinct("tenentId")
I'm using Mongo java 3.0 driver, to retrieve the distinct values using the following query
MongoCursor<String> iterator = coll.distinct("tenantId", String.class).iterator();
When i run the query i get the following exception
org.bson.BsonInvalidOperationException: readString can only be called when CurrentBSONType is STRING, not when CurrentBSONType is NULL.
Well, the root cause of the error here is because you have a String type as expected output and one of the distinct values is actually null. The way I see it you have two ways of working with this.
Also noting that an "iterator" is overkill for a "distinct" list generally speaking, so just go straight to ArrayList.
Either .filter() out the unwanted null values:
ArrayList<String> distinct = coll.distinct("tenantId", String.class)
.filter(new Document("tenantId",new Document("$ne",null)))
.into(new ArrayList<String>());
System.out.println(distinct);
Or accept the results as BsonValue and handle those:
ArrayList<BsonValue> distinct = coll.distinct("tenantId", BsonValue.class)
.into(new ArrayList<BsonValue>());
System.out.println(distinct);
But in the latter case, you still need to handle the types returned. There are methods on BsonValue to allow you to code for this, but it is also a fair bit of overkill for just getting a list of distinct values.
Therefore as a "third" option, I would go for something with an "un-typed" response. The .aggregate() method works will here, but it will be BSON documents in the response, it is still up to you to transfer to a plain ArrayList of different types:
ArrayList<Object> objects = new ArrayList<Object>();
MongoCursor<Document> iterator = coll.aggregate(Arrays.asList(
new Document("$group",
new Document("_id", "$tenantId")
)
)).iterator();
while (iterator.hasNext()) {
objects.add(iterator.next().get("_id"));
}
System.out.println(objects);

Hibernate Restrictions.in() only accepts propertyName as String

I have a List of ids:
List<Object> ids;
I need to use this in a criteria query to get all rows with an id that ids contains.
What I have now and works:
if (ids.size() > 0) {
for (Object id : ids) {
preparedResults.add((T)sessionMngr.getSession().
createCriteria(rowType).add(Restrictions.idEq(id))
.uniqueResult());
}
}
So I fetch them one by one, which isn't optimal, but I first tried something like following to get them in one query, but don't know what to put at the ???:
preparedResults.addAll(sessionMngr.getSession().
createCriteria(rowType).
add(Restrictions.in(???, ids)).list());
The first argument of Restrictions.in() is of type String. I can't put a hard coded "id" there as I don't know what the propertyname is.
So I don't know how to get the id property as a String there.
I saw Projections.id(), but I am not sure if I can use this to get it as a String.
With this solution you can retrieve the name of the id field of your entity. If you use annotations you can have it even shorter as described here. If you don´t use composite primary keys you could also use
ClassMetadata classMetadata = getSessionFactory().getClassMetadata(myClass);
string identifierPropertyName = classMetadata.getIdentifierPropertyName();
Source of this snippet: here

Can I get the string from preparedStatem.setString()?

I have a problem - I create my SQL queries dynamically and basing on user input options. So the user has 5 parameters (actually it's more) and he can choose to use some of them (all if he wants) or none and specify their value in the query. So I construct my query String (basic the WHERE conditions) by checking if a parameter was selected and if a value was provided. However now there is the problem of special characters like '. I could try to use replaceAll("'", "\\") but this is quite dull and I know that preparedStatement.setString() does the job better. However for me I would need than to check again if the parameter was provided and if the previous one were also (to specify the poison of ? and connect it to the right parameter). This causes a lot of combinations and does not look elegant.
So my question is - can I somehow receive the string preparedStatement.setString() produces? Or is there a similar function that would do the same job and give me the String so I can put it in the query manually.
Maybe the intro was too long but someone might have a better idea and I wanted to explain why I need it.
What you can do is construct the basic, unparameterized SQL query based on whether the parameters were specified, and then use the prepared statement to fill in the parameters.
It could look something like this (rough sketch):
Map<String, Object> parameterValues = /*from user*/;
List<String> parameterNames = Arrays.asList("field1", "field2", "field3");
List<Object> valueList = new ArrayList<Object>();
StringBuilder statementBuilder = new StringBuilder("select * from table where ");
for ( String parameterName : parameterNames ) {
if ( parameterValues.containsKey(parameterName) ) {
statementBuilder.append(parameterName + " = ? AND");
valueList.add(parameterValues.get(parameterName));
}
}
PreparedStatement st = conn.prepareStatement(statementBuilder.toString(),
valueList);
//set each parameter here.
It's only hard the first time; then you can make it generic. That said there are probably query builders that abstract all of this away for you. I use QueryDSL but that does not have bindings for pure JDBC but rather JPA and JDO, etc.
On another forum I was given a different, simpler and cleaner approach that work perfectly.
Here are some links for others with the same problem:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1669972300346534908
http://www.akadia.com/services/dyn_modify_where_clause.html

Categories