Guava의 Joiner와 Splitter 중 잘 사용 중인 부분이다. 



package com.google;


import java.util.List;

import org.junit.Test;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;

public class JoinAndSplitTest {
@Test
public void JoinerTest() {
System.
out.println("== joiner demo ==");
Joiner
joiner = Joiner.on(", ").skipNulls();
String
names = joiner.join("Samuel", null, "Aston", "Kalley");
System.
out.println("names : " + names);

Joiner
joinerUsingNull = Joiner.on(", ").useForNull("N/A");
String
namesUsingNull = joinerUsingNull.join("Samuel", null, "Aston", "Kalley");
System.
out.println("names using null : " + namesUsingNull);

List<String>
list = Lists.newArrayList("1", "2", "3");
String
string = Joiner.on(",").join(list);
System.
out.println("list : " + string);
}

@Test
public void SplitterTest() {
System.
out.println("== splitter demo ==");
Iterable<String>
listByComma = Splitter.on(',')
    .trimResults()
   
//.omitEmptyStrings()
    .split(
"aston,samuel,,jason");
System.
out.println("* test1");
for (String string : listByComma) {
System.
out.println(string);
}

Iterable<String>
listByTab = Splitter.on('\t')
    .trimResults()
    .omitEmptyStrings()
    .split(
"aston samuel jason");
System.
out.println("* test2");
for (String string : listByTab) {
System.
out.println(string);
}

Iterable<String>
listByTabAndSpace = Splitter.on('\t')
    .trimResults()
    .omitEmptyStrings()
    .split(
"aston samuel     jason");
System.
out.println("* test3");
for (String string : listByTabAndSpace) {
System.
out.println(string);
}
}
}



결과


== joiner demo ==

names : Samuel, Aston, Kalley

names using null : Samuel, N/A, Aston, Kalley

list : 1,2,3

== splitter demo ==

* test1

aston

samuel


jason

* test2

aston

samuel

jason

* test3

aston

samuel

jason



이 것 말고, http request parameter를 만들 때처럼 joiner를 활용할 수 있다. 


예제

@Test
public void mapJoinTest() {
Map<String, String>
map =
    ImmutableMap.<String, String>builder()
        .put(
"name", "Samuel")
        .put(
"phone", "111")
        .put(
"address", "Sanfrancisco")
        .build();

String
joined = Joiner.on("&").withKeyValueSeparator("=").join(map);
System.
out.println("http://localhost/join.api?" + joined);
}



결과

http://localhost/join.api?name=Samuel&phone=111&address=Sanfrancisco



Posted by '김용환'
,



Guava에서 자주 사용하는 Maps api


http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Maps.html



Map을 생성/변환한다. TreeMap을 생성할 경우 Comparator나 SortedMap을 인자로 받을 수 있다.


Maps.newLinkedHashMap();

Maps.newTreeMap();

Maps.newTreeMap(Collections.reverseOrder());

Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER)

Maps.newHashMapWithExpectedSize(2);

Maps.newConcurrentMap();



Maps.filter*() 또는 Maps.uniqueIndex() 는 함수(function) 메소드를 사용해서 map의 submap을 얻어올 수 있으며,

properties에서 바로 map으로 읽어오는 Maps.fromProperties()도 있다. 




import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.collections.MapUtils;
import org.junit.Test;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;


public class MapsTest {
@Test
public void test() {

class Member {
int id;
String
name;
String
phone;

public Member(int id, String name, String phone) {
this.id = id;
this.name = name;
this.phone = phone;
}

@Override
public String toString() {
return com.google.common.base.Objects.toStringHelper(this).add("id", id).add("name", name).add("phone", phone).toString();
}
}

List<Member>
members = Lists.newArrayList();
members.add(new Member(3, "Kaley", "222"));
members.add(new Member(4, "Yong", "333"));
members.add(new Member(1, "Samuel", "000"));
members.add(new Member(0, "Jason", "111"));

Map<Integer, Member>
memberById = Maps.uniqueIndex(members, new Function<Member, Integer>() {
@Override
public Integer apply(Member member) {
return member.id;
}
});

MapUtils.debugPrint(System.
out, "member by id ", memberById);

// filterKey, filterValue도 비슷한 형태
Map<Integer, Member>
filteredMemberById = Maps.filterEntries(memberById, new Predicate<Map.Entry<Integer, Member>>() {
@Override
public boolean apply(Map.Entry<Integer, Member> input) {
return input.getValue().name.contains("Yong");
}
});

MapUtils.debugPrint(System.
out, "filted member by id ", filteredMemberById);
}

@Test
public void mapsPropertiesTest() {
Properties
properties = new Properties();
properties.put("replicated.cache.url", "redis://1.1.1.2/0");
properties.put("origin.cache.url", "redis://1.1.1.1/0");

Map<String, String>
maps = Maps.fromProperties(properties);
MapUtils.debugPrint(System.
out, "map from properties", maps);
}
}


결과

map from properties = 

{

    replicated.cache.url = redis://1.1.1.2/0 java.lang.String

    origin.cache.url = redis://1.1.1.1/0 java.lang.String

} com.google.common.collect.RegularImmutableMap

member by id  = 

{

    3 = Member{id=3, name=Kaley, phone=222} com.google.tag.location.MapsTest$1Member

    4 = Member{id=4, name=Yong, phone=333} com.google.tag.location.MapsTest$1Member

    1 = Member{id=1, name=Samuel, phone=000} com.google.tag.location.MapsTest$1Member

    0 = Member{id=0, name=Jason, phone=111} com.google.tag.location.MapsTest$1Member

} com.google.common.collect.RegularImmutableMap

filted member by id  = 

{

    4 = Member{id=4, name=Yong, phone=333} com.google.tag.location.MapsTest$1Member

} com.google.common.collect.Maps$FilteredEntryMap



Maps.filterValues()도 쓰인다. null이 아닌 것만 저장하고 싶을 때, Predicate 클래스를 활용하여 사용할 수 있다. 


objectMap = Maps.filterValues(objectMap, new Predicate<Object>() {
  @Override
        public boolean apply(Object object) {
       
return object != null;
}
});





Posted by '김용환'
,


https://guava-libraries.googlecode.com/svn/tags/release04/javadoc/com/google/common/collect/Sets.html


Set instace 생성/변환할 때 사용한다. 


Sets.newCopyOnWriteArraySet()

Sets.newConcurrentHashSet()

Sets.newLinkedHashSet()

Sets.newTreeSet()

Sets.newHashSet()

Sets.newHashSetWithExpectedSize(members.size())

Sets.immutableEnumSet(encodeKey)  



가장 많이 유용한 것은 Set간의 intersection, union이다. 


@Test
public void test() {

Set<String>
set1 = new HashSet<String>();
set1.add("a");
set1.add("b");
set1.add("c");

Set<String>
set2 = new HashSet<String>();
set2.add("c");
set2.add("d");
set2.add("e");

Set<String>
intersection = Sets.intersection(set1, set2);
System.
out.println(Arrays.toString(intersection.toArray()));

Set<String>
union = Sets.union(set1, set2);
System.
out.println(Arrays.toString(union.toArray()));
}



결과

[c]

[b, c, a, d, e]

Posted by '김용환'
,


Java에서 Object의 comparator를 여러 번을 사용하여 Object를 소팅하기 위해서는

Guava의 Ordering 클래스의 from()와 compound() 메소드를 이용해서 쉽고 간결하게 소팅을 할 수 있다. 



Ordering<Member> ordering = Ordering.from(new MemberById()).compound(new MemberBySubId());

Collections.sort(members, ordering);



예제) 



import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.junit.Test;

import com.google.common.collect.Lists;

import com.google.common.collect.Ordering;

import com.google.common.primitives.Ints;


public class OrderingTest {
@Test
public void test() {

Member
member1 = new Member();
member1.id = 100;
member1.subId = 3;

Member
member2 = new Member();
member2.id = 50;
member2.subId = 20;

Member
member3 = new Member();
member3.id = 100;
member3.subId = 1;

Member
member4 = new Member();
member4.id = 1;
member4.subId = 1;

Member
member5 = new Member();
member4.id = 100;
member4.subId = 2;

List<Member>
members = Lists.newArrayList(member1, member2, member3, member4, member5);

Ordering<Member>
ordering = Ordering.from(new MemberById()).compound(new MemberBySubId());
Collections.sort(
members, ordering);
System.
out.println(members);

}
}


class MemberBySubId implements Comparator<Member> {
@Override
public int compare(Member member1, Member member2) {
return Ints.compare(member1.subId, member2.subId);
}
}


class MemberById implements Comparator<Member> {

@Override
public int compare(Member member1, Member member2) {
return Ints.compare(member1.id, member2.id);
}

}


class Member {
int id;
int subId;

@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}




결과

[id=0,subId=0], [id=50,subId=20], [id=100,subId=1], [id=100,subId=2],[id=100,subId=3]]


Posted by '김용환'
,




Window – Preferences – Java – Editor – Save Actions 선택


Perform the selected actions on save 선택하고, Configure 버튼 선택


Code Organizing 탭에서 Remove tailing whitespace 에서 All lines 선택 하고 저장






Posted by '김용환'
,


java에서 다음 에러 발생했다. 


Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path, preempting StackOverflowError.>

at org.apache.log4j.Log4jLoggerFactory.<clinit>(Log4jLoggerFactory.java:51)



이런 문제는 간단히 둘 중 하나를 정리한다. 나는 slf4j-log4j12를 제외시킨다. 


<exclusion>

      <groupId>org.slf4j</groupId>

      <artifactId>slf4j-log4j12</artifactId>

</exclusion>



참조)
http://www.slf4j.org/codes.html#log4jDelegationLoop

Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path, preempting StackOverflowError.

The purpose of slf4j-log4j12 module is to delegate or redirect calls made to an SLF4J logger to log4j. The purpose of the log4j-over-slf4j module is to redirect calls made to a log4j logger to SLF4J. If both slf4j-log4j12.jar and log4j-over-slf4j.jar are present on the class path, a StackOverflowError will inevitably occur immediately after the first invocation of an SLF4J or a log4j logger.


원인은 log4j -> slf4j, slf4j-> log4j로 가는 라이브러리 때문인데.. 무한 루프를 방지하는 코드에서 발견된 것..
따라서 프로젝트가 slf4j만 쓰기로 했다면.. lib 추가할 때(또는 에러가 발생할 때)마다 mvm dependency:tree 하는 습관이 필요하다. 하나의 log정책을 사용할 필요가 있다. 따라서 slf4j로 하나로 묶어 logback을 쓰는 방식을 쓰는 정책을 사용한다고 가정한다면, 관련 lib 정책을 잘 살펴볼 필요가 있다. (아래 그림 참조)


http://www.slf4j.org/images/legacy.png


비슷한 이슈는 또 있다..

참조 )http://www.slf4j.org/codes.html 

jul-to-slf4j.jar and slf4j-jdk14.jar cannot be present simultaneously

The presence of slf4j-jdk14.jar, that is the jul binding for SLF4J, will force SLF4J calls to be delegated to jul. On the other hand, the presence of jul-to-slf4j.jar, plus the installation of SLF4JBridgeHandler, by invoking "SLF4JBridgeHandler.install()" will route jul records to SLF4J. Thus, if both jar are present simultaneously (and SLF4JBridgeHandler is installed), slf4j calls will be delegated to jul and jul records will be routed to SLF4J, resulting in an endless loop.






Posted by '김용환'
,

play 1.2.5.x는 python 2.4에도 동작한다. 
https://github.com/yalpframework/yalp/issues/1


그러나 java 8 & play 1.3.0 에서는 python 2.4에서 동작하지 않는다. 
python은 리눅스에 중요한 언어이고 라이브러리이기 때문에 library up하다가 꼬이는 경우가 많다.
삭제하려고 하다가 dependency가 있는 라이브러리를 모두 삭제할 수 있다.(ssh까지 다 지운다.)

따라서, 리눅스를 다시 설치하고 play 1.3.0을 실행시키는 것이 효율적인 것 같다.



Posted by '김용환'
,



dynamic하게 bean 을 생성하는 법은 두 가지 (BeanFactoryPostProcessor, BeanPostProcessor)를 활용한 방식이다. 


1. BeanFactoryPostProcessor

예제)
http://random-thoughts-vortex.blogspot.kr/2009/03/create-dynamically-spring-beans.html

API)
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/beans/factory/config/BeanFactoryPostProcessor.html



2. BeanPostProcessor

예제)
http://www.springindepth.com/book/in-depth-ioc-bean-post-processors-and-beanFactory-post-processors.html

API)
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/beans/factory/config/BeanPostProcessor.html


참골, ConfigurableListableBeanFactory 는 SingletonBeanRegistry를 상속받았기 때문에 singleton bean을 container에 추가할 수 있다. 특이한 것은 BeanDefinition과 무관하게 임의의 이름으로 spring container에 추가할 수 있다는 큰 장점이 있다. 

http://srcrr.com/java/spring/3.1.0/reference/org/springframework/beans/factory/config/ConfigurableListableBeanFactory.html


아래 예제는 SimpleBean에 임의의 이름 xxxxxsimplebean으로 SimpleBean 을 Binding하였다. ConfigurableListableBeanFactory.registerSingleton() 메소드는 BeanDefinition과 상관없다. 따라서 ApplicationContext.removeBeanDefinition()을 호출하면, "org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'xxxxxsimplebean' is defined"이 발생한다. 

* SimpleBean.java

public class SimpleBean {
    public void print() {
        System.
out.println("Simple Bean!");
    }
}


* 코드 


@Test
public void test() {
    StaticApplicationContext
applicationContext = new StaticApplicationContext();
    ConfigurableListableBeanFactory
beanFactory = applicationContext.getBeanFactory();
 
beanFactory.registerSingleton("xxxxxsimplebean", new SimpleBean());
  SimpleBean
bean = (SimpleBean)applicationContext.getBean("xxxxxsimplebean");
 
bean.print();
 

  SimpleBean bean1 = (SimpleBean) beanFactory.getSingleton("xxxxxsimplebean");

  bean1.print();

 
// applicationContext.removeBeanDefinition("xxxxxsimplebean"); // 에러
 
applicationContext.close();
}


* 결과 화면


Simple Bean!
Simple Bean!



Posted by '김용환'
,

[Guava] HashBiMap

general java 2015. 3. 25. 15:25


key가 같으면 override하고,  value의 값이 같으면 에러난다.


@Test 

public void test_hashbiTest() {

BiMap<String, String> biMap = HashBiMap.create();

biMap.put("1", "One");

biMap.put("2", "Two");


//biMap.put("3", "One"); // error

MapUtils.debugPrint(System.out, "", biMap.inverse());

}


결과


{

    Two = 2 java.lang.String

    One = 1 java.lang.String

} com.google.common.collect.HashBiMap$Inverse



만약 value 의 값이 같으면 다음 에러가 발생한다.

java.lang.IllegalArgumentException: value already present: One

at com.google.common.collect.HashBiMap.put(HashBiMap.java:238)

at com.google.common.collect.HashBiMap.put(HashBiMap.java:215)



용도 : host/ip address 같은 map

Posted by '김용환'
,


godeps는 github dependency 관리를 이렇게 할 수 있다. 


https://github.com/tools/godep


{
    "ImportPath": "github.com/kr/hk",
    "GoVersion": "go1.1.2",
    "Deps": [
        {
            "ImportPath": "code.google.com/p/go-netrc/netrc",
            "Rev": "28676070ab99"
        },
        {
            "ImportPath": "github.com/kr/binarydist",
            "Rev": "3380ade90f8b0dfa3e363fd7d7e941fa857d0d13"
        }
    ]
}



비슷하게 maven에서도 쓸 수 있다. 

https://jitpack.io/




  1. Add repository first
<repository>
    <id>jitpack.io</id>
    <url>https://jitpack.io</url>
</repository>
  1. Add dependency
<dependency>
    <groupId>com.github.User</groupId>
    <artifactId>Repo name</artifactId>
    <version>Release tag</version>
</dependency>


Posted by '김용환'
,