2017-01-11 17 views
2

У меня проблема с UUID полей, определенной ID доменомJaybird с JPA на UUID поля (CHAR (16) набора символов октет)

CREATE DOMAIN OCTET16 AS CHAR(16) CHARACTER SET OCTETS; 

Я определил AttributeConverter для JPA как импортных java.util.UUID;

import javax.persistence.AttributeConverter; 
import javax.persistence.Converter; 

import com.ekser.nakkash.icdv.tools.UUIDTools; 

@Converter 
public class UUIDAttributeConverter implements AttributeConverter<UUID, byte[]> { 
    @Override 
    public byte[] convertToDatabaseColumn(UUID arg0) { 
     return UUIDTools.asBytes((UUID) arg0); 
    } 
    @Override 
    public UUID convertToEntityAttribute(byte[] arg0) { 
     return UUIDTools.asUUID((byte[])arg0); 
    } 
} 

и определенные JPA поля как

@Id 
@Convert(converter = UUIDAttributeConverter.class) 
private UUID id; 

но JPA (EclipseLink + Eclipse, Gemini) дает ошибку, как он пытается преобразовать не бинарное представление, но текстовую форму 36 символа

Я полагаю, проблема что jaybird дает тип поля как CHAR (16), (я проверил с ResultSetMetaData), я знаю, что есть опция octetsAsBytes, я использовал его с URL-адресом jbdc, например

jdbc:firebirdsql:localhost:D:/aktarma-12-13/VERI.FDB?octetsAsBytes=true 

без результата.

Моя установка довольно сложна

Java 1.8 
Efxclipse 2.4.0 RCP 
Firebird 2.5.6 
Jaybird 2.2.12 JDK_1.8 
HikariCP 2.4.1 
EclipseLink 2.6.4 
Eclipse Gemini 1.2.0.M1 

Так что я думаю, что когда ResultSetMetaData даст мне тип поля, как BINARY проблема будет исчезла. Но как? Какие-либо предложения.

Я просто не хочу хранить идентификаторы в виде char (32) или char (36).

Edit: После переключения на Соек 3 & beta-2, можно ясно видеть на третьей строке invalid stream header: F1505533. Это часть ASCII декодированного идентификатора (char (16)). Как заставить JPA принять это значение в качестве исходного байта и передать его в класс UUIDAttributeConverter ?? !!

Exception in thread "JavaFX Application Thread" javax.persistence.PersistenceException: Exception [EclipseLink-66] (Eclipse Persistence Services - 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.DescriptorException 
Exception Description: Could not deserialize object from byte array. 
Internal Exception: java.lang.RuntimeException: java.io.StreamCorruptedException: invalid stream header: F1505533 
Mapping: org.eclipse.persistence.mappings.DirectToFieldMapping[id-->YAZDIRMA_TURLERI.ID] 
Descriptor: RelationalDescriptor(com.ekser.nakkash.icdv.pojo.YazdirmaTuru --> [DatabaseTable(YAZDIRMA_TURLERI)]) 
    at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:484) 
    at com.ekser.nakkash.icdv.gui.MainPartIcdv.lambda$1(MainPartIcdv.java:180) 
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) 
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) 
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49) 
    at javafx.event.Event.fireEvent(Event.java:198) 
    at javafx.scene.Node.fireEvent(Node.java:8413) 
    at javafx.scene.control.Button.fire(Button.java:185) 
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182) 
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96) 
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89) 
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218) 
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) 
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) 
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) 
    at javafx.event.Event.fireEvent(Event.java:198) 
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757) 
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485) 
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762) 
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416) 
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415) 
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555) 
    at com.sun.glass.ui.View.notifyMouse(View.java:937) 
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) 
    at java.lang.Thread.run(Unknown Source) 
Caused by: Exception [EclipseLink-66] (Eclipse Persistence Services - 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.DescriptorException 
Exception Description: Could not deserialize object from byte array. 
Internal Exception: java.lang.RuntimeException: java.io.StreamCorruptedException: invalid stream header: F1505533 
Mapping: org.eclipse.persistence.mappings.DirectToFieldMapping[id-->YAZDIRMA_TURLERI.ID] 
Descriptor: RelationalDescriptor(com.ekser.nakkash.icdv.pojo.YazdirmaTuru --> [DatabaseTable(YAZDIRMA_TURLERI)]) 
    at org.eclipse.persistence.exceptions.DescriptorException.notDeserializable(DescriptorException.java:1232) 
    at org.eclipse.persistence.mappings.converters.SerializedObjectConverter.convertDataValueToObjectValue(SerializedObjectConverter.java:144) 
    at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.getObjectValue(AbstractDirectMapping.java:616) 
    at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.valueFromRow(AbstractDirectMapping.java:1220) 
    at org.eclipse.persistence.mappings.DatabaseMapping.readFromRowIntoObject(DatabaseMapping.java:1539) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:462) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:1005) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneNormally(ObjectBuilder.java:899) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:852) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:735) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:689) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:805) 
    at org.eclipse.persistence.queries.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:962) 
    at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:573) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1175) 
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:904) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1134) 
    at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:460) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1222) 
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1857) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1839) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804) 
    at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258) 
    at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:473) 
    ... 56 more 
Caused by: java.lang.RuntimeException: java.io.StreamCorruptedException: invalid stream header: F1505533 
    at org.eclipse.persistence.sessions.serializers.JavaSerializer.deserialize(JavaSerializer.java:57) 
    at org.eclipse.persistence.mappings.converters.SerializedObjectConverter.convertDataValueToObjectValue(SerializedObjectConverter.java:142) 
    ... 79 more 
Caused by: java.io.StreamCorruptedException: invalid stream header: F1505533 
    at java.io.ObjectInputStream.readStreamHeader(Unknown Source) 
    at java.io.ObjectInputStream.<init>(Unknown Source) 
    at org.eclipse.persistence.internal.helper.CustomObjectInputStream.<init>(CustomObjectInputStream.java:37) 
    at org.eclipse.persistence.sessions.serializers.JavaSerializer.deserialize(JavaSerializer.java:53) 
    ... 80 more 
+0

Является ли водитель способным обрабатывать байт [] при записи - это проблема только при чтении? Если это так, просто попросите конвертер обработать строку символов, возвращенную из драйвера. – Chris

+1

Не могли бы вы попробовать с помощью [Jaybird 3-beta-2] (https://github.com/FirebirdSQL/jaybird/releases/tag/v3.0.0-beta-2), он будет обрабатывать октеты символов с символом char (16) 'как' '' '' '' '' '' '' '' всегда, см. [Набор символов OCTETS, обработанный как JDBC (VAR) BINARY] (https://www.firebirdsql.org/file/documentation/drivers_documentation/java/3.0.0-beta-2/release_notes. HTML # Символьный набором-октет рукоятки-как-JDBC-VARBINARY). «OctetsAsBytes» в Jaybird 2.2, к сожалению, не применяется последовательно (хотя он должен применяться в случае 'ResultSetMetaData', он не работает, если, например,' getObject' используется в результирующем наборе). –

+0

BTW: Возможно, было бы полезно включить фактическую ошибку в ваш вопрос. –

ответ

1

Я сделал простой проект, используя EclipseLink 2.6.4, чтобы проверить это, и как с JayBird 2.2.12 (установка octetsAsBytes=true требуется) и JayBird 3.0.0-бета-2 работает:

кодекс также на: https://gist.github.com/mrotteveel/273aa9e836880211820f54ff21164ec1

Todo Entity:

package com.example.eclipselink.entity; 

import com.example.eclipselink.converter.UUIDAttributeConverter; 

import javax.persistence.Convert; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import java.util.UUID; 

@Entity 
public class Todo { 

    @Id 
    @Convert(converter = UUIDAttributeConverter.class) 
    private UUID id; 

    public UUID getId() { 
     return id; 
    } 

    public void setId(UUID id) { 
     this.id = id; 
    } 
} 

UUIDAttributeConverter:

package com.example.eclipselink.converter; 

import javax.persistence.AttributeConverter; 
import javax.persistence.Converter; 
import java.nio.ByteBuffer; 
import java.util.UUID; 

@Converter 
public class UUIDAttributeConverter implements AttributeConverter<UUID, byte[]> { 

    @Override 
    public byte[] convertToDatabaseColumn(UUID uuid) { 
     if (uuid == null) return null; 
     byte[] buffer = new byte[16]; 
     ByteBuffer bb = ByteBuffer.wrap(buffer); 
     bb.putLong(uuid.getMostSignificantBits()); 
     bb.putLong(uuid.getLeastSignificantBits()); 
     return buffer; 
    } 

    @Override 
    public UUID convertToEntityAttribute(byte[] bytes) { 
     if (bytes == null) return null; 
     ByteBuffer bb = ByteBuffer.wrap(bytes); 
     long high = bb.getLong(); 
     long low = bb.getLong(); 
     return new UUID(high, low); 
    } 
} 

Главная:

package com.example.eclipselink; 

import com.example.eclipselink.entity.Todo; 

import javax.persistence.EntityManager; 
import javax.persistence.EntityManagerFactory; 
import javax.persistence.Persistence; 
import javax.persistence.Query; 
import java.util.List; 
import java.util.UUID; 

public class Main { 
    private static final String PERSISTENCE_UNIT_NAME = "todos"; 
    private static EntityManagerFactory factory; 

    public static void main(String[] args) { 
     factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME); 
     EntityManager em = factory.createEntityManager(); 
     // read the existing entries and write to console 
     Query q = em.createQuery("select t from Todo t"); 
     List<Todo> todoList = q.getResultList(); 
     for (Todo todo : todoList) { 
      System.out.println(todo.getId()); 
     } 
     System.out.println("Size: " + todoList.size()); 

     // create new todo 
     em.getTransaction().begin(); 
     Todo todo = new Todo(); 
     todo.setId(UUID.randomUUID()); 
     em.persist(todo); 
     em.getTransaction().commit(); 

     em.close(); 
    } 
} 

Постоянство контекст:

<?xml version="1.0" encoding="UTF-8" ?> 
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" 
      version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"> 
    <persistence-unit name="todos" transaction-type="RESOURCE_LOCAL"> 
     <class>com.example.eclipselink.entity.Todo</class> 
     <class>com.example.eclipselink.converter.UUIDAttributeConverter</class> 
     <properties> 
      <property name="javax.persistence.jdbc.driver" value="org.firebirdsql.jdbc.FBDriver" /> 
      <property name="javax.persistence.jdbc.url" 
         value="jdbc:firebirdsql://localhost/d:/data/db/fb3/eclipselink.fdb?charSet=UTF-8&amp;octetsAsBytes=true" /> 
      <property name="javax.persistence.jdbc.user" value="sysdba" /> 
      <property name="javax.persistence.jdbc.password" value="masterkey" /> 
     </properties> 

    </persistence-unit> 
</persistence> 

DDL:

CREATE TABLE TODO 
(
    ID char(16) CHARACTER SET OCTETS NOT NULL, 
    CONSTRAINT PK_TODO PRIMARY KEY (ID) 
); 

Выход после нескольких прогонов:

[EL Info]: 2017-01-13 15:59:14.733--ServerSession(1139700454)--EclipseLink, version: Eclipse Persistence Services - 2.6.4.v20160829-44060b6 
[EL Info]: connection: 2017-01-13 15:59:15.093--ServerSession(1139700454)--/file:/D:/Development/project/eclipselink/target/classes/_todos login successful 
4c062d69-849e-4946-8e25-edfc5d7441be 
dac10396-cfe2-4fb0-b048-65f954a82da5 
8dab770e-ebd2-4ebc-a29b-4b8aae0b449a 
9d376c67-fdc5-4e21-8013-f71cde5119aa 
Size: 4 
+0

Чтобы быть в безопасности, я также тестировал его, используя домен, как вы упомянули в своем вопросе. –

+0

Марк, ты мой герой! Ты спасаешь меня во второй раз. Я этого не забуду. Мой код был в порядке. Я просто забыл аннотировать поля uuid с аннотацией @Converter. В моих других AttibuteConverters есть (autoApply = true). .... –