| /* |
| * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // 10/09/2012-2.5 Guy Pelletier |
| // - 374688: JPA 2.1 Converter support |
| // 10/25/2012-2.5 Guy Pelletier |
| // - 374688: JPA 2.1 Converter support |
| // 11/22/2012-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support (index metadata support) |
| // 11/28/2012-2.5 Guy Pelletier |
| // - 374688: JPA 2.1 Converter support |
| // 12/07/2012-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support (foreign key metadata support) |
| // 01/23/2013-2.5 Guy Pelletier |
| // - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls |
| // 02/28/2013-2.5 Chris Delahunt |
| // - 402029: Application exceptions need to be wrapped in PersistenceException |
| // 06/03/2013-2.5.1 Guy Pelletier |
| // - 402380: 3 jpa21/advanced tests failed on server with |
| // "java.lang.NoClassDefFoundError: org/eclipse/persistence/testing/models/jpa21/advanced/enums/Gender" |
| // 07/16/2013-2.5.1 Guy Pelletier |
| // - 412384: Applying Converter for parameterized basic-type for joda-time's DateTime does not work |
| // 11/06/2014-2.6 Tomas Kraus |
| // - 449818: Test to verify Convert annotation on ElementCollection of Embeddable class. |
| package org.eclipse.persistence.testing.tests.jpa22.advanced; |
| |
| import java.util.Date; |
| import java.util.List; |
| import java.util.Map; |
| |
| import jakarta.persistence.EntityManager; |
| import jakarta.persistence.Query; |
| import jakarta.persistence.TypedQuery; |
| |
| import junit.framework.Test; |
| import junit.framework.TestSuite; |
| |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.mappings.DirectToFieldMapping; |
| import org.eclipse.persistence.mappings.converters.ConverterClass; |
| import org.eclipse.persistence.mappings.converters.SerializedObjectConverter; |
| import org.eclipse.persistence.sessions.server.ServerSession; |
| import org.eclipse.persistence.testing.framework.junit.JUnitTestCase; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.Employee; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.Organizer; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.Race; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.Responsibility; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.Runner; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.RunnerInfo; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.RunnerStatus; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.RunnerVictory; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.converters.CompetitionConverter; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.converters.ResponsibilityConverter; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.enums.Health; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.enums.Level; |
| import org.eclipse.persistence.testing.models.jpa22.advanced.enums.RunningStatus; |
| |
| public class ConverterTestSuite extends JUnitTestCase { |
| public ConverterTestSuite() {} |
| |
| public ConverterTestSuite(String name) { |
| super(name); |
| setPuName("MulitPU-1"); |
| } |
| |
| public static Test suite() { |
| TestSuite suite = new TestSuite(); |
| suite.setName("ConverterTestSuite"); |
| |
| suite.addTest(new ConverterTestSuite("testAutoApplyConverter")); |
| suite.addTest(new ConverterTestSuite("testAnnotationConverters")); |
| suite.addTest(new ConverterTestSuite("testConverterExceptionWrapping1")); |
| suite.addTest(new ConverterTestSuite("testConverterExceptionWrapping2")); |
| suite.addTest(new ConverterTestSuite("testConvertOnElementCollection")); |
| |
| return suite; |
| } |
| |
| /** |
| * Test that an attribute picks up an auto apply converter. |
| */ |
| public void testAutoApplyConverter() { |
| ServerSession session = getPersistenceUnitServerSession(); |
| |
| ClassDescriptor employeeDescriptor = session.getDescriptor(Employee.class); |
| DirectToFieldMapping salaryMapping = (DirectToFieldMapping) employeeDescriptor.getMappingForAttributeName("salary"); |
| assertNotNull("Salary mapping did not have the auto apply converter", salaryMapping.getConverter()); |
| |
| DirectToFieldMapping previousSalaryMapping = (DirectToFieldMapping) employeeDescriptor.getMappingForAttributeName("previousSalary"); |
| assertNull("Salary mapping did not have the auto apply converter", previousSalaryMapping.getConverter()); |
| |
| ClassDescriptor runnerDescriptor = session.getDescriptor(Runner.class); |
| |
| DirectToFieldMapping tagsMapping = (DirectToFieldMapping) runnerDescriptor.getMappingForAttributeName("tags"); |
| assertTrue("Tags mapping did not have a converter", tagsMapping.hasConverter()); |
| assertTrue("Serials mappings did not have a SerializedObjectConverter", tagsMapping.getConverter() instanceof ConverterClass); |
| |
| DirectToFieldMapping serialsMapping = (DirectToFieldMapping) runnerDescriptor.getMappingForAttributeName("serials"); |
| assertTrue("Serials mapping did not have a converter", serialsMapping.hasConverter()); |
| assertTrue("Serials mappings did not have a SerializedObjectConverter", serialsMapping.getConverter() instanceof SerializedObjectConverter); |
| } |
| |
| /** |
| * Test that converters are set. |
| */ |
| public void testAnnotationConverters() { |
| EntityManager em = createEntityManager(); |
| |
| try { |
| beginTransaction(em); |
| |
| Runner runner = new Runner(); |
| runner.setAge(53); |
| runner.setIsFemale(); |
| runner.setFirstName("Doris"); |
| runner.setLastName("Day"); |
| runner.addPersonalBest("10 KM", "47:34"); |
| runner.addPersonalBest("5", "26:41"); |
| runner.addTag("tag1"); |
| runner.addAccomplishment("Ran 100KM without stopping", new Date(System.currentTimeMillis())); |
| RunnerInfo runnerInfo = new RunnerInfo(); |
| runnerInfo.setHealth(Health.H); |
| runnerInfo.setLevel(Level.A); |
| RunnerStatus runnerStatus = new RunnerStatus(); |
| runnerStatus.setRunningStatus(RunningStatus.D); |
| runnerInfo.setStatus(runnerStatus); |
| runner.setInfo(runnerInfo); |
| |
| Race race = new Race(); |
| race.setName("The Ultimate Marathon"); |
| race.addRunner(runner); |
| |
| Organizer organizer = new Organizer(); |
| organizer.setName("Joe Organ"); |
| organizer.setRace(race); |
| |
| Responsibility responsibility = new Responsibility(); |
| responsibility.setUniqueIdentifier(System.currentTimeMillis()); |
| responsibility.setDescription("Raise funds"); |
| |
| race.addOrganizer(organizer, responsibility); |
| |
| em.persist(race); |
| em.persist(organizer); |
| em.persist(runner); |
| em.flush(); |
| |
| // Clear the cache |
| em.clear(); |
| clearCache(); |
| |
| Runner runnerRefreshed = em.find(Runner.class, runner.getId()); |
| assertTrue("The age conversion did not work.", runnerRefreshed.getAge() == 52); |
| assertTrue("The embeddable health conversion did not work.", runnerRefreshed.getInfo().getHealth().equals(Health.HEALTHY)); |
| assertTrue("The embeddable level conversion did not work.", runnerRefreshed.getInfo().getLevel().equals(Level.AMATEUR)); |
| assertTrue("The nested embeddable running status conversion did not work.", runnerRefreshed.getInfo().getStatus().getRunningStatus().equals(RunningStatus.DOWN_TIME)); |
| assertTrue("The number of personal bests for this runner is incorrect.", runnerRefreshed.getPersonalBests().size() == 2); |
| assertTrue("Distance (map key) conversion did not work.", runnerRefreshed.getPersonalBests().keySet().contains("10K")); |
| assertTrue("Distance (map key) conversion did not work.", runnerRefreshed.getPersonalBests().keySet().contains("5K")); |
| assertTrue("Time (map value) conversion did not work.", runnerRefreshed.getPersonalBests().values().contains("47:34.0")); |
| assertTrue("Time (map value) conversion did not work.", runnerRefreshed.getPersonalBests().values().contains("26:41.0")); |
| |
| Race raceRefreshed = em.find(Race.class, race.getId()); |
| Map<Responsibility, Organizer> organizers = raceRefreshed.getOrganizers(); |
| assertFalse("No race organizers returned.", organizers.isEmpty()); |
| assertTrue("More than one race organizer returned.", organizers.size() == 1); |
| |
| Responsibility resp = organizers.keySet().iterator().next(); |
| assertTrue("Responsibility was not uppercased by the converter", resp.getDescription().equals("RAISE FUNDS")); |
| |
| for (String accomplishment : runnerRefreshed.getAccomplishments().keySet()) { |
| assertTrue("Accomplishment (map key) conversion did not work.", accomplishment.endsWith("!!!")); |
| } |
| } finally { |
| closeEntityManagerAndTransaction(em); |
| } |
| } |
| |
| /** |
| * Test that application exceptions thrown from the converter's convertToEntityAttribute method get |
| * wrapped in a PersistenceException. |
| * Added for bug 402029: Application exceptions need to be wrapped in PersistenceException |
| */ |
| public void testConverterExceptionWrapping1() { |
| EntityManager em = createEntityManager(); |
| |
| try { |
| beginTransaction(em); |
| // setup |
| Race race = new Race(); |
| race.setName("Just Another Marathon"); |
| |
| Organizer organizer = new Organizer(); |
| organizer.setName("John Smith"); |
| organizer.setRace(race); |
| |
| Responsibility responsibility = new Responsibility(); |
| responsibility.setUniqueIdentifier(System.currentTimeMillis()); |
| //This string causes an exception to be thrown from the ResponsibilityConverter.convertToEntityAttribute method |
| responsibility.setDescription(ResponsibilityConverter.THROW_EXCEPTION_IN_TO_ENTITY_ATTRIBUTE); |
| |
| race.addOrganizer(organizer, responsibility); |
| |
| try { |
| em.persist(race); |
| em.persist(organizer); |
| em.flush(); |
| |
| // Clear the cache |
| em.clear(); |
| clearCache(); |
| |
| race = em.find(Race.class, race.getId()); |
| //trigger indirection |
| race.getOrganizers().get(responsibility); |
| } catch (jakarta.persistence.PersistenceException pe) { |
| if (pe.getCause() == null || |
| !ResponsibilityConverter.THROW_EXCEPTION_IN_TO_ENTITY_ATTRIBUTE.equals(pe.getCause().getMessage())) { |
| //rethrow this exception because it does not contain the expected application generated RuntimeException |
| throw pe; |
| }//else this error is expected and can be ignored |
| } catch (RuntimeException unexpected) { |
| if (ResponsibilityConverter.THROW_EXCEPTION_IN_TO_ENTITY_ATTRIBUTE.equals(unexpected.getMessage())) { |
| fail("Application exception thrown from convertToEntityAttribute was not wrapped in a PersistenceException"); |
| } |
| throw unexpected; |
| } |
| |
| } finally { |
| closeEntityManagerAndTransaction(em); |
| } |
| } |
| |
| /** |
| * Test that application exceptions thrown from the converter's convertToDatabaseColumn method get |
| * wrapped in a PersistenceException. |
| * Added for bug 402029: Application exceptions need to be wrapped in PersistenceException |
| */ |
| public void testConverterExceptionWrapping2() { |
| EntityManager em = createEntityManager(); |
| |
| try { |
| beginTransaction(em); |
| // setup |
| Race race = new Race(); |
| race.setName("Just Another Marathon"); |
| |
| Organizer organizer = new Organizer(); |
| organizer.setName("John Smith"); |
| organizer.setRace(race); |
| |
| Responsibility responsibility = new Responsibility(); |
| responsibility.setUniqueIdentifier(System.currentTimeMillis()); |
| //This string causes an exception to be thrown from the ResponsibilityConverter.convertToDatabaseColumn method |
| responsibility.setDescription(ResponsibilityConverter.THROW_EXCEPTION_IN_TO_DATABASE_COLUMN); |
| |
| race.addOrganizer(organizer, responsibility); |
| |
| try { |
| em.persist(race); |
| em.persist(organizer); |
| em.flush(); |
| } catch (jakarta.persistence.PersistenceException pe) { |
| if (pe.getCause() == null || |
| !ResponsibilityConverter.THROW_EXCEPTION_IN_TO_DATABASE_COLUMN.equals(pe.getCause().getMessage())) { |
| //rethrow this exception because it does not contain the expected application generated RuntimeException |
| throw pe; |
| }//else this error is expected and can be ignored |
| |
| } catch (RuntimeException unexpected) { |
| if (ResponsibilityConverter.THROW_EXCEPTION_IN_TO_DATABASE_COLUMN.equals(unexpected.getMessage())) { |
| fail("Application exception thrown from convertToDatabaseColumn was not wrapped in a PersistenceException"); |
| } |
| throw unexpected; |
| } |
| |
| } finally { |
| closeEntityManagerAndTransaction(em); |
| } |
| } |
| |
| /** |
| * Verify {@code @Convert} annotation on {@code @ElementCollection} mapping. Two collections are defined, first |
| * with annotation and second one without it. Tests verifies if converter class is applied on both collections |
| * or not. |
| */ |
| public void testConvertOnElementCollection() { |
| final EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| // Converter used in @ElementCollection mapping. |
| final CompetitionConverter converter = new CompetitionConverter(); |
| // Run test for all existing Runner instances. |
| final TypedQuery<Runner> rq = em.createNamedQuery("Runner.listAll", Runner.class); |
| final List<Runner> runners = rq.getResultList(); |
| assertTrue("No Runner object was returned", runners.size() > 0); |
| for (Runner runner : runners) { |
| |
| // Verify Map processed with @Convert annotation. |
| final Map <String, RunnerVictory> victoriesThisYear = runner.getVictoriesThisYear(); |
| final Query rvtq = em.createNamedQuery("RunnerVictoryThis.getById"); |
| rvtq.setParameter(1, runner.getId()); |
| final List<Object[]> victories = rvtq.getResultList(); |
| assertEquals("Count of retrieved objects from database shall be the same.", |
| runner.getVictoriesThisYear().size(), victories.size()); |
| for (Object[] victory : victories) { |
| final String name = (String)victory[0]; |
| final Long id = ((Number)victory[1]).longValue(); |
| final String competition = (String)victory[2]; |
| final RunnerVictory entityVictory = victoriesThisYear.get(name); |
| String entityCompetitionConverted |
| = converter.convertToDatabaseColumn(entityVictory.getCompetition()); |
| String dbCompetitionConverted = converter.convertToEntityAttribute(competition); |
| assertFalse("Entity and database values shall not match.", |
| competition.equals(entityVictory.getCompetition())); |
| assertTrue("Manually converted entity value and plain database value shall match.", |
| competition.equals(entityCompetitionConverted)); |
| assertTrue("Manually converted database value and plain entity value shall match.", |
| entityVictory.getCompetition().equals(dbCompetitionConverted)); |
| } |
| } |
| for (Runner runner : runners) { |
| |
| // Verify Map not processed with @Convert annotation. |
| final Map <String, RunnerVictory> victoriesLastYear = runner.getVictoriesLastYear(); |
| final Query rvlq = em.createNamedQuery("RunnerVictoryLast.getById"); |
| rvlq.setParameter(1, runner.getId()); |
| final List<Object[]> victories = rvlq.getResultList(); |
| assertEquals("Count of retrieved objects from database shall be the same.", |
| runner.getVictoriesLastYear().size(), victories.size()); |
| for (Object[] victory : victories) { |
| final String name = (String)victory[0]; |
| final Long id = ((Number)victory[1]).longValue(); |
| final String competition = (String)victory[2]; |
| final RunnerVictory entityVictory = victoriesLastYear.get(name); |
| // Converter is missing so only entity to database conversion check makes sense. |
| String entityCompetitionConverted |
| = converter.convertToDatabaseColumn(entityVictory.getCompetition()); |
| assertTrue("Entity and database values shall match.", |
| competition.equals(entityVictory.getCompetition())); |
| assertFalse("Manually converted entity value and plain database value shall not match.", |
| competition.equals(entityCompetitionConverted)); |
| } |
| } |
| } finally { |
| closeEntityManagerAndTransaction(em); |
| } |
| } |
| |
| @Override |
| public String getPersistenceUnitName() { |
| return "MulitPU-1"; |
| } |
| } |