Here is the stack trace when I try to execute a simple query using MyBatis:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ppcredit.gypsophila.mapper.GypsophilaVarsStatisticsMapper.selectBySql
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:225)
at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:48)
at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58)
at com.sun.proxy.$Proxy110.selectBySql(Unknown Source)
Here is a method from my class:
/**
* use the sql to query result
*
* #param sql
* #return
*/
List<LinkedHashMap<String, Object>> selectBySql(String sql, Map<String, Object> parms);
In this case, need want to execute SQL statement directly, the sql as below:
SELECT VELOCITY_VARS FROM PPC_GYPSOPHILA_VARS_STATISTICS WHERE SCENARIO_ID=#{scenarioId} and TACTIC_ID=#{flowId} and CREATE_USER=#{userId}
all parameters of sql can be found in Map<String, Object> parms
I've done some research, but none of the solutions have worked for me. My Mapper class seems have some problems, but i dont know what's wrong.
Does anyone have an idea what's wrong here?
Thanks in advance
I am going to suppose that public interface GypsophilaVarsStatisticsMapper implements selectBySQL, in a correct way. I assumed you are import annotations if you are using it by:
import com.ppcredit.gypsophila.mapper.entity.GypsophilaVarsStatistics;
import org.apache.ibatis.annotations.*;
public interface GypsophilaVarsStatisticsMapper {
List<GypsophilaVarsStatistics> selectBySQL(String sql,Map parameters);
/**your code**/
I am going to suppose likewise, that you have a class (let's call it test) whose scope allows to call GypsophilaVarsStatisticsMapper Interface (in other case import). That would i do is the folloging:
import com.ppcredit.gypsophila.mapper.entity.GypsophilaVarsStatistics;
public class Test {
public static void main(String args[]) throws IOException{
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = sqlSessionFactory.openSession();
session.getConfiguration().addMapper(GypsophilaVarsStatisticsMapper.class);
GypsophilaVarsStatisticsMapper mapper = session.getMapper(GypsophilaVarsStatisticsMapper.class);
sql_string = 'SELECT VELOCITY_VARS FROM PPC_GYPSOPHILA_VARS_STATISTICS WHERE SCENARIO_ID=#{scenarioId} and TACTIC_ID=#{flowId} and CREATE_USER=#{userId}'
Map<String,Object) params = getParams() /* Your params */
List<GypsophilaVarsStatistics> result = mapper.selectBySQL(sql_string, params)
I suppose than you not are using MyBatis with a dependency injection framework like Spring. In this case SqlSessionFactory is supplied by this framework.
Related
I am getting nullPointerException from my custom jpa method findShiftNameById() in my shift planner project(github link below). I have used #Query annotation inside ShiftDetailsRepo Interface to implement the method. Please check and let me know what could be causing this. I tried by removing nativeQuery parameter but that gives shift_details not mapped error.I tried by changing datatypes between int and long and also by changing sd.shiftName to sd.shift_name(as per the column name that is available in my actual database) but still same nullPointerException error is coming.
Github link-https://github.com/Anupam5713/shiftPlannerAPI
The method is being called in the ShiftPlanService Class inside the service package
Is there something wrong in my query?
#Query(value = "select sd.shiftName from shift_details sd where sd.shiftId=:shiftId",nativeQuery=true)
public String findShiftNameById(#Param("shiftId") int shiftId);
The following is the cause of NPE. The call to sdr is done before the dependencies are wired.
#Service
public class ShiftPlanService {
#Autowired
ShiftDetailsRepo sdr;
String S1 = sdr.findShiftNameById(1);
String S2 = sdr.findShiftNameById(2);
Move these initializations to a #PostConstruct method.
Example
#PostConstruct
public void initDetails() {
S1 = sdr.findShiftNameById(1);
S2 = sdr.findShiftNameById(2);
}
I have this camel route:
from("direct:getUser")
.pollEnrich("jpa://User?namedQuery=User.findById&consumeDelete=false");
This is my user Entity:
#Entity
#NamedQueries({
#NamedQuery(name="User.findAll", query="SELECT u FROM User u"),
#NamedQuery(name="User.findById", query="SELECT u FROM User u WHERE u.id = :id")
})
public class User{
#Id
private String id;
}
I have tried this route by setting the header:
from("direct:getUser")
.setHeader("id", simple("myid"))
.pollEnrich("jpa://User?namedQuery=User.findById&consumeDelete=false");
But it is not working
Is there any method to set jpa properties by the headers? The camel documentation quote this in parameters option but i don't found the examples
Options: parameters
This option is Registry based which requires the # notation. This
key/value mapping is used for building the query parameters. It is
expected to be of the generic type java.util.Map where
the keys are the named parameters of a given JPA query and the values
are their corresponding effective values you want to select for. Camel
2.19: it can be used for producer as well. When it's used for producer, Simple expression can be used as a parameter value. It
allows you to retrieve parameter values from the message body header
and etc.
I hope it's not too late to answer. In any case I had a similar issue in my project, the client does a HTTP GET with a parameter id, which is used by the JPA query and the result is finally marshalled back to the HTTP client. I'm running camel in a Spring application.
I finally figured out how to achieve it in a reasonably clean way.
This is the RouteBuilder where the route is defined:
#Override
public void configure() throws Exception {
Class dataClass = SomeClass.class;
JacksonDataFormat format = new JacksonDataFormat();
format.setUnmarshalType(dataClass);
String jpaString = String
.format("jpa://%1$s?resultClass=%1$s&namedQuery=q1" +
"¶meters={\"id\":${headers.id}}", dataClass.getName());
from("jetty://http://localhost:8080/test").toD(jpaString) // note the .toD
.marshal(format)
}
And this is the StringToMapTypeConverter class, otherwise camel cannot convert {"id": X} to a map
public class StringToMapTypeConverter implements TypeConverters {
private static final ObjectMapper mapper = new ObjectMapper();
private static JavaType mapType;
static {
mapType = mapper.getTypeFactory().constructMapType(Map.class,
String.class, Object.class);
}
#Converter
public Map<String, Object> toMap(String map) throws IOException {
return mapper.readValue(map, mapType);
}
}
Remember to add it to the context. In Spring is something like:
<bean id="myStringToMapTypeConverter" class="....StringToMapTypeConverter" />
Refs:
http://camel.apache.org/jpa.html
http://camel.apache.org/message-endpoint.html#MessageEndpoint-DynamicTo
http://camel.apache.org/type-converter.html#TypeConverter-Addtypeconverterclassesatruntime
When i try to insert a new entry to a deserialized Map instance i get no exception but the Map is not modified. This EntryPoint code probes it. I'm doing anything wrong?
public class Test2 implements EntryPoint {
public interface SomeProxy {
Map<String, List<Integer>> getStringKeyMap();
void setStringKeyMap(Map<String, List<Integer>> value);
}
public interface BeanFactory extends AutoBeanFactory {
BeanFactory INSTANCE = GWT.create(BeanFactory.class);
AutoBean<SomeProxy> someProxy();
}
#Override
public void onModuleLoad() {
SomeProxy proxy = BeanFactory.INSTANCE.someProxy().as();
proxy.setStringKeyMap(new HashMap<String, List<Integer>>());
proxy.getStringKeyMap().put("k1", new ArrayList<Integer>());
proxy.getStringKeyMap().put("k2", new ArrayList<Integer>());
String payload = AutoBeanCodex.encode(AutoBeanUtils.getAutoBean(proxy)).toString();
proxy = AutoBeanCodex.decode(BeanFactory.INSTANCE, SomeProxy.class, payload).as();
// insert a new entry into a deserialized map
proxy.getStringKeyMap().put("k3", new ArrayList<Integer>());
System.out.println(proxy.getStringKeyMap().keySet()); // the keySet is [k1, k2] :-( ¿where is k3?
}
}
Shouldn't AutoBeanCodex.encode(AutoBeanUtils.getAutoBean(proxy)).toString(); be getPayLoad()
I'll check the code later, and I don't know if that is causing the issue. But it did stand out as different from my typical approach.
Collection classes such as java.util.Set and java.util.List are tricky because they operate in terms of Object instances. To make collections serializable, you should specify the particular type of objects they are expected to contain through normal type parameters (for example, Map<Foo,Bar> rather than just Map). If you use raw collections or maps you will get bloated code and be vulnerable to denial of service attacks.
Font: http://www.gwtproject.org/doc/latest/DevGuideServerCommunication.html#DevGuideSerializableTypes
Tried to find the answer on the Web but failed. Should be simple for pro Spring Devs... so here it comes:
In few words I want to bind the List of interface type: List to the form and get the data back (possibly modified by user via form. The problem is that it doesn't work :(
my code (short version) - command/model class which is passed to the form:
public class RoomsFormSearchResultCommand extends RoomsFormSearchCommand {
#SuppressWarnings("unchecked")
private List<IRoom> roomsList = LazyList.decorate(new ArrayList<Room>(),
FactoryUtils.instantiateFactory(Room.class));
public List<IRoom> getRoomsList() {
return roomsList;
}
public void setRoomsList(final List<IRoom> roomsList) {
this.roomsList = roomsList;
}
(...)
then in the form I use it like that (short version):
<form:form method="post" action="reserve" commandName="roomsResultsCmd">
(...)
<c:forEach var="room" items="${roomsResultsCmd.roomsList}"
varStatus="status">
<tr>
<td><form:input path="roomsList[${status.index}].roomNumber" readonly="true"/>
(...)
The form is displayed fine but after submitting it I get:
2012-01-22 21:31:55 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [wyspa] in context with path [/wyspa] threw exception [Request processing failed; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'roomsList[0]' of bean class [com.wyspa.controller.command.RoomsFormSearchResultCommand]: Illegal attempt to get property 'roomsList' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'roomsList' of bean class [com.wyspa.controller.command.RoomsFormSearchResultCommand]: Could not instantiate property type [com.wyspa.entity.IRoom] to auto-grow nested property path: java.lang.InstantiationException: com.wyspa.entity.IRoom] with root cause
org.springframework.beans.NullValueInNestedPathException: Invalid property 'roomsList' of bean class [com.wyspa.controller.command.RoomsFormSearchResultCommand]: Could not instantiate property type [com.wyspa.entity.IRoom] to auto-grow nested property path: java.lang.InstantiationException: com.wyspa.entity.IRoom
at org.springframework.beans.BeanWrapperImpl.newValue(BeanWrapperImpl.java:633)
at org.springframework.beans.BeanWrapperImpl.growCollectionIfNecessary(BeanWrapperImpl.java:863)
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:770)
at org.springframework.beans.BeanWrapperImpl.getNestedBeanWrapper(BeanWrapperImpl.java:555)
(...)
The deal is then when I change the List to "instances" list everything works fine!
public class RoomsFormSearchResultCommand extends RoomsFormSearchCommand {
#SuppressWarnings("unchecked")
//notice that the List is now List<Room>
private List<Room> roomsList = LazyList.decorate(new ArrayList<Room>(),
FactoryUtils.instantiateFactory(Room.class));
In this case data is passed to the controller in proper way.
Since I am used to devlop on interfaces and I am pretty crazy about it I would REALLY prefer not to translate the List<IRoom> (which comes back from services) to List<Room> which seems to suit Spring. Is it possible to work with List<IRoom> in this case or Spring just doesn't support it?
//Of course Room implements IRoom - but I guess you already got that...
I would be VERY happy for any help/suggestions!
Best Regards,
Nirwan
I have exact the same problem. Changing to following won't fix the problem. It looks spring binding ignores the factory utils and tries to instantiate the null object itself:
#SuppressWarnings("unchecked")
private List<IRoom> roomsList = LazyList.decorate(new ArrayList<IRoom>(),
FactoryUtils.instantiateFactory(Room.class));
The workaround is to set auto grow nested path off in your controller:
#InitBinder protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
binder.setAutoGrowNestedPaths(false);
super.initBinder(request, binder);
}
The problem is you'll lose the handy nested path like user.account.address.street. You have to make sure none of user, account, addresss is null. It does cause a lot of problems. That's why I came here, see if I can find better solution.
If you don't actually need the list to auto-grow, you can store the form object in the session to avoid the nasty side effects of disabling auto-growing nested paths.
#Controller
#SessionAttributes(types = RoomsFormSearchResultCommand.class)
public final class SearchController {
#InitBinder
protected void initBinder(final WebDataBinder binder) {
binder.setAutoGrowNestedPaths(false);
}
#RequestMapping(method = RequestMethod.GET)
public String showForm(final Model model) {
RoomsFormSearchResultCommand form = ... // create or load form
model.addAttribute(form);
}
#RequestMapping(method = RequestMethod.POST)
public String onSubmitUpdateCart(
#ModelAttribute final RoomsFormSearchResultCommand form,
final BindingResult result,
final SessionStatus status) {
// if result has no errors, just set status to complete
status.setComplete();
}
}
Try the following lines
#SuppressWarnings("unchecked")
private List<IRoom> roomsList = LazyList.decorate(new ArrayList<IRoom>(),
FactoryUtils.instantiateFactory(Room.class));
don't have time to try that myself, but it would make sense.
I get exception "There is no default persistence unit in this deployment." can I somehow mark unit as default?(I have only one persistence unit, so Id rather not call it by name)
No, you have to call PU's by name.
You are probably doing it through code rather than letting the container manage it. In which case you have to specify by name.
My unit test code has this code block to do this.
#Before
public void createEntityManagerFactory() throws IOException {
final Properties p = new Properties();
p.load(getClass().getResourceAsStream("/inmemory.properties"));
emf = Persistence.createEntityManagerFactory("default", p);
}
However, my application code looks like this.
/**
* Injected persistence context.
*/
#PersistenceContext
private EntityManager em;