Spring Data JPA Receiving参数值[2]与期望类型[java.lang.String(n / a)]不匹配

时间:2016-07-16 23:51:01

标签: javascript java hibernate jpa spring-data

我知道这里已经提出了类似的问题,但我相信我做了我的研究,尝试了很多不同的方法但是还没有运气。

我的配置:Spring Data JPA(hibernate,H2 DB),上面的REST层,并有一个AngularJS客户端发出请求。

REST路径:

@RequestMapping("/search/{destinationId}/{arrivalId}/{departureTime}/{arrivalTime}/{numberOfPassengers}")
    public List<Flight> getFlightsWithCriteria(@PathVariable String destinationId,
                                               @PathVariable String arrivalId,
                                               @PathVariable String departureTime,
                                               @PathVariable String arrivalTime,
                                               @PathVariable Integer numberOfPassengers) { }

我按照以下方式调用该服务:

/search/2/1/2016-08-15T21:00:00.000Z/2016-08-15T21:00:00.000Z/2

顺便说一下,departureTime对象在数据库上是TIMESTAMP,测试数据的格式为2016-05-16 17:30:00.0

然后将日期解析为合适的格式以匹配DB:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date departureDate = sdf.parse(departureTime);
String formattedTime = dateFormat.format(departureDate);

然后在我的查询中使用此formattedTime参数,如下所示:

flights = (List<Flight>) entityManager
                    .createQuery("SELECT f FROM Flight f WHERE f.departureTerminal = :destination AND f.arrivalTerminal = :arrival AND f.departureTime <= :departureDate AND f.numberOfSeatsAvailable <= :numberOfPassengers")
                    .setParameter("destination", destination)
                    .setParameter("arrival", arrival)
                    .setParameter("departureDate", newDate)
                    .setParameter("numberOfPassengers", numberOfPassengers).getResultList();

然后我当然会收到:

java.lang.IllegalArgumentException: Parameter value [2] did not match expected type [java.lang.String (n/a)]

鉴于这些,您可能会说我为什么要将String的查询发送到TIMESTAMP对象,这是我迄今为止所尝试过的:

  • 在查询中发送了String
  • 在查询中发送了Date
  • Date
  • 的查询中发送了TemporalType.TIMESTAMP
  • @DateFormat
  • 中使用了@PathParam
  • 将日期类型的整个实体模型更改为String并一次又一次地尝试

..我已经在这个问题上抓了几个小时,但还没有解决方案。

请你看看我的代码并指出我做错了什么?

谢谢

1 个答案:

答案 0 :(得分:0)

尝试通过在适当的位置添加括号来清除查询操作数的分组,以帮助您进行逻辑和调试,例如:以下

flights = (List<Flight>) entityManager
                    .createQuery("SELECT f FROM Flight f WHERE f.departureTerminal = :destination AND f.arrivalTerminal = :arrival AND (f.departureTime <= :departureDate)  AND (f.numberOfSeatsAvailable <= :numberOfPassengers)")
                    .setParameter("destination", destination)
                    .setParameter("arrival", arrival)
                    .setParameter("departureDate", newDate)
                    .setParameter("numberOfPassengers", numberOfPassengers).getResultList();

只是另一个想法,尝试传递1参数然后调整您的请求服务1参数然后进入第二参数,等等。这将精确确定哪个参数有问题。

一旦你发现了罪魁祸首,现在通过传递唯一的请求参数来解决问题,将问题简化为该参数。

更新(我的解决方案):

我的代码有另一个破解,查询很好。我怀疑你输入的是像你报告的异常一样的问题。以下是我测试的内容,与您的查询类似,如果这可以帮助您进行测试。

<强> FlightTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestH2DatabaseConfiguration.class }, loader = AnnotationConfigContextLoader.class)
public class FlightTest extends AbstractTransactionalJUnit4SpringContextTests {

    final static Logger log = LoggerFactory.getLogger(FlightTest.class);

    @Autowired
    @Qualifier("entityManagerFactory")
    EntityManagerFactory entityManagerFactory;

    @Test
    @SuppressWarnings("unchecked")
    public void test() throws ParseException {

        assertNotNull(entityManagerFactory);

        EntityManager entityManager = entityManagerFactory.createEntityManager();
        assertNotNull(entityManager);

        List<Flight> flights = (List<Flight>) entityManager.createQuery("FROM Flight").getResultList();

        assertEquals(2, flights.size());


        String departureTimeRequestInput = "2016-05-16T21:00:00.000Z";

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");        
        Date departureDate = sdf.parse(departureTimeRequestInput);
        Timestamp departureTimestamp = new Timestamp(departureDate.getTime());


        flights = (List<Flight>) entityManager.createQuery(
                  "SELECT f FROM Flight f "
                + "WHERE "
                + "f.destinationId = :destinationId "
                + "and "
                + "f.arrivalId = :arrivalId "
                + "and "
                + "f.departureTime <= :departureDate "
                + "and "
                + "f.numberOfPassengers <= :numberOfPassengers")
                .setParameter("destinationId", 1L)
                .setParameter("arrivalId", 3L)
                .setParameter("departureDate", departureTimestamp)          
                .setParameter("numberOfPassengers", 400L)
                 .getResultList();              

        assertEquals(1, flights.size());

        log.debug("**H2**SIZE: " + flights.size());     
    }

}

<强> TestH2DatabaseConfiguration.java

@Configuration
@EnableJpaRepositories("com.mycompany.h2.jpa")
@EnableTransactionManagement
public class TestH2DatabaseConfiguration {

    final static Logger log = LoggerFactory.getLogger(TestH2DatabaseConfiguration.class);

    @Bean
    @Qualifier("dataSource")
    public DataSource h2DataSource() {
        return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).addScript("classpath:flight.sql").build();
    }

    @Bean
    public EntityManagerFactory entityManagerFactory() {

        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();

        factoryBean.setDataSource(h2DataSource());
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setPackagesToScan("com.mycompany.h2.jpa");
        factoryBean.setPersistenceUnitName("flight_table");

        Properties ps = new Properties();
        ps.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        ps.put("hibernate.show_sql", "true");
        ps.put("hibernate.hbm2ddl.auto", "none");
        factoryBean.setJpaProperties(ps);       

        factoryBean.afterPropertiesSet();


        return factoryBean.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory());
        return txManager;
    }   
}

<强> Flight.java

public class Flight implements Serializable {

    private static final long serialVersionUID = 2608721697556397731L;

    @Id
    private Long destinationId;

    private Long arrivalId;
    private Timestamp departureTime;
    private Timestamp arrivalTime;
    private Long numberOfPassengers;
    ...
}

<强> flight.sql

CREATE TABLE flight (
  destinationId      INTEGER PRIMARY KEY,
  arrivalId          INTEGER,
  departureTime      TIMESTAMP,
  arrivalTime        TIMESTAMP,
  numberOfPassengers INTEGER
);

INSERT INTO flight VALUES (1, 3, '2016-05-16 17:30:00.0', '2016-05-18 17:30:00.0', 400);
INSERT INTO flight VALUES (2, 2, '2016-05-17 17:30:00.0', '2016-05-19 17:30:00.0', 200);

<强>关键点: 这里的关键点是将用户输入时间超过java.sql.Timestamp对象,如 FlightTest.java 所示,例如

        String departureTimeRequestInput = "2016-05-16T21:00:00.000Z";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");        
        Date departureDate = sdf.parse(departureTimeRequestInput);
        Timestamp departureTimestamp = new Timestamp(departureDate.getTime());

...
.setParameter("departureDate", departureTimestamp)
...

Update2:以下交易中的示例航班对象插入

EntityManager entityManager = null;
try {
    entityManager = entityManagerFactory.createEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    entityManager.persist(flightObject);
    entityManager.flush();
    transaction.commit();           
    return flightObject;
}
finally {
    entityManager.close();
}