использовать коррелированный подзапрос
select t1.* from mytable t1
where not exists ( select 1 from mytable t2 where t2.column2=t1.column2 and column1='A')
или использовать not in
select t1.* from table_name t1 where t1.column2 not in ( select column2 from table_name where column1='A')
Это возможно. Я использовал это, чтобы monkeypatch порочные потоки, которые предотвращали выгрузку классов в веб-приложениях. Вам просто нужно использовать отражение, чтобы удалить модификатор final
, затем вы можете изменить поле.
Что-то вроде этого поможет:
private void killThreadLocal(String klazzName, String fieldName) {
Field field = Class.forName(klazzName).getDeclaredField(fieldName);
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
int modifiers = modifiersField.getInt(field);
modifiers &= ~Modifier.FINAL;
modifiersField.setInt(field, modifiers);
field.set(null, null);
}
Также есть некоторое кеширование вокруг Field #set
, поэтому, если какой-то код выполнялся раньше, он может не обязательно работать ....
Любая инфраструктура AOP будет соответствовать вашим потребностям
Она позволит вам определить переопределение времени выполнения для метода getInstance, позволяющего Вы должны вернуть любой класс, который соответствует вашим потребностям.
Jmockit использует инфраструктуру ASM для того же.
Вы можете попробовать следующее. Примечание. Это не совсем потокобезопасно, и это не работает для константных примитивов, известных во время компиляции (поскольку они встроены компилятором)
Field field = SomeClass.class.getDeclareField("INSTANCE");
field.setAccessible(true); // what security. ;)
field.set(null, newValue);
Если вы действительно должны (хотя для нашей проблемы я бы посоветовал вам использовать решение CaptainAwesomePants) вы мог бы взглянуть на JMockIt . Хотя это предназначено для использования в модульных тестах, если позволяет переопределить произвольные методы. Это делается путем изменения байт-кода во время выполнения.
Я предвосхищу этот ответ, признав, что на самом деле это не ответ на заданный вами вопрос об изменении приватного статического финала поле. Однако в приведенном выше конкретном примере кода я могу сделать так, чтобы вы могли переопределить doSomething (). Что вы можете сделать, так это воспользоваться тем, что getInstance () является открытым методом и подклассом:
public class MySomeClass extends SomeClass
{
private static final INSTANCE = new MySomeClass();
public SomeClass getInstance() {
return INSTANCE;
}
public Object doSomething() {
//Override behavior here!
}
}
Теперь просто вызовите MySomeClass.getInstance () вместо SomeClass.getInstance (), и все готово. Конечно, это работает, только если вы тот, кто вызывает getInstance (), а не какую-то другую часть неизменяемого материала, с которым вы работаете.
Если нет Доступен внешний взлом (по крайней мере, я не в курсе) Я бы взломал сам класс. Измените код, добавив необходимую проверку безопасности. Так как это внешняя библиотека, вы не будете регулярно получать обновления, также не так много обновлений в любом случае. Всякий раз, когда это происходит, я с радостью могу сделать это заново, так как в любом случае это не большая задача.
Вы должны быть в состоянии изменить его с помощью JNI ... не уверен, что это вариант для вас.
РЕДАКТИРОВАТЬ: это возможно, но не очень хорошая идея.
http://java.sun.com/docs/books/jni/html/pitfalls.html
10.9 Нарушение правил контроля доступа
JNI не применяет класс, поле, и метод контроля доступа ограничения что можно выразить на Яве уровень языка программирования через использование модификаторов, таких как частные и окончательный. Можно написать родной код для доступа или изменения полей возражать, хотя делает это на Уровень языка программирования Java будет привести к IllegalAccessException. Вседозволенность JNI была сознательной дизайнерское решение, учитывая, что родной код может получить доступ и изменить любую память в любом случае, местоположение в куче.
Собственный код, который обходит проверки доступа на уровне исходного языка может иметь нежелательные последствия для выполнение программы. Например, несоответствие может быть создано, если нативный метод изменяет конечное поле после JIT-компилятора имеет встроенный доступ к полю. Аналогично, нативные методы не должны изменить неизменяемые объекты, такие как поля в случаях java.lang.String или java.lang.Integer. Это может привести к поломке инварианты в платформе Java реализация.
Здесь ваша проблема - старый добрый Инъекция зависимостей (иначе говоря, инверсия контроля). Ваша цель должна заключаться в том, чтобы внедрить вашу реализацию SomeClass
вместо того, чтобы устанавливать ее вручную. И да, этот подход требует некоторых изменений в вашем существующем дизайне, но по правильным причинам (назовите ваш любимый принцип дизайна здесь) - особенно один и тот же объект не должен отвечать за создание и использование других объектов.
Я предполагаю, что вы используете SomeClass
выглядит примерно так:
public class OtherClass {
public void doEverything() {
SomeClass sc = SomeClass.geInstance();
Object o = sc.doSomething();
// some more stuff here...
}
}
Вместо этого вам следует сначала создать свой класс, который реализует тот же интерфейс или расширяет SomeClass
и затем передать этот экземпляр в doEverything ()
, чтобы ваш класс стал независимым от реализации SomeClass
. В этом случае код, который вызывает doEverything
, ответственен за передачу в правильной реализации - будь то фактический SomeClass
или ваш обезьяновый патч MySomeClass
.
public class MySomeClass() extends SomeClass {
public Object doSomething() {
// your monkeypatched implementation goes here
}
}
public class OtherClass {
public void doEveryting(SomeClass sc) {
Object o = sc.doSomething();
// some more stuff here...
}
}
на mockito очень прост:
import static org.mockito.Mockito.*;
public class SomeClass {
private static final SomeClass INSTANCE = new SomeClass();
public static SomeClass getInstance() {
return INSTANCE;
}
public Object doSomething() {
return "done!";
}
public static void main(String[] args) {
SomeClass someClass = mock(SomeClass.getInstance().getClass());
when(someClass.doSomething()).thenReturn("something changed!");
System.out.println(someClass.doSomething());
}
}
этот код печатает «что-то изменилось!»; Вы можете легко заменить свои экземпляры-одиночки. Мои 0,02 цента.