Как-то не доводилось до этого, а тут понадобилось попользоваться декомпилятором Java. Понравился проект Java Decompiler - удобно и красиво получается. Есть отдельное GUI-приложение, а есть плагин для Eclipse.
Показаны сообщения с ярлыком java. Показать все сообщения
Показаны сообщения с ярлыком java. Показать все сообщения
вторник, декабря 11, 2012
среда, ноября 28, 2012
Преобразование java-объекта, списка java-объектов в JSON и из JSON
Пусть есть такой простой класс
class Book {
private String name;
private List authors;
...
}
Мне нужно отображать экземпляры этого класса либо список таких экземпляров в JSON и получать их из JSON обратно.
Попалась и понравилась библиотека Gson от гугла, с ней такие вещи делаются легко и удобно. К проекту нужно добавить одну jar-ку размером 185KB.
book.setName("Test Book");
book.addAuthor("A");
book.addAuthor("Б");
Gson gson = new Gson();
String result = gson.toJson(book);
В результате получаем:
{"name":"Test Book","authors":["A","Б"]}
class Book {
private String name;
private List
...
}
Мне нужно отображать экземпляры этого класса либо список таких экземпляров в JSON и получать их из JSON обратно.
Попалась и понравилась библиотека Gson от гугла, с ней такие вещи делаются легко и удобно. К проекту нужно добавить одну jar-ку размером 185KB.
Отображение одного объекта
Book book = new Book();book.setName("Test Book");
book.addAuthor("A");
book.addAuthor("Б");
Gson gson = new Gson();
String result = gson.toJson(book);
В результате получаем:
{"name":"Test Book","authors":["A","Б"]}
Восстановление объекта из JSON
book = gson.fromJson(result, Book.class);Отображение списка объектов
Book book2 = new Book();
book2.setName("Test Book 2");
book2.addAuthor("A2");
book2.addAuthor("Б2");
List books = new ArrayList();
books.add(book);
books.add(book2);
String booksStr = gson.toJson(books);
Получаем:
[{"name":"Test Book","authors":["A","Б"]},{"name":"Test Book 2","authors":["A2","Б2"]}]
Восстановление списка объектов
Type collectionType = new TypeToken
- >(){}.getType();
List gBooks = gson.fromJson(booksStr, collectionType);
Готово!
пятница, августа 03, 2012
Как сгенерировать SHA-1 дайджест по строке (в том числе и в Android)
public class SecurityUtils {
public static String getSHA1Digest(String str) throws NoSuchAlgorithmException {
if (str == null || str.trim().length() == 0) {
throw new InvalidParameterException("Не указано значение строки");
}
MessageDigest sha = MessageDigest.getInstance("SHA-1");
byte[] bytes = str.getBytes();
sha.update(bytes);
byte[] digest = sha.digest();
StringBuilder sb = new StringBuilder(40);
for (int i = 0; i < digest.length; i++) {
String hexVal = String.format("%02x", Integer.valueOf((digest[i] + 256) & 0xFF));
sb.append(hexVal);
}
return sb.toString();
}
}
Проверяем:
public class SHA1Test extends TestCase {
public void testSHA1() {
String sourceString = "12345";
String expectedResult = "8cb2237d0679ca88db6464eac60da96345513964";
String result = "";
try {
result = SecurityUtils.getSHA1Digest(sourceString);
} catch (NoSuchAlgorithmException e) {
assertTrue(e.getMessage(), false);
}
assertEquals(expectedResult, result);
}
пятница, апреля 06, 2012
Отформатировать копейки в рубли с разделителями групп и с точкой
Понадобилось отформатировать для вывода значения сумм в копейках.
При этом нужны разделители групп, а в качестве разделителя дробной части должна использоваться точка.
private static DecimalFormat currencyFormat;
static {
currencyFormat = new DecimalFormat();
DecimalFormatSymbols dfs = currencyFormat.getDecimalFormatSymbols();
dfs.setDecimalSeparator('.');
currencyFormat.setDecimalFormatSymbols(dfs);
currencyFormat.setMinimumFractionDigits(2);
currencyFormat.setMaximumFractionDigits(2);
currencyFormat.setGroupingSize(3);
currencyFormat.setGroupingUsed(true);
}
int amount = ...
double roubles = (double) amount / 100;
return currencyFormat.format( roubles );
При этом нужны разделители групп, а в качестве разделителя дробной части должна использоваться точка.
private static DecimalFormat currencyFormat;
static {
currencyFormat = new DecimalFormat();
DecimalFormatSymbols dfs = currencyFormat.getDecimalFormatSymbols();
dfs.setDecimalSeparator('.');
currencyFormat.setDecimalFormatSymbols(dfs);
currencyFormat.setMinimumFractionDigits(2);
currencyFormat.setMaximumFractionDigits(2);
currencyFormat.setGroupingSize(3);
currencyFormat.setGroupingUsed(true);
}
int amount = ...
double roubles = (double) amount / 100;
return currencyFormat.format( roubles );
четверг, августа 19, 2010
понедельник, июля 26, 2010
Как получить курсор из хранимой процедуры Oracle - SimpleJdbcCall
Понадобилось получить набор данных из хранимой процедуры Oracle. Данные получить эти надо в java-приложение.
Посмотрел несколько вариантов, наиболее симпатичным (что, впрочем, предсказуемо) оказался вариант и использованием спрингового SimpleJdbcCall.
Итак, есть такая табличка - разумеется, что здесь всё упрощено насколько это можно - и даже чуть более
CREATE TABLE BOOK (
ID INTEGER NOT NULL PRIMARY KEY,
NAME VARCHAR2(20))
Есть такая вот хранимая процедура
PROCEDURE GET_BOOKS_BY_NAME (book_cursor OUT SYS_REFCURSOR, name_template IN VARCHAR2)
IS
BEGIN
OPEN book_cursor FOR
SELECT b.ID as ID, b.NAME as NAME
FROM BOOK b
WHERE b.NAME LIKE name_template
ORDER BY ID;
END GET_BOOKS_BY_NAME;
Осталась самая малость - получить от этой процедуры содержимое курсора book_cursor.
Для начала, понадобится получить экземпляр SimpleJdbcCall. Его можно создать руками, можно прописать в контексте спринга - по вкусу.
Для представления данных удобно создать отдельный DTO
public class BookItem {
private Integer id;
private String name;
public BookItem() {}
// getters и setters опущены
}
На экземпляры этого класса будут отображены данные из получаемого курсора.
А теперь собираем всё вместе и получаем данные
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml");
SimpleJdbcCall simpleJdbcCall = context.getBean("simpleJdbcCall", SimpleJdbcCall.class);
// Этот экземпляр отвечает за отображение набора данных, полученных из
// базы данных в курсоре, на список объектов
RowMapper rowMapper = ParameterizedBeanPropertyRowMapper.newInstance(BookItem.class);
// Указывается имя вызываемой хранимой процедуры
simpleJdbcCall.withProcedureName("GET_BOOKS_BY_NAME");
// Связывается курсор, получаемый из хранимой процедуры, с отображателем
// данных
simpleJdbcCall.returningResultSet("BOOK_CURSOR", rowMapper);
// Задаются входные параметры для хранимой процедуры
SqlParameterSource params = new MapSqlParameterSource().addValue("NAME_TEMPLATE", "NEW%");
// Теперь производится непосредственный вызов хранимой процедуры.
// В возвращаемый в результате вызова map помещается имя курсора
// (параметр типа String) и сами полученные данные в виде ArrayList.
// Для того, чтобы эти данные из ArrayList разобрать, и используется
// rowMapper
Map resultMap = simpleJdbcCall.execute(params);
// При этом вызове производится отображение полученных данных на тип,
// указанный в параметре rowMapper
@SuppressWarnings("unchecked")
List resultList = (List) resultMap.get("BOOK_CURSOR");
// А теперь просто работаем с тем, что получили от БД
System.out.println("Получено записей: " + resultList.size());
for (BookItem item : resultList) {
System.out.println(item);
}
}
Вот и всё.
Посмотрел несколько вариантов, наиболее симпатичным (что, впрочем, предсказуемо) оказался вариант и использованием спрингового SimpleJdbcCall.
Итак, есть такая табличка - разумеется, что здесь всё упрощено насколько это можно - и даже чуть более
CREATE TABLE BOOK (
ID INTEGER NOT NULL PRIMARY KEY,
NAME VARCHAR2(20))
Есть такая вот хранимая процедура
PROCEDURE GET_BOOKS_BY_NAME (book_cursor OUT SYS_REFCURSOR, name_template IN VARCHAR2)
IS
BEGIN
OPEN book_cursor FOR
SELECT b.ID as ID, b.NAME as NAME
FROM BOOK b
WHERE b.NAME LIKE name_template
ORDER BY ID;
END GET_BOOKS_BY_NAME;
Осталась самая малость - получить от этой процедуры содержимое курсора book_cursor.
Для начала, понадобится получить экземпляр SimpleJdbcCall. Его можно создать руками, можно прописать в контексте спринга - по вкусу.
Для представления данных удобно создать отдельный DTO
public class BookItem {
private Integer id;
private String name;
public BookItem() {}
// getters и setters опущены
}
На экземпляры этого класса будут отображены данные из получаемого курсора.
А теперь собираем всё вместе и получаем данные
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml");
SimpleJdbcCall simpleJdbcCall = context.getBean("simpleJdbcCall", SimpleJdbcCall.class);
// Этот экземпляр отвечает за отображение набора данных, полученных из
// базы данных в курсоре, на список объектов
RowMapper
// Указывается имя вызываемой хранимой процедуры
simpleJdbcCall.withProcedureName("GET_BOOKS_BY_NAME");
// Связывается курсор, получаемый из хранимой процедуры, с отображателем
// данных
simpleJdbcCall.returningResultSet("BOOK_CURSOR", rowMapper);
// Задаются входные параметры для хранимой процедуры
SqlParameterSource params = new MapSqlParameterSource().addValue("NAME_TEMPLATE", "NEW%");
// Теперь производится непосредственный вызов хранимой процедуры.
// В возвращаемый в результате вызова map помещается имя курсора
// (параметр типа String) и сами полученные данные в виде ArrayList.
// Для того, чтобы эти данные из ArrayList разобрать, и используется
// rowMapper
Map
// При этом вызове производится отображение полученных данных на тип,
// указанный в параметре rowMapper
@SuppressWarnings("unchecked")
List
// А теперь просто работаем с тем, что получили от БД
System.out.println("Получено записей: " + resultList.size());
for (BookItem item : resultList) {
System.out.println(item);
}
}
Вот и всё.
воскресенье, июня 27, 2010
вторник, апреля 20, 2010
Apache Commons Lang - ToStringBuilder, формирование строки и форматы
Для определённости, возьём такой простой класс:
Я хочу для этого класса получить toString-like отображение.
Удобный для этого способ - взять и применить ToStringBuilder из библиотеки apache commons lang.
Полное имя этого класса - org.apache.commons.lang.builder.ToStringBuilder.
Способ №1 - руками переопределить метод toString и, с помощью этого класса, описать способ конструирования строкового отображения объектов. Ничего особо примечательного здесь нет, за исключением удобства, которое добавляет упомянутый ToStringBuilder.
А вот вид получаемой строки зависит от заданного на момент вызова стиля (формата). Примеры этих форматов - чуть низже.
Способ №2 интереснее - он использует reflection. В этом случае мне достаточно вызвать ToStringBuilder.reflectionToString(мой-объект), не занимаясь перечислением имён полей и их значений вручную.
Например, для такого случая
вызов
вернёт такой вот результат:
Да, вот эти >>> я добавил в результат сам, для удобства (моего) при чтении.
Есть несколько способов повлиять на формат получаемого результата.
Результат, показанный чуть выше, получен при использовании формата, используемого по-умолчанию. Имя этого формата - DEFAULT_STYLE.
Можно руками, вызвав статический метод, указать формат, который я хочу использовать:
А можно указать нужный формат явным образом, например, вот так:
Теперь самое интересное - какие форматы есть и как они влияют на результат.
DEFAULT_STYLE
MULTI_LINE_STYLE
SHORT_PREFIX_STYLE
NO_FIELD_NAMES_STYLE
SIMPLE_STYLE
class Book {
private String title;
private String author;
private Double price;
private Date publDate;
...
}Я хочу для этого класса получить toString-like отображение.
Удобный для этого способ - взять и применить ToStringBuilder из библиотеки apache commons lang.
Полное имя этого класса - org.apache.commons.lang.builder.ToStringBuilder.
Способ №1 - руками переопределить метод toString и, с помощью этого класса, описать способ конструирования строкового отображения объектов. Ничего особо примечательного здесь нет, за исключением удобства, которое добавляет упомянутый ToStringBuilder.
@Override
public String toString() {
return new ToStringBuilder(this)
.append("title", title)
.append("author", author)
.append("price", price)
.append("date", publDate)
.toString();
} А вот вид получаемой строки зависит от заданного на момент вызова стиля (формата). Примеры этих форматов - чуть низже.
Способ №2 интереснее - он использует reflection. В этом случае мне достаточно вызвать ToStringBuilder.reflectionToString(мой-объект), не занимаясь перечислением имён полей и их значений вручную.
Например, для такого случая
Book book = new Book();
book.setAuthor("Gregory M.");
book.setTitle("The Secret Book of Secrets");
book.setPrice(15.03);
book.setPublDate(null); // это специально, чтобы явно показать null-значениевызов
System.out.println(ToStringBuilder.reflectionToString(book));вернёт такой вот результат:
>>> javaapplication243.Book@10b30a7[title=The Secret Book of Secrets,author=Gregory M.,price=15.03,publDate=] Да, вот эти >>> я добавил в результат сам, для удобства (моего) при чтении.
Есть несколько способов повлиять на формат получаемого результата.
Результат, показанный чуть выше, получен при использовании формата, используемого по-умолчанию. Имя этого формата - DEFAULT_STYLE.
Можно руками, вызвав статический метод, указать формат, который я хочу использовать:
ToStringBuilder.setDefaultStyle(ToStringStyle.MULTI_LINE_STYLE);А можно указать нужный формат явным образом, например, вот так:
ToStringBuilder.reflectionToString(book, ToStringStyle.MULTI_LINE_STYLE) Теперь самое интересное - какие форматы есть и как они влияют на результат.
DEFAULT_STYLE
>>> javaapplication243.Book@10b30a7[title=The Secret Book of Secrets,author=Gregory M.,price=15.03,publDate=] MULTI_LINE_STYLE
>>> javaapplication243.Book@10b30a7[
title=The Secret Book of Secrets
author=Gregory M.
price=15.03
date=
]SHORT_PREFIX_STYLE
>>> Book[title=The Secret Book of Secrets,author=Gregory M.,price=15.03,publDate=] NO_FIELD_NAMES_STYLE
>>> javaapplication243.Book@10b30a7[The Secret Book of Secrets,Gregory M.,15.03,] SIMPLE_STYLE
>>> The Secret Book of Secrets,Gregory M.,15.03,
среда, апреля 14, 2010
Составной первичный ключ из двух FK
Встретился несколько необычный случай отображения данных.
На картинке показаны соответствующие таблицы.
В EVENT_KIND содержится список каких-то видов событий, а в VALID_EVENT_KIND - список допустимых сочетаний "предыдущий вид события" - "следующий тип события".
Если работа с EVENT_KIND типична и ничего интересного не представляет, то вот случай с VALID_EVENT_KIND - интереснее.
Классогенератор Netbeans отказыватеся генерировать для этой таблицы соответствующий Entity, резонно, в некотором смысле, сообщая о том, что это ведь обычная таблица связи (для отношения многие-ко-многим), а поэтому и сущность соответствующая не нужна. А раз не нужна, то и делать не буду (упорный, блин).
Другим интересным фактом является использование составного единственного ключа, который состоит из внешних ключей, ссылающихся на одну и ту же таблицу. Такое тоже встречается не часто.
Итак, раз для нас код сгенерировать отказались, остаётся написать его самому. К счастью, особо тут и писать нечего.
Вот так выглядит класс, соответствующий VALID_EVENT_KIND
А вот и описание самого первичного, embedded-ного, ключа:
Вот и всё...
На картинке показаны соответствующие таблицы.
В EVENT_KIND содержится список каких-то видов событий, а в VALID_EVENT_KIND - список допустимых сочетаний "предыдущий вид события" - "следующий тип события".
Если работа с EVENT_KIND типична и ничего интересного не представляет, то вот случай с VALID_EVENT_KIND - интереснее.
Классогенератор Netbeans отказыватеся генерировать для этой таблицы соответствующий Entity, резонно, в некотором смысле, сообщая о том, что это ведь обычная таблица связи (для отношения многие-ко-многим), а поэтому и сущность соответствующая не нужна. А раз не нужна, то и делать не буду (упорный, блин).
Другим интересным фактом является использование составного единственного ключа, который состоит из внешних ключей, ссылающихся на одну и ту же таблицу. Такое тоже встречается не часто.
Итак, раз для нас код сгенерировать отказались, остаётся написать его самому. К счастью, особо тут и писать нечего.
Вот так выглядит класс, соответствующий VALID_EVENT_KIND
@EntityНичего интересного, за исключением @EmbeddedId.
@Table(name="VALID_EVENT_KIND")
public class ValidEventKind implements Serializable {
@EmbeddedId
private ValidEventKindPk pk;
public ValidEventKind() {}
public ValidEventKind(EventKind prevEvent, EventKind nextEvent) {
this.pk = new ValidEventKindPk(prevEvent, nextEvent);
}
}
А вот и описание самого первичного, embedded-ного, ключа:
@EmbeddableРазные getters и setters в обоих классах я, очевидное дело, опустил.
public class ValidEventKindPk implements Serializable {
@ManyToOne()
@JoinColumn(name="prev_event", referencedColumnName="code")
private EventKind prevEventKind;
@ManyToOne
@JoinColumn(name="next_event", referencedColumnName="code")
private EventKind nextEventkind;
public ValidEventKindPk() { }
public ValidEventKindPk(EventKind prevEventKind, EventKind nextEventKind) {
this.prevEventKind = prevEventKind;
this.nextEventkind = nextEventKind;
}
}
Вот и всё...
Подписаться на:
Сообщения (Atom)
