Parsing the Table Name from queries in Java - java

https://github.com/FoundationDB/sql-parser
How to use this library to parse a query (can be very complex) and retrieve the list of every table in that query.
The queries can be long and complex for example :
SELECT LINK.instance_id,
LINK.fk_rte_pnt_start,
LINK.fk_rte_pnt_end,
LINK.depart_time_local_expect,
LINK.arrvl_time_local_expect,
LINK.depart_time_utc_expctd,
LINK.arrvl_time_utc_expctd,
LINK.fk_mepc_trnsprt_mode,
LINK.mepc_link_id,
LINK.rkst_carrier_cd,
LINK.water_land_mode,
LINK.fk_rkstves_part_vehicle,
LINK.rkstves_part_vehicle,
LINK.vehicle_voyg_num,
LINK.fk_route,
LINK.routng_type,
LINK.is_out_of_cntrct_scope,
STRT.point_seq,
STRT.fk_geo_site DEP_SITE_CD,
ENDP.fk_geo_site ARR_SITE_CD,
STRT.geo_site DEP_SITE_CD_X,
ENDP.geo_site ARR_SITE_CD_X
FROM (SELECT instance_id,
fk_rte_pnt_start,
fk_rte_pnt_end,
depart_time_local_expect,
arrvl_time_local_expect,
depart_time_utc_expctd,
arrvl_time_utc_expctd,
fk_mepc_trnsprt_mode,
mepc_link_id,
rkst_carrier_cd,
water_land_mode,
fk_rkstves_part_vehicle,
rkstves_part_vehicle,
vehicle_voyg_num,
fk_route,
routng_type,
is_out_of_cntrct_scope
FROM codsbrk.gcss_route_link
WHERE fk_route = ?) LINK
LEFT OUTER JOIN codsbrk.gcss_route_point STRT
ON STRT.instance_id = LINK.fk_rte_pnt_start
LEFT OUTER JOIN codsbrk.gcss_route_point ENDP
ON ENDP.instance_id = LINK.fk_rte_pnt_end
ORDER BY STRT.point_seq
WITH UR
and
SELECT MIRL.invoice_req_line_id,
MIRL.collection_office,
MIRL.prepaid_collect,
MIRL.item_code,
MIRL.line_amount_quoted,
MIRL.currency_code,
MIRL.unit_price_quoted,
MIRL.quantity,
MIRL.owner_of_income
FROM codsbrk.mlis_invoice MIR
INNER JOIN codsbrk.mlis_invoice_line MIRL
ON MIR.tpdoc_no = MIRL.tpdoc_no
AND MIR.invoice_req_id = MIRL.invoice_req_id
WHERE MIR.tpdoc_no = ?
AND MIR.invoice_status = ?
WITH UR

The solution was provided by Nathan Williams
code here : https://gist.github.com/nathanlws/f71000943777297c7cfb
can be found here !!!
http://community.foundationdb.com/questions/4418/parsing-the-table-names-from-complex-queries.html#answer-4419
Quoting Nathan Williams :
Switching to looking for FromTable will allow you to catch the remaining tables that aren't directly in the FromList (e.g. subqueries, joins).
import com.foundationdb.sql.parser.*;
import com.foundationdb.sql.StandardException;
public class TableFinder {
public static void main(String[] args) throws Exception {
SQLParser parser = new SQLParser();
for(String sql : args) {
StatementNode node = parser.parseStatement(sql);
node.accept(new FromTablePrinter());
}
}
public static class FromTablePrinter implements Visitor {
public Visitable visit(Visitable node) throws StandardException {
if(node instanceof FromTable) {
FromTable ft = (FromTable)node;
TableName name = ft.getOrigTableName();
String alias = ft.getCorrelationName();
if(name != null) {
System.out.print(name);
if(alias != null) {
System.out.print(" AS " + alias);
}
System.out.println();
} else if (alias != null) {
String type = node.getClass().getSimpleName();
System.out.println(type + " AS " + alias);
}
}
return node;
};
public boolean visitChildrenFirst(Visitable node) {
return false;
}
public boolean stopTraversal() {
return false;
}
public boolean skipChildren(Visitable node) {
return false;
}
}
}

Related

Custom HQL Function with param and single quote

I'm trying to write a custom function in hibernate to use ts_vector (postgres), my code so far:
public class PostgresSQLFTSFunction implements SQLFunction {
static final Logger LOG = LogManager.getLogger();
#Override
public boolean hasArguments() {
return true;
}
#Override
public boolean hasParenthesesIfNoArguments() {
return false;
}
#Override
public Type getReturnType(Type firstArgumentType, Mapping mapping) throws QueryException {
return new BooleanType();
}
#Override
public String render(Type firstArgumentType, List arguments, SessionFactoryImplementor factory) throws QueryException {
if (arguments == null || arguments.size() < 2) {
throw new IllegalArgumentException("The function must have at least 2 arguments");
}
String fragment, ftsConfig, field, value;
if (arguments.size() == 3) {
ftsConfig = (String) arguments.get(0);
field = (String) arguments.get(1);
value = (String) arguments.get(2);
fragment = "to_tsvector(" + ftsConfig + ", unaccent(" + field + ")) ## to_tsquery(" + ftsConfig + ", unaccent(" + value + "))";
} else {
field = (String) arguments.get(0);
value = (String) arguments.get(1);
fragment = "to_tsvector(unaccent(" + field + ")) ## " + "to_tsquery('" + value + ":*' )";
}
LOG.info(fragment);
return fragment;
}
}
My repo:
#Query(value = "from City c where fts_partial(c.name, :cityName) = true")
List<City> getPartialByName(#Param("cityName") String cityName);
And registering the function:
public class SqlFunctionsMetadataBuilderContributor implements MetadataBuilderContributor {
#Override
public void contribute(MetadataBuilder metadataBuilder) {
metadataBuilder.applySqlFunction("fts_partial", new PostgresSQLFTSFunction());
}
}
The output query generated by Hibernate is:
select city0_.id as id1_0_, city0_.created_at as created_2_0_, city0_.updated_at as updated_3_0_, city0_.version as version4_0_, city0_.lat as lat5_0_, city0_.lng as lng6_0_, city0_.name as name7_0_, city0_.state_id as state_id8_0_ from cities city0_ where to_tsvector(unaccent(city0_.name)) ## to_tsquery('?:*' )=true
The problem here is that to_tsquery('?:*' ) does not translate the question mark to the named param (cityName), because it is included in single quotes, but the single quote here is necessary, otherwise the query does not work.
For instance, the query that works is:
select city0_.id as id1_0_, city0_.created_at as created_2_0_, city0_.updated_at as updated_3_0_, city0_.version as version4_0_, city0_.lat as lat5_0_, city0_.lng as lng6_0_, city0_.name as name7_0_, city0_.state_id as state_id8_0_ from cities city0_ where to_tsvector(unaccent(city0_.name)) ## to_tsquery('vi:*')=true;
So, the cityName question mark should be translated by HQL to 'vi' in the above example.
How can I achieve that?
Thanks!

Osmosis WayNode instances always return 0 from getLatitude and getLongitude

I am trying to use openstreetmap osmosis to read a pbf file of an airport and extract features like gates and runways.
I am using code similar to: http://www.javaoptimum.com/how-to-read-osm-pbf-files-programmatically-java/
When the code encounters a Node instance, it returns reasonable values from getLatitude and getLongitude...
However when the code encounters a Way instance the coordinates appear to be zero. Here is the code that I am using:
Sink sinkImplementation = new Sink() {
public void process(EntityContainer entityContainer) {
Entity entity = entityContainer.getEntity();
entity.getTags().forEach((tag) -> {
if ("aeroway".equals(tag.getKey())) {
if (entity instanceof Node) {
if ("holding_position".equals(tag.getValue())) {
installPointHook(airportIcaoCode, entity, tag);
} else if ("gate".equals(tag.getValue())) {
installPointHook(airportIcaoCode, entity, tag);
} else {
LOGGER.info("Ignoring unrecognized tag value " + tag.getValue());
}
} else if (entity instanceof Way) {
Way way = (Way)entity;
if ("runway".equals(tag.getValue())) {
way.getWayNodes().forEach((it) -> System.out.println(it + " : " + it.getLatitude()+","+it.getLongitude()));
} else if ("taxiway".equals(tag.getValue())) {
way.getWayNodes().forEach((it) -> System.out.println(it + " : " + it.getLatitude()+","+it.getLongitude()));
} else if ("apron".equals(tag.getValue())) {
way.getWayNodes().forEach((it) -> System.out.println(it + " : " + it.getLatitude()+","+it.getLongitude()));
} else if ("hangar".equals(tag.getValue())) {
way.getWayNodes().forEach((it) -> System.out.println(it + " : " + it.getLatitude()+","+it.getLongitude()));
} else {
LOGGER.info("Ignoring unrecognized tag value " + tag.getValue());
}
} else if (entity instanceof Relation) {
LOGGER.info("Ignoring unrecognized tag value " + tag.getValue());
}
}
});
}
public void initialize(Map<String, Object> arg0) {
}
public void complete() {
}
#Override
public void close() {
}
};
Is there some other processing I need to do in order to get the coordinates for Ways?
Turns out that ways don't have coordinates themselves, instead they have lists of WayNodes that have coordinates:
public void process(EntityContainer entityContainer) {
Entity entity = entityContainer.getEntity();
entity.getTags().forEach((tag) -> {
if (tag.getKey().equals("aeroway") && tag.getValue().equals("runway")
&& entity instanceof Way) {
final List<WayNode> wayNodes = ((Way) entity).getWayNodes();
Runway runway = new Runway(entity.getId(), nodes.get(wayNodes.get(0).getNodeId()),
nodes.get(wayNodes.get(wayNodes.size() - 1).getNodeId()));
runways.add(runway);
}
});
}
You could enhance the WayNodes with coordinates using the following snippets:
private static class MySink implements Sink {
public void process(EntityContainer entityContainer) {
if (entityContainer.getEntity() instanceof Node) {
Node node = (Node) entityContainer.getEntity();
nodes.put(node.getId(), node);
}
...
}
...
}
for (int i = 0; i < way.getWayNodes().size(); i++) {
WayNode wayNode = way.getWayNodes().get(i);
Node node = sink.nodes.get(wayNode.getNodeId());
way.getWayNodes().set(i, new WayNode(wayNode.getNodeId(), node.getLatitude(), node.getLongitude()));
}

Run a Cypher query from Spring to Neo4j

I have uploaded a CSV file and already have nodes and relationship defined on Neo4j. I've tried to create a program base on an example that basically run a cypher query from Spring that would generate the output from neo4j. However, I'm encountering this error:
Exception in thread "main" java.lang.NoSuchMethodError:org.neo4j.graphdb.factory.GraphDatabaseFactory.newEmbeddedDatabase(Ljava/io/File;)Lorg/neo4j/graphdb/GraphDatabaseService;
at org.neo4j.connection.Neo4j.run(Neo4j.java:43)
at org.neo4j.connection.Neo4j.main(Neo4j.java:37)
I'm wondering what could possibly be the error?
Here is my code:
public class Neo4j{
public enum NodeType implements Label{
Issues, Cost, Reliability, Timeliness;
}
public enum RelationType implements RelationshipType{
APPLIES_TO
}
String rows = "";
String nodeResult;
String resultString;
String columnString;
private static File DB_PATH = new File("/Users/phaml1/Documents/Neo4j/default.graphdb/import/");
public static void main(String[] args){
Neo4j test = new Neo4j();
test.run();
}
void run()
{
clear();
GraphDatabaseService db = new GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);
try(Transaction tx1 = db.beginTx();
Result result = db.execute("MATCH(b:Business)-[:APPLIES_TO]->(e:Time) RETURN b,e"))
{
while(result.hasNext())
{
while ( result.hasNext() )
{
Map<String,Object> row = result.next();
for ( Entry<String,Object> column : row.entrySet() )
{
rows += column.getKey() + ": " + column.getValue() + "; ";
}
rows += "\n";
}
}
try (Transaction something = db.beginTx();
Result result1 = db.execute("MATCH(b:Business)-[:APPLIES_TO]->(e:Time) RETURN b,e"))
{
Iterator<Node> n_column = result.columnAs("n");
for(Node node: Iterators.asIterable(n_column))
{
nodeResult = node + ": " + node.getProperties("Description");
}
List<String> columns = result.columns();
columnString = columns.toString();
resultString = db.execute("MATCH(b:Business)-[:APPLIES_TO]->(e:Time) RETURN b,e").resultAsString();
}
db.shutdown();
}
}
private void clear(){
try{
deleteRecursively(DB_PATH);
}
catch(IOException e){
throw new RuntimeException(e);
}
}
}
It looks like a Neo4j version conflict.
GraphDatabaseService db = new GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);
has a String as the argument in Neo4j 2x (https://neo4j.com/api_docs/2.0.3/org/neo4j/graphdb/factory/GraphDatabaseFactory.html#newEmbeddedDatabase(java.lang.String))
but a File in Neo4j 3x (http://neo4j.com/docs/java-reference/current/javadocs/org/neo4j/graphdb/factory/GraphDatabaseFactory.html#newEmbeddedDatabase-java.io.File-)
SDN is probably pulling in Neo4j 2.3.6 as a dependency- please check your dependency tree and override the Neo4j version

Creating an Hierarchy-Object with an undefined number of childs

I am currently working on a "code parser" parsing Valve Map Format (.vmf files) into a java readable Object.
In vmf files,
there are 2 types of objects: Classes and Properties.
classes have a name and can contain other classes and properties.
properties have a name and an unlimited number of values.
Therefore I created a VMFClass Object Class and a VMFProperty Object Class.
I created a List with self-created HierarchyObjects, containing the VMFClass/VMFProperty Object, an UUID and the parentUUID.
The VMFClass Object Contains 2 Lists one with sub-VMFClasses, one with properties.
My Problem is that I have no clue on how to achieve that a Class contains all of its subclasses, since I can't tell how much subclasses the subclasses have and so on...
Here is my Code (Github):
HierachyObject:
package net.minecraft.sourcecraftreloaded.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HierarchyObject {
private static Map<Long, Long> usedUUIDs = new HashMap<>();
private long parentUUID;
private long UUID;
private Object object;
/**
*
* #param Object
* #param parent -1 is maximum level
*/
public HierarchyObject(Object object, long parent) {
this.object = object;
this.parentUUID = parent;
while (true) {
long random = (long) (Math.random() * Long.MAX_VALUE);
if (usedUUIDs.containsKey(random)) {
this.UUID = random;
usedUUIDs.put(random, parent);
break;
}
}
}
public long getUUID() {
return UUID;
}
public long getParentUUID() {
return parentUUID;
}
public static long getParentUUIDbyUUID(long UUID) {
if (usedUUIDs.containsKey(UUID)) {
return usedUUIDs.get(UUID);
}
return -1;
}
public Object getObject() {
return object;
}
public static boolean hasChild(long UUID){
if(usedUUIDs.containsValue(UUID)){
return true;
}
if(UUID == -1){
return true;
}
return false;
}
public boolean hasChild(){
return hasChild(this.UUID);
}
public static long[] getChildUUIDs(long UUID){
if(hasChild(UUID)){
List<Long> cUUIDs = new ArrayList<>();
for(int i = 0; i < usedUUIDs.size(); i++){
for (Map.Entry<Long, Long> e : usedUUIDs.entrySet()) {
if(e.getValue().longValue() == UUID){
cUUIDs.add(e.getKey());
}
}
}
return ListUtils.toPrimitivebyList(cUUIDs);
}
return null;
}
}
VMFProperty:
package net.minecraft.sourcecraftreloaded.source;
public class VMFProperty{
private String name;
private String[] values;
public VMFProperty(String name, String... values) {
this.name = name;
this.values = values;
}
public String getName() {
return name;
}
public String[] getValues() {
return values;
}
#Override
public boolean equals(Object paramObject){
if(paramObject instanceof VMFProperty){
return ((VMFProperty)paramObject).name.equals(this.name) && ((VMFProperty)paramObject).values.equals(this.values);
}
return false;
}
}
VMFClass:
package net.minecraft.sourcecraftreloaded.source;
import java.util.List;
public class VMFClass{
private List<VMFClass> classes;
private List<VMFProperty> properties;
private String name;
public VMFClass(String name, List<VMFClass> classes, List<VMFProperty> properties) {
this.name = name;
this.classes = classes;
this.properties = properties;
}
public String getName() {
return name;
}
public List<VMFClass> getClasses() {
return classes;
}
public List<VMFProperty> getProperties() {
return properties;
}
public void add(VMFClass vmfclass) {
classes.add(vmfclass);
}
public void add(VMFProperty vmfproperty) {
properties.add(vmfproperty);
}
public void remove(VMFClass vmfclass) {
classes.remove(vmfclass);
}
public void remove(VMFProperty vmfproperty) {
properties.remove(vmfproperty);
}
#Override
public boolean equals(Object paramObject){
if(paramObject instanceof VMFClass){
return ((VMFClass)paramObject).properties.equals(this.properties) && ((VMFClass)paramObject).classes.equals(this.classes) && ((VMFClass)paramObject).name.equals(this.name);
}
return false;
}
}
VMFObject (the class executing all the code):
package net.minecraft.sourcecraftreloaded.source;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.sourcecraftreloaded.utils.HierarchyObject;
public class VMFObject {
private String rawfile = "";
private List<VMFClass> toplevelclasses;
private static final String INVALID_CHARS = "\\*,;<>|?=`´#'+~^°!§$%&()[].:-_";
public VMFObject(List<VMFClass> toplevelclasses) {
this.toplevelclasses = toplevelclasses;
}
public VMFObject() {
this(new ArrayList<VMFClass>());
}
public void write(File file) {
VMFWriter.write(file, rawfile);
}
public VMFObject read(File file) throws VMFParsingException {
this.rawfile = VMFReader.read(file);
parse();
return this;
}
public List<VMFClass> getClasses() {
return toplevelclasses;
}
private void parse() throws VMFParsingException {
evaluate();
get();
}
private void evaluate() throws VMFParsingException {
char[] textchars = rawfile.toCharArray();
int[] c = new int[]{0, 0, 0};
int line = 0;
int linepos = 0;
for (int i : textchars) {
linepos++;
if (textchars[i] == '\n') {
line++;
linepos = 0;
c[3] = 0;
if (c[3] % 2 != 0) {
throw new VMFParsingException("Invalid quotes on line" + line + ":" + linepos);
}
}
if (textchars[i] == '{') {
c[1]++;
}
if (textchars[i] == '}') {
c[2]++;
}
if (textchars[i] == '"') {
c[3]++;
if (c[1] - c[2] == 0) {
}
}
if (textchars[i] == '/' && textchars[i + 1] == '/') {
while (true) {
i++;
if (textchars[i] == '\n') {
break;
}
}
}
if (textchars[i] == '/' && textchars[i + 1] == ' ') {
throw new VMFParsingException("Invalid Character '/' on line" + line + ":" + linepos);
}
if (INVALID_CHARS.indexOf(textchars[i]) != -1) {
throw new VMFParsingException("Invalid Character '" + textchars[i] + "' on line" + line + ":" + linepos);
}
}
if (c[1] != c[2]) {
throw new VMFParsingException("Unbalanced brackets in vmf File");
}
}
public void add(VMFClass vmfclass) {
toplevelclasses.add(vmfclass);
}
private void get() throws VMFParsingException {
List<HierarchyObject> content = new ArrayList<>();
long curparent = -1;
String[] text = rawfile.split("\n");
for (int i = 0; i < text.length; i++) {
String line = text[i].trim();
if (line.startsWith("//")) {
continue;
} else {
byte quotec = 0;
char[] linechar = line.toCharArray();
boolean readp = false;
List<String> reads = new ArrayList<>();
byte creads = 0;
for (int y = 0; y < linechar.length; y++) {
if (linechar[y] == '/' && linechar[y + 1] == '/') {
break;
}
if (linechar[y] == '"') {
quotec++;
if (quotec % 2 == 0) {
readp = false;
creads++;
} else {
readp = true;
}
}
if (readp) {
reads.set(creads, reads.get(creads) + linechar[y]);
}
if (linechar[y] == '{') {
HierarchyObject object = new HierarchyObject(new VMFClass(line.substring(line.substring(0, y).lastIndexOf(' '), y).trim(), null, null), curparent);
content.add(object);
curparent = object.getUUID();
}
if (linechar[y] == '}') {
curparent = HierarchyObject.getParentUUIDbyUUID(curparent);
}
}
content.add(new HierarchyObject(new VMFProperty(reads.remove(0), reads.toArray(new String[reads.size()])), curparent));
}
}
buildObject(content);
}
private void buildObject(List<HierarchyObject> content) {
long curUUID = -1;
for(int i = 0; i < HierarchyObject.getChildUUIDs(curUUID).length; i++){
HierarchyObject.getChildUUIDs(curUUID);
}
//TODO implement
}
}
the //TODO part is where the Hierachy Object should get "converted" to the actual object.
Overview
It seems to me that your class layout is overcomplicated.
Let's try to simplify it...
What you have described with the VMF model is essentially a linked-list Tree.
Here's what the model looks like:
[.vmf file] (root)
/ \
_____/ \ _____
/ \
/ \
(VMFClass) (VMFClass)
/ \ / \
/ \ / \
/ \ / \
(VMFClass) (VMFProperties) (VMFClass) (VMFProperties)
/ \
/ \
/ \
(VMFClass) (VMFProperties)
What you need:
A Parser class (in your case, you have VMFObject, but lets call this class VMFParser).
The VMFClass and VMFProperty classes which you have are fine.
What you don't need:
The HierarchyObject class. The VMFParser can be the main controller and container for the hierarchy (e.g. the linked-list Tree model).
All the UUIDs (parent, child, etc.) These are just complicated things, but I see why you have them. You don't need them to track the hierarchy - Java will do this for us!!
VMFClass
public class VMFClass
{
// name of the class
private String name;
// reference back up to the parent
private VMFClass parentClass = null;
// all direct children go here
private List<VMFClass> children = new ArrayList<VMFClass>();
// I don't think you need a list of properties here since your VMFProperty class holds onto an array of properties
private VMFProperty properties;
// set the parent of this class
public void setParent (VMFClass parent)
{
this.parentClass = parent;
}
// get the direct children
public List<VMFClass> getChildren()
{
return this.children;
}
// rest of methods...
}
VMFParser
class VMFParser
{
private String rawfile = "";
// this is really the container for everything - think of it as the file shell
private VMFClass root = new VMFClass("root", null, null);
// construct yourself with the file
public VMFParser (String fileName)
{
this.rawfile = fileName;
}
public void parse ()
{
// all the parsing code goes here
read();
evaluate();
get();
// now at this point your hierarchy is built and stored in the
// root object in this class.
// Use the traverse method to go through it
}
private void get() throws VMFParsingException
{
// keep a reference to the current VMFClass parent
// starts out as root
VMFClass currParentClass = root;
// main parse loop
for (...)
{
// if you find a class
VMFClass currClass = new VMFClass(/* params here */);
// add this class to the parent
currParentClass.add(currClass);
// set the parent of this class
currClass.setParent(currParentClass);
// if you find a property
// parse and add all the properties to the property
VMFProperty property = new VMFProperty (/* value params here */);
// attach this property to the last VMF class that got parsed
currClass.setPoperties(property);
// If you nest deeper into classes, then the parent becomes the current class
currParentClass = currClass;
// If you go back out of a class
currParentClass = currClass.getParent();
}
}
// Traverse the hierarchy
public void traverse ()
{
traverseTree(root);
}
private void traverseTree (VMFClass root)
{
System.out.println("Class Name: " + root.getName());
// print out any properties
VMFProperty prop = root.getProperty();
if (prop != null)
{
System.out.println("Property Name: " + prop.getName());
String [] props = prop.getValues();
for (String s: props)
{
System.out.println("Value: " + s);
}
}
// get all child classes
List<VMFClass> children = root.getChildren();
for (VMFClass c: children)
{
traverseTree(c);
}
}
}
Client Code
Example
public static void main(String[] args)
{
VMFParser vmfParser = null;
try
{
vmfParser = new VMFParser("myFile.vmf");
vmfParser.parse();
// access the vmfParser for the hierarchy
vmfParser.traverse();
}
catch (VMFParsingException vpe)
{
// do something here
vpe.printStackTrace();
}
finally
{
// clean up...
}
}
If you are just looking to find all sub classes of particular class or interface , this might help you,
How can I get a list of all the implementations of an interface programmatically in Java?

Hibernate gives a strange ClassCast exception (using Transformers)

This code:
#Override
public List<FactCodeDto> getAllFactsWithoutParentsAsFactDto() {
String completeQuery = FactCodeQueries.SELECT_DTO_FROM_FACT_WITH_NO_PARENTS;
Query query = createHibernateQueryForUnmappedTypeFactDto(completeQuery);
List<FactCodeDto> factDtoList = query.list(); //line 133
return factDtoList;
}
calling this method:
private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException {
return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class));
}
gives me a ClassCastException -> part of the trace:
Caused by: java.lang.ClassCastException: org.bamboomy.cjr.dto.FactCodeDto cannot be cast to java.util.Map
at org.hibernate.property.access.internal.PropertyAccessMapImpl$SetterImpl.set(PropertyAccessMapImpl.java:102)
at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple(AliasToBeanResultTransformer.java:78)
at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:75)
at org.hibernate.loader.custom.CustomLoader.getResultList(CustomLoader.java:435)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2423)
at org.hibernate.loader.Loader.list(Loader.java:2418)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:336)
at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:1898)
at org.hibernate.internal.AbstractSessionImpl.list(AbstractSessionImpl.java:318)
at org.hibernate.internal.SQLQueryImpl.list(SQLQueryImpl.java:125)
at org.bamboomy.cjr.dao.factcode.FactCodeDAOImpl.getAllFactsWithoutParentsAsFactDto(FactCodeDAOImpl.java:133)
Which is pretty strange because, indeed, if you look up the source code of Hibernate it tries to do this:
#Override
#SuppressWarnings("unchecked")
public void set(Object target, Object value, SessionFactoryImplementor factory) {
( (Map) target ).put( propertyName, value ); //line 102
}
Which doesn't make any sense...
target is of type Class and this code tries to cast it to Map,
why does it try to do that???
any pointers are more than welcome...
I'm using Hibernate 5 (and am upgrading from 3)...
edit: I also use Spring (4.2.1.RELEASE; also upgrading) which calls these methods upon deploy, any debugging pointers are most welcome as well...
edit 2: (the whole FactCodeDto class, as requested)
package org.bamboomy.cjr.dto;
import org.bamboomy.cjr.model.FactCode;
import org.bamboomy.cjr.model.FactCodeType;
import org.bamboomy.cjr.utility.FullDateUtil;
import org.bamboomy.cjr.utility.Locales;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.util.Assert;
import java.util.*;
#Getter
#Setter
#ToString
public class FactCodeDto extends TreeNodeValue {
private String cdFact;
private String cdFactSuffix;
private Boolean isSupplementCode;
private Boolean isTitleCode;
private Boolean mustBeFollowed;
private Date activeFrom;
private Date activeTo;
private Boolean isCode;
private Long idFact;
private Long idParent;
private String type;
Map<Locale, String> description = new HashMap<Locale, String>(3);
public FactCodeDto() {
}
public FactCodeDto(String prefix, String suffix) {
super();
this.cdFact = prefix;
this.cdFactSuffix = suffix;
}
public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed) {
super();
this.cdFact = cdFact;
this.cdFactSuffix = cdFactSuffix;
this.isSupplementCode = isSupplementCode;
this.mustBeFollowed = mustBeFollowed;
}
public FactCodeDto(String cdFact, String cdFactSuffix, Boolean isSupplementCode, Boolean mustBeFollowed, Long idFact, Long idParent, Boolean isCode, Boolean isTitleCode, Date from, Date to, Map<Locale, String> descriptions,String type) {
super();
this.cdFact = cdFact;
this.cdFactSuffix = cdFactSuffix;
this.isSupplementCode = isSupplementCode;
this.mustBeFollowed = mustBeFollowed;
this.idFact = idFact;
this.idParent = idParent;
this.isCode = isCode;
this.isTitleCode = isTitleCode;
this.activeFrom = from;
this.activeTo = to;
if (descriptions != null) {
this.description = descriptions;
}
this.type = type;
}
public FactCodeDto(FactCode fc) {
this(fc.getPrefix(), fc.getSuffix(), fc.isSupplementCode(), fc.isHasMandatorySupplCodes(), fc.getId(), fc.getParent(), fc.isActualCode(), fc.isTitleCode(), fc.getActiveFrom(), fc.getActiveTo(), fc.getAllDesc(),fc.getType().getCode());
}
public String formatCode() {
return FactCode.formatCode(cdFact, cdFactSuffix);
}
public boolean isActive() {
Date now = new Date(System.currentTimeMillis());
return FullDateUtil.isBetweenDates(now, this.activeFrom, this.activeTo);
}
public void setDescFr(String s) {
description.put(Locales.FRENCH, s);
}
public void setDescNl(String s) {
description.put(Locales.DUTCH, s);
}
public void setDescDe(String s) {
description.put(Locales.GERMAN, s);
}
/**
* public String toString() {
* StringBuilder sb = new StringBuilder();
* sb.append(getIdFact() + ": ")
* .append(getIdParent() + ": ")
* .append(" " + cdFact + cdFactSuffix + ": " + (isSupplementCode ? "NO Principal " : " Principal "))
* .append((mustBeFollowed ? " Must Be Followed " : "NOT Must Be Followed "));
* return sb.toString();
* }
*/
public Map<Locale, String> getDescription() {
return description;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
String fullCode = formatCode();
result = prime * result + ((fullCode == null) ? 0 : fullCode.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FactCodeDto other = (FactCodeDto) obj;
return formatCode().equals(other.formatCode());
}
#Override
public boolean isChildOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isChild = false;
if (value instanceof FactCodeDto) {
if (this.getIdParent() != null) {
isChild = this.getIdParent().equals(((FactCodeDto) value).getIdFact());
}
}
return isChild;
}
#Override
public boolean isBrotherOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isBrother = false;
if (value instanceof FactCodeDto) {
if (this.getIdParent() != null) {
isBrother = this.getIdParent().equals(((FactCodeDto) value).getIdParent());
}
}
return isBrother;
}
#Override
public boolean isParentOf(TreeNodeValue value) {
Assert.notNull(value);
boolean isParent = false;
if (value instanceof FactCodeDto) {
isParent = this.getIdFact().equals(((FactCodeDto) value).getIdParent());
}
return isParent;
}
#Override
public int compareTo(TreeNodeValue to) {
if (to instanceof FactCodeDto) {
return formatCode().compareTo(((FactCodeDto) to).formatCode());
} else return 1;
}
public String getCode() {
return formatCode();
}
}
I found that AliasToBean has changed in Hibernate 5. For me adding getter for my field fixed the problem.
This exception occurs when the setters and getters are not mapped correctly to the column names.
Make sure you have the correct getters and setters for the query(Correct names and correct datatypes).
Read more about it here:
http://javahonk.com/java-lang-classcastexception-com-wfs-otc-datamodels-imagineexpirymodel-cannot-cast-java-util-map/
I do some investigation on this question. The problem is that Hibernate converts aliases for column names to upper case — cdFact becomesCDFACT.
Read for a more deeply explanation and workaround here:
mapping Hibernate query results to custom class?
In the end it wasn't so hard to find a solution,
I just created my own (custom) ResultTransformer and specified that in the setResultTransformer method:
private Query createHibernateQueryForUnmappedTypeFactDto(String sqlQuery) throws HibernateException {
return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(new FactCodeDtoResultTransformer());
//return FactCodeQueries.addScalars(createSQLQuery(sqlQuery)).setResultTransformer(Transformers.aliasToBean(FactCodeDto.class));
}
the code of the custom result transformer:
package org.bamboomy.cjr.dao.factcode;
import org.bamboomy.cjr.dto.FactCodeDto;
import java.util.Date;
import java.util.List;
/**
* Created by a162299 on 3-11-2015.
*/
public class FactCodeDtoResultTransformer implements org.hibernate.transform.ResultTransformer {
#Override
public Object transformTuple(Object[] objects, String[] strings) {
FactCodeDto result = new FactCodeDto();
for (int i = 0; i < objects.length; i++) {
setField(result, strings[i], objects[i]);
}
return result;
}
private void setField(FactCodeDto result, String string, Object object) {
if (string.equalsIgnoreCase("cdFact")) {
result.setCdFact((String) object);
} else if (string.equalsIgnoreCase("cdFactSuffix")) {
result.setCdFactSuffix((String) object);
} else if (string.equalsIgnoreCase("isSupplementCode")) {
result.setIsSupplementCode((Boolean) object);
} else if (string.equalsIgnoreCase("isTitleCode")) {
result.setIsTitleCode((Boolean) object);
} else if (string.equalsIgnoreCase("mustBeFollowed")) {
result.setMustBeFollowed((Boolean) object);
} else if (string.equalsIgnoreCase("activeFrom")) {
result.setActiveFrom((Date) object);
} else if (string.equalsIgnoreCase("activeTo")) {
result.setActiveTo((Date) object);
} else if (string.equalsIgnoreCase("descFr")) {
result.setDescFr((String) object);
} else if (string.equalsIgnoreCase("descNl")) {
result.setDescNl((String) object);
} else if (string.equalsIgnoreCase("descDe")) {
result.setDescDe((String) object);
} else if (string.equalsIgnoreCase("type")) {
result.setType((String) object);
} else if (string.equalsIgnoreCase("idFact")) {
result.setIdFact((Long) object);
} else if (string.equalsIgnoreCase("idParent")) {
result.setIdParent((Long) object);
} else if (string.equalsIgnoreCase("isCode")) {
result.setIsCode((Boolean) object);
} else {
throw new RuntimeException("unknown field");
}
}
#Override
public List transformList(List list) {
return list;
}
}
in hibernate 3 you could set Aliasses to queries but you can't do that anymore in hibernate 5 (correct me if I'm wrong) hence the aliasToBean is something you only can use when actually using aliasses; which I didn't, hence the exception.
Im my case :
=> write sql query and try to map result to Class List
=> Use "Transformers.aliasToBean"
=> get Error "cannot be cast to java.util.Map"
Solution :
=> just put \" before and after query aliases
ex:
"select first_name as \"firstName\" from test"
The problem is that Hibernate converts aliases for column names to upper case or lower case
I solved it by defining my own custom transformer as given below -
import org.hibernate.transform.BasicTransformerAdapter;
public class FluentHibernateResultTransformer extends BasicTransformerAdapter {
private static final long serialVersionUID = 6825154815776629666L;
private final Class<?> resultClass;
private NestedSetter[] setters;
public FluentHibernateResultTransformer(Class<?> resultClass) {
this.resultClass = resultClass;
}
#Override
public Object transformTuple(Object[] tuple, String[] aliases) {
createCachedSetters(resultClass, aliases);
Object result = ClassUtils.newInstance(resultClass);
for (int i = 0; i < aliases.length; i++) {
setters[i].set(result, tuple[i]);
}
return result;
}
private void createCachedSetters(Class<?> resultClass, String[] aliases) {
if (setters == null) {
setters = createSetters(resultClass, aliases);
}
}
private static NestedSetter[] createSetters(Class<?> resultClass, String[] aliases) {
NestedSetter[] result = new NestedSetter[aliases.length];
for (int i = 0; i < aliases.length; i++) {
result[i] = NestedSetter.create(resultClass, aliases[i]);
}
return result;
}
}
And used this way inside the repository method -
#Override
public List<WalletVO> getWalletRelatedData(WalletRequest walletRequest,
Set<String> requiredVariablesSet) throws GenericBusinessException {
String query = getWalletQuery(requiredVariablesSet);
try {
if (query != null && !query.isEmpty()) {
SQLQuery sqlQuery = mEntityManager.unwrap(Session.class).createSQLQuery(query);
return sqlQuery.setResultTransformer(new FluentHibernateResultTransformer(WalletVO.class))
.list();
}
} catch (Exception ex) {
exceptionThrower.throwDatabaseException(null, false);
}
return Collections.emptyList();
}
It worked perfectly !!!
Try putting Column names and field names both in capital letters.
This exception occurs when the class that you specified in the AliasToBeanResultTransformer does not have getter for the corresponding columns. Although the exception details from the hibernate are misleading.

Categories