2016-03-15 9 views
1

У меня есть два класса Stream и Lake, которые распространяются на WaterBody. Stream или Lake хранятся в сеансе, управляемом Apache Shiro 1.2.4 для последующего использования.Объект, хранящийся в сеансе, не будет соответствовать тому же классу после повторного развертывания проекта

WaterBody lake = new Lake(); 
session.setAttribute("water", lake);` 

и получить его с помощью

WaterBody water = (WaterBody) session.getAttribute("water"); 

На новый старт сервера Wildfly 9.0.2 я могу хранить магазину объекты просто отлично на сессию и получить их просто отлично. Не имеет значения, сохраняю ли я Lake или Stream атрибуту сеанса water. Однако после повторного развертывания проекта без перезагрузки сервера Wildfly я могу сохранить для атрибута сеанса water тот же тип класса, что и раньше, т.е.: не удается сохранить Lake, а затем переустановить, а затем сохранить Stream. Я получаю эту ошибку:

java.lang.ClassCastException: cannot assign instance of [Lfwp.fish.water.HydroUnit; to field fwp.fish.water.WaterBody.hucs of type [Lfwp.fish.water.HydroUnit; in instance of fwp.fish.water.Stream 

Класс WaterBody имеет методы получения и установки для частного поля типа HydroUnit и поскольку это inheritied обоими Stream и Lake ошибка имеет мало смысла.

Если на свежем начать атрибут water сессии назначается как же класс до и после повторного развёртывания будет присвоить значение переменного сеанса просто отлично, а затем при извлечении он будет бросать эту ошибку:

java.lang.ClassCastException: fwp.fish.water.Lake cannot be cast to fwp.fish.water.WaterBody 

С Lake распространяется WaterBody у него не должно быть проблем.

С Shiro мы используем ehcache 2.9 для кеша сеанса.

Похоже, что serialVersionUID игнорируется кешем, или он генерирует другую за кулисами, и он думает, что классы изменились, когда они не связаны между перераспределениями.

Классы:

public class WaterBody implements Serializable { 
    private static final long serialVersionUID = -5481729151007010163L; 
    private int id; 
    private HydroUnit[] hucs; 

    public WaterBody() { 
    } 

    public int getId() { 
     return id; 
    } 

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

    public HydroUnit[] getHucs() { 
     return hucs; 
    } 

    public void setHucs(HydroUnit[] hucs) { 
     this.hucs = hucs; 
    } 
} 

public class Lake extends WaterBody { 
    private static final long serialVersionUID = -925557850476426686L; 
    private String centroidLatitude; 
    private String centroidLongitude; 

    public Lake(){ 
     super();  
    } 

    public String getCentroidLatitude() { 
     return centroidLatitude; 
    } 

    public void setCentroidLatitude(String centroidLatitude) { 
     this.centroidLatitude = centroidLatitude; 
    } 

    public String getCentroidLongitude() { 
     return centroidLongitude; 
    } 

    public void setCentroidLongitude(String centroidLongitude) { 
     this.centroidLongitude = centroidLongitude; 
    } 
} 

public class Stream extends WaterBody { 
    private static final long serialVersionUID = 2556033593701784053L; 
    private String mouthLatitude; 
    private String mouthLongitude; 

    public Stream(){ 
     super();  
    } 

    public String getMouthLatitude() { 
     return mouthLatitude; 
    } 

    public void setMouthLatitude(String mouthLatitude) { 
     this.mouthLatitude = mouthLatitude; 
    } 

    public String getMouthLongitude() { 
     return mouthLongitude; 
    } 

    public void setMouthLongitude(String mouthLongitude) { 
     this.mouthLongitude = mouthLongitude; 
    } 
} 
+0

Учитывайте возможность перезагрузки _Class_ и повторного создания объекта класса. Это может привести к тому, что два экземпляра _object_ считаются несовместимыми, даже если они, похоже, имеют один и тот же класс. Лучшим способом устранения этого является остановка кода перед исключением и сравнение классов двух экземпляров, чтобы увидеть, являются ли они тем же самым классом. –

+0

Это то, что я сделал, и кажется, что это тот же самый класс, что и перед отливом. Если вы делаете 'Object water = session.getAttribute (« вода »);' И проверяйте объект 'water', у которого, похоже, есть все те же критерии, что и то, что нужно, а если вы выполняете проверку' instanceof' 'WaterBody' он потерпит неудачу. Мне, вероятно, нужно пройти через это с помощью тонкой зубной гребенки перед повторным развертыванием и после того, когда это будет тот объект, чтобы увидеть, есть ли какая-либо разница вообще. –

+0

Как указано выше, просто сравнивая объект с глазу, объект воды, когда он вытаскивается из сеанса, выглядит точно таким же, как когда он застрял даже после повторного развертывания. Я также проверил, что использовал «ClassLoader», и во всех случаях он дает мне «ModuleClassLoader for Module» deploy.fish.war: main «из загрузчика сервисного модуля», поэтому кажется, что там нет никакой несогласованности. –

ответ

0

После исследования в вопрос это то, что мы нашли. Когда проект запускается в первый раз, ClassLoader создает классы, когда они используются, а затем сохраняет объекты в сеансе. После горячей пересылки этого проекта во время работы сервера, когда дело доходит до загрузки Class, ClassLoader создает новый экземпляр этого Class. Однако сеанс по-прежнему запоминает Class с последнего момента, когда объект этого Class был сохранен и иногда позволяет новым объектам быть сохраненными в сеансе, появляющемся как тот же самый объект. Но после извлечения объекта он все еще определяется старым экземпляром этого Class и, таким образом, при попытке передать его текущему экземпляру этого Class он потерпит неудачу.

Наше решение предназначено для проектов, имеющих объекты, хранящиеся в сеансе, для разделения классов, которые будут храниться как объекты в сеансе, в отдельный модуль .jar, включенный в проект, который перераспределяется. Таким образом, если есть изменения в файлах Class, сервер должен быть перезапущен в любом случае, так как есть изменения в зависимости от модуля.Теперь, если проект горячо перераспределен, классы остаются нетронутыми, так как они не находятся в обновленном файле .war.