├── README.md ├── .gitignore ├── circle.yml ├── java ├── src │ └── org │ │ └── nutz │ │ └── mongo │ │ ├── interceptor │ │ ├── MongoInterceptor.java │ │ ├── ZOperationExecutor.java │ │ ├── impl │ │ │ └── LogMongoInterceptor.java │ │ └── MongoInterceptorChain.java │ │ ├── adaptor │ │ ├── ZMoPojoAdaptor.java │ │ ├── ZMoSimpleAdaptor.java │ │ ├── ZMoEnumAdaptor.java │ │ ├── ZMoSmartAdaptor.java │ │ ├── ZMoMapAdaptor.java │ │ ├── ZMoIdAdaptor.java │ │ ├── ZMoDBObjectAdaptor.java │ │ ├── ZMoAs.java │ │ ├── ZMoCollectionAdaptor.java │ │ └── ZMoArrayAdaptor.java │ │ ├── annotation │ │ ├── MoIgnore.java │ │ ├── MoEnum.java │ │ └── MoField.java │ │ ├── fieldfilter │ │ ├── ZMoRegexFF.java │ │ ├── ZMoSimpleFF.java │ │ └── ZMoFF.java │ │ ├── entity │ │ ├── ZMoGeneralMapField.java │ │ ├── ZMoEntityHolder.java │ │ ├── ZMoGeneralMapEntity.java │ │ ├── ZMoField.java │ │ ├── ZMoEntity.java │ │ └── ZMoEntityMaker.java │ │ ├── ZMongoDB2.java │ │ ├── ZMoAdaptor.java │ │ ├── mr │ │ ├── ZMoMapReduce.java │ │ └── ZMoMapReduceManager.java │ │ ├── ZMoDB.java │ │ ├── ZMongo.java │ │ ├── ZMo.java │ │ ├── ZMoDoc.java │ │ └── ZMoCo.java ├── test │ └── org │ │ └── nutz │ │ └── mongo │ │ ├── AllZMoTest.java │ │ ├── pojo │ │ ├── PetType.java │ │ ├── PetColor.java │ │ ├── Pet2.java │ │ ├── Human.java │ │ └── Pet.java │ │ ├── ZMoBaseTest.java │ │ ├── ZMoDocTest.java │ │ └── ZMoPetTest.java └── build │ └── build.xml ├── mvn_settings.py ├── .travis.yml ├── pom.xml └── mvn_settings.xml /README.md: -------------------------------------------------------------------------------- 1 | move to https://github.com/nutzam/nutzmore/tree/master/nutz-plugins-mongodb 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | .classpath 3 | .project 4 | .settings 5 | *.DS_Store 6 | /target 7 | .idea 8 | *.iml 9 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | timezone: Asia/Shanghai 3 | java: 4 | version: oraclejdk8 5 | 6 | general: 7 | branches: 8 | only: 9 | - master 10 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/interceptor/MongoInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.interceptor; 2 | 3 | public interface MongoInterceptor { 4 | 5 | void filter(MongoInterceptorChain chain); 6 | } 7 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/adaptor/ZMoPojoAdaptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.adaptor; 2 | 3 | public class ZMoPojoAdaptor extends ZMoMapAdaptor { 4 | 5 | ZMoPojoAdaptor() { 6 | super(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /java/test/org/nutz/mongo/AllZMoTest.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.junit.runners.Suite; 5 | 6 | @RunWith(Suite.class) 7 | @Suite.SuiteClasses({ZMoDocTest.class, ZMoPetTest.class}) 8 | public class AllZMoTest {} 9 | -------------------------------------------------------------------------------- /java/test/org/nutz/mongo/pojo/PetType.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.pojo; 2 | 3 | public enum PetType { 4 | 5 | // 0 6 | DOG, 7 | 8 | // 1 9 | CAT, 10 | 11 | // 2 12 | CROCDILE, 13 | 14 | // 3 15 | PYTHON, 16 | 17 | // 4 18 | HAMSTER 19 | } 20 | -------------------------------------------------------------------------------- /java/test/org/nutz/mongo/pojo/PetColor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.pojo; 2 | 3 | public enum PetColor { 4 | 5 | // 0 6 | RED, 7 | 8 | // 1 9 | BLUE, 10 | 11 | // 2 12 | GREEN, 13 | 14 | // 3 15 | GRAY, 16 | 17 | // 4 18 | WHITE, 19 | 20 | // 5 21 | BLACK, 22 | 23 | // 6 24 | OTHER 25 | 26 | } 27 | -------------------------------------------------------------------------------- /mvn_settings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import os 4 | import os.path 5 | import xml.dom.minidom 6 | import subprocess 7 | 8 | if "1.8.0" in subprocess.check_output("java -Xmx32m -version", shell=1, stderr=subprocess.STDOUT) : 9 | subprocess.check_call("mvn -Dmaven.test.skip=true clean source:jar deploy --settings mvn_settings.xml", shell=1, stderr=subprocess.STDOUT) 10 | else : 11 | print "not java 8" -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/annotation/MoIgnore.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * 如果声明了这个属性的字段,不被当做映射实体 11 | * 12 | * @author zozoh(zozohtnt@gmail.com) 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ElementType.FIELD, ElementType.METHOD}) 16 | @Documented 17 | public @interface MoIgnore {} 18 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/fieldfilter/ZMoRegexFF.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.fieldfilter; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | /** 6 | * 根据给定的正则表达式,来判断Java字段或者Mongo字段是否忽略该字段 7 | * 8 | * @author zozoh(zozohtnt@gmail.com) 9 | */ 10 | public class ZMoRegexFF extends ZMoFF { 11 | 12 | private Pattern regex; 13 | 14 | public ZMoRegexFF(String regex) { 15 | super(); 16 | this.regex = Pattern.compile(regex); 17 | } 18 | 19 | @Override 20 | public boolean match(String fld) { 21 | return regex.matcher(fld).find(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/annotation/MoEnum.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * 对枚举类型字段的补充说明 11 | *

12 | * 指明这个字段映射的时候,是要转换成数字还是字符串 13 | * 14 | * @author zozoh(zozohtnt@gmail.com) 15 | */ 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Target({ElementType.FIELD, ElementType.METHOD}) 18 | @Documented 19 | public @interface MoEnum { 20 | 21 | boolean str() default true; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/entity/ZMoGeneralMapField.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.entity; 2 | 3 | import org.nutz.mongo.ZMoAdaptor; 4 | import org.nutz.mongo.adaptor.ZMoAs; 5 | 6 | public class ZMoGeneralMapField extends ZMoField { 7 | 8 | @Override 9 | public boolean isEnumStr() { 10 | return true; 11 | } 12 | 13 | @Override 14 | public void setEnumStr(boolean isEnumString) {} 15 | 16 | @Override 17 | public ZMoField clone() { 18 | return new ZMoGeneralMapField(); 19 | } 20 | 21 | @Override 22 | public ZMoAdaptor getAdaptor() { 23 | return ZMoAs.smart(); 24 | } 25 | 26 | @Override 27 | public void setAdaptor(ZMoAdaptor adaptor) {} 28 | 29 | } 30 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/annotation/MoField.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * MongoDB 的字段映射关系 11 | * 12 | * @author zozoh(zozohtnt@gmail.com) 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ElementType.FIELD, ElementType.METHOD}) 16 | @Documented 17 | public @interface MoField { 18 | 19 | /** 20 | * 空字符串,表示采用 Java 字段原名 21 | */ 22 | String value() default ""; 23 | 24 | /** 25 | * 特殊声明一下当前字段的实现类,默认为 Object.class 表示 ZMo 自行决定 26 | */ 27 | Class type() default Object.class; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/fieldfilter/ZMoSimpleFF.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.fieldfilter; 2 | 3 | import java.util.List; 4 | 5 | import org.nutz.lang.Lang; 6 | 7 | /** 8 | * 根据给定的 java 字段名字,来判断是否忽略该字段 9 | * 10 | * @author zozoh(zozohtnt@gmail.com) 11 | */ 12 | public class ZMoSimpleFF extends ZMoFF { 13 | 14 | private String[] names; 15 | 16 | /** 17 | * @param names 18 | * 给定一个字段名称列表(大小写敏感) 19 | */ 20 | public ZMoSimpleFF(String... names) { 21 | super(); 22 | this.names = names; 23 | } 24 | 25 | public ZMoSimpleFF(List names) { 26 | this.names = names.toArray(new String[names.size()]); 27 | } 28 | 29 | @Override 30 | public boolean match(String fld) { 31 | return Lang.contains(names, fld); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/adaptor/ZMoSimpleAdaptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.adaptor; 2 | 3 | import org.nutz.castor.Castors; 4 | import org.nutz.lang.Mirror; 5 | import org.nutz.mongo.ZMoAdaptor; 6 | import org.nutz.mongo.entity.ZMoField; 7 | 8 | public class ZMoSimpleAdaptor implements ZMoAdaptor { 9 | 10 | ZMoSimpleAdaptor() {} 11 | 12 | @Override 13 | public Object toJava(ZMoField fld, Object obj) { 14 | if (null == fld || obj == null) 15 | return obj; 16 | Mirror mirror = fld.getMirror(); 17 | if (null != mirror && (mirror.isArray() || mirror.isCollection())) { 18 | return Castors.me().castTo(obj, fld.getEleType()); 19 | } 20 | return Castors.me().castTo(obj, fld.getType()); 21 | } 22 | 23 | @Override 24 | public Object toMongo(ZMoField fld, Object obj) { 25 | return obj; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/ZMongoDB2.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import org.nutz.log.Log; 4 | import org.nutz.log.Logs; 5 | 6 | import com.mongodb.CommandResult; 7 | import com.mongodb.DB; 8 | import com.mongodb.DBEncoder; 9 | import com.mongodb.DBObject; 10 | import com.mongodb.Mongo; 11 | import com.mongodb.ReadPreference; 12 | 13 | public class ZMongoDB2 extends DB { 14 | 15 | private static final Log log = Logs.get(); 16 | 17 | public ZMongoDB2(Mongo mongo, String name) { 18 | super(mongo, name); 19 | } 20 | 21 | @Override 22 | public CommandResult command(DBObject command, 23 | ReadPreference readPreference, 24 | DBEncoder encoder) { 25 | if (log.isDebugEnabled()) 26 | log.debug("cmd= " + command.toString()); 27 | return super.command(command, readPreference, encoder); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /java/test/org/nutz/mongo/ZMoBaseTest.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | 8 | public abstract class ZMoBaseTest { 9 | 10 | private static final String DB_NAME = "nutzmongo"; 11 | 12 | protected static final ZMo mo = ZMo.me(); 13 | 14 | protected ZMoDB db; 15 | 16 | @Before 17 | public void before() { 18 | db = ZMongo.me("localhost").db(DB_NAME); 19 | prepare(); 20 | } 21 | 22 | @SuppressWarnings("deprecation") 23 | @After 24 | public void after() { 25 | db.cleanCursors(true); 26 | } 27 | 28 | protected void prepare() {}; 29 | 30 | protected void assertArray(T[] expects, T[] objs) { 31 | assertEquals(expects.length, objs.length); 32 | for (int i = 0; i < objs.length; i++) { 33 | assertEquals(expects[i], objs[i]); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: java 3 | script: mvn -Dmaven.test.skip=true package source:jar 4 | jdk: 5 | - oraclejdk8 6 | # whitelist 7 | branches: 8 | only: 9 | - master 10 | notifications: 11 | email: false 12 | before_install: 13 | - export TZ=Asia/Shanghai 14 | env: 15 | global: 16 | # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created 17 | # via the "travis encrypt" command using the project repo's public key 18 | - secure: "E1z+6z9M4iTdAXZ2a1rYSrxfIOq6PkdXEMutAbIn/bp1e/Qvb5IVoAS0heo7SPwcIlHlN8mDiOtKdzbcu9q8VaftfHwFjff6AoKyuWtfDqE1ecTfflebWwzmtXKJmT5uxBPvu442dS4sIc2zx3zjvnxMsSmvrdSwbMxwdbAKvDc=" 19 | - SONATYPE_USERNAME=wendal 20 | - secure : "BaXmGpodQiuU23YgtUThWCHf7Vig2Gv3UfpBjo3FATgn1LRF3i2IOgY5sCSi+XJYqx+05fVNdwVYccxS/9UfhPNSqQuslIwgmg0y9f26DYaX2gaW+jk8padhZRkeBrY3fO+g9nQuu+Epgqi0ITru6+IjH932O0m1JR7iJu2RNhs=" 21 | after_success: 22 | - bash <(curl -s https://codecov.io/bash) 23 | - python mvn_settings.py -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/ZMoAdaptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import org.nutz.mongo.entity.ZMoField; 4 | 5 | /** 6 | * 将 Mongo 驱动的字段值与普通 Java 字段值互相转换的适配器 7 | *

8 | * 每个适配器的实例将只能处理特定范围的数据类型,比如 ZMoMapAdaptor 只能处理 Map 9 | *

10 | * 注意: 11 | *

    12 | *
  1. 所有的适配器都不会处理 null 这个情况 13 | *
14 | * 15 | * @author zozoh(zozohtnt@gmail.com) 16 | */ 17 | public interface ZMoAdaptor { 18 | 19 | /** 20 | * 将任何 Mongo 驱动的数据类型变成 Java 的值 21 | * 22 | * @param fld 23 | * 要映射的字段 24 | * @param obj 25 | * 字段值 26 | * 27 | * @return 适合普通 Java 程序的字段值 28 | */ 29 | Object toJava(ZMoField fld, Object obj); 30 | 31 | /** 32 | * 将任何 Java 字段值变成 Mongo 驱动能接受的值 33 | * 34 | * @param fld 35 | * 要映射的字段 36 | * @param obj 37 | * 字段值 38 | * 39 | * @return Mongo 驱动能接受的值 40 | */ 41 | Object toMongo(ZMoField fld, Object obj); 42 | } 43 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/adaptor/ZMoEnumAdaptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.adaptor; 2 | 3 | import org.nutz.castor.Castors; 4 | import org.nutz.lang.Lang; 5 | import org.nutz.mongo.ZMoAdaptor; 6 | import org.nutz.mongo.entity.ZMoField; 7 | 8 | public class ZMoEnumAdaptor implements ZMoAdaptor { 9 | 10 | ZMoEnumAdaptor() {} 11 | 12 | @Override 13 | public Object toJava(ZMoField fld, Object obj) { 14 | if (null == fld) 15 | return obj; 16 | return Castors.me().castTo(obj, fld.getType()); 17 | } 18 | 19 | @SuppressWarnings("rawtypes") 20 | @Override 21 | public Object toMongo(ZMoField fld, Object obj) { 22 | if (obj.getClass().isEnum()) { 23 | if (null != fld && fld.isEnumStr()) { 24 | return ((Enum) obj).name(); 25 | } 26 | return Castors.me().castTo(obj, Integer.class); 27 | } 28 | throw Lang.makeThrow("obj<%s> should be ENUM", obj.getClass()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /java/test/org/nutz/mongo/pojo/Pet2.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.pojo; 2 | 3 | import java.util.List; 4 | 5 | import org.nutz.mongo.annotation.MoField; 6 | 7 | public class Pet2 { 8 | 9 | private String _id; 10 | 11 | @MoField("nm") 12 | private String name; 13 | 14 | private int age; 15 | 16 | private List pets; 17 | 18 | public String get_id() { 19 | return _id; 20 | } 21 | 22 | public void set_id(String _id) { 23 | this._id = _id; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setName(String name) { 31 | this.name = name; 32 | } 33 | 34 | public int getAge() { 35 | return age; 36 | } 37 | 38 | public void setAge(int age) { 39 | this.age = age; 40 | } 41 | 42 | public List getPets() { 43 | return pets; 44 | } 45 | 46 | public void setPets(List pets) { 47 | this.pets = pets; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /java/test/org/nutz/mongo/pojo/Human.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.pojo; 2 | 3 | import org.nutz.lang.random.R; 4 | import org.nutz.mongo.annotation.MoField; 5 | 6 | public class Human { 7 | 8 | public static Human NEW(String name) { 9 | return new Human().setName(name); 10 | } 11 | 12 | public static Human[] ARR(String... names) { 13 | Human[] people = new Human[names.length]; 14 | for (int i = 0; i < names.length; i++) { 15 | people[i] = NEW(names[i]).setAge(R.random(2, 20)); 16 | } 17 | return people; 18 | } 19 | 20 | public static final String CNAME = "human"; 21 | 22 | @MoField("nm") 23 | private String name; 24 | 25 | private int age; 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public Human setName(String name) { 32 | this.name = name; 33 | return this; 34 | } 35 | 36 | public int getAge() { 37 | return age; 38 | } 39 | 40 | public Human setAge(int age) { 41 | this.age = age; 42 | return this; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/entity/ZMoEntityHolder.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.entity; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | import org.nutz.lang.Strings; 8 | 9 | /** 10 | * 缓存 ZMoEntity 对象 11 | * 12 | * @author zozoh(zozohtnt@gmail.com) 13 | */ 14 | public class ZMoEntityHolder { 15 | 16 | private Map ens; 17 | 18 | public ZMoEntityHolder() { 19 | ens = new HashMap(); 20 | } 21 | 22 | public ZMoEntity get(String key) { 23 | return ens.get(key); 24 | } 25 | 26 | public void add(String key, ZMoEntity en) { 27 | if (null != en && !Strings.isBlank(key)) { 28 | en.setKey(key); 29 | ens.put(key, en); 30 | } 31 | } 32 | 33 | public Set keys() { 34 | return ens.keySet(); 35 | } 36 | 37 | public int count() { 38 | return ens.size(); 39 | } 40 | 41 | public ZMoEntity remove(String key) { 42 | return ens.remove(key); 43 | } 44 | 45 | public void clear() { 46 | ens.clear(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/mr/ZMoMapReduce.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.mr; 2 | 3 | import org.nutz.mongo.ZMoDoc; 4 | 5 | public class ZMoMapReduce { 6 | 7 | private String key; 8 | 9 | private String init; 10 | 11 | private ZMoDoc _init_obj; 12 | 13 | private String reduceFunc; 14 | 15 | public String getKey() { 16 | return key; 17 | } 18 | 19 | public void setKey(String key) { 20 | this.key = key; 21 | } 22 | 23 | public String getInit() { 24 | return init; 25 | } 26 | 27 | public ZMoDoc getInitObj() { 28 | if (null == _init_obj) { 29 | synchronized (this) { 30 | if (null == _init_obj) { 31 | _init_obj = ZMoDoc.NEW(init); 32 | } 33 | } 34 | } 35 | return _init_obj; 36 | } 37 | 38 | public void setInit(String initObj) { 39 | this.init = initObj; 40 | } 41 | 42 | public String getReduce() { 43 | return reduceFunc; 44 | } 45 | 46 | public void setReduceFunc(String reduceFunc) { 47 | this.reduceFunc = reduceFunc; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/adaptor/ZMoSmartAdaptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.adaptor; 2 | 3 | import org.nutz.lang.Lang; 4 | import org.nutz.lang.Mirror; 5 | import org.nutz.mongo.ZMoAdaptor; 6 | import org.nutz.mongo.entity.ZMoField; 7 | 8 | /** 9 | * 根据值的类型而不是字段类型类判断如何适配 10 | * 11 | * @author zozoh(zozohtnt@gmail.com) 12 | */ 13 | public class ZMoSmartAdaptor implements ZMoAdaptor { 14 | 15 | ZMoSmartAdaptor() {} 16 | 17 | @Override 18 | public Object toJava(ZMoField fld, Object obj) { 19 | Mirror mi = Mirror.me(obj); 20 | try { 21 | return ZMoAs.get(mi).toJava(fld, obj); 22 | } 23 | catch (Exception e) { 24 | throw Lang.wrapThrow(e, "I am not such smart toJava -_-! : %s", obj.getClass()); 25 | } 26 | } 27 | 28 | @Override 29 | public Object toMongo(ZMoField fld, Object obj) { 30 | Mirror mi = Mirror.me(obj); 31 | try { 32 | return ZMoAs.get(mi).toMongo(fld, obj); 33 | } 34 | catch (Exception e) { 35 | throw Lang.wrapThrow(e, "I am not such smart toMongo -_-! : %s", obj.getClass()); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/adaptor/ZMoMapAdaptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.adaptor; 2 | 3 | import org.nutz.lang.Lang; 4 | import org.nutz.lang.Mirror; 5 | import org.nutz.mongo.ZMo; 6 | import org.nutz.mongo.ZMoAdaptor; 7 | import org.nutz.mongo.ZMoDoc; 8 | import org.nutz.mongo.entity.ZMoEntity; 9 | import org.nutz.mongo.entity.ZMoField; 10 | 11 | import com.mongodb.DBObject; 12 | 13 | public class ZMoMapAdaptor implements ZMoAdaptor { 14 | 15 | ZMoMapAdaptor() {} 16 | 17 | @Override 18 | public Object toJava(ZMoField fld, Object obj) { 19 | if (obj instanceof DBObject) { 20 | ZMoDoc doc = ZMoDoc.WRAP((DBObject) obj); 21 | ZMoEntity en = ZMo.me().getEntity(fld.getType()); 22 | return ZMo.me().fromDoc(doc, en); 23 | } 24 | throw Lang.makeThrow("toJava error: %s", obj.getClass()); 25 | } 26 | 27 | @Override 28 | public Object toMongo(ZMoField fld, Object obj) { 29 | Mirror mi = Mirror.me(obj); 30 | if (mi.isMap() || mi.isPojo()) { 31 | ZMoEntity en = ZMo.me().getEntity(mi.getType()); 32 | return ZMo.me().toDoc(obj, en); 33 | } 34 | throw Lang.makeThrow("toMongo error: %s", obj.getClass()); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/adaptor/ZMoIdAdaptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.adaptor; 2 | 3 | import org.bson.types.ObjectId; 4 | import org.nutz.lang.Lang; 5 | import org.nutz.lang.Mirror; 6 | import org.nutz.mongo.ZMoAdaptor; 7 | import org.nutz.mongo.entity.ZMoField; 8 | 9 | public class ZMoIdAdaptor implements ZMoAdaptor { 10 | 11 | @Override 12 | public Object toJava(ZMoField fld, Object obj) { 13 | if (obj instanceof ObjectId || obj instanceof Integer || obj instanceof Long) { 14 | if (null != fld) { 15 | Mirror mi = fld.getMirror(); 16 | if (null != mi) { 17 | if (mi.isOf(Object.class)) { 18 | return obj; 19 | } 20 | if (mi.isArray() && fld.getEleMirror().isOf(Object.class)) { 21 | return obj; 22 | } 23 | } 24 | } 25 | return obj.toString(); 26 | } 27 | throw Lang.makeThrow("should be ObjectId"); 28 | } 29 | 30 | @Override 31 | public Object toMongo(ZMoField fld, Object obj) { 32 | if (obj instanceof ObjectId) { 33 | return obj; 34 | } 35 | return new ObjectId(obj.toString()); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/interceptor/ZOperationExecutor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.interceptor; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.mongodb.ReadPreference; 7 | import com.mongodb.operation.OperationExecutor; 8 | import com.mongodb.operation.ReadOperation; 9 | import com.mongodb.operation.WriteOperation; 10 | 11 | public class ZOperationExecutor implements OperationExecutor { 12 | 13 | protected OperationExecutor proxy; 14 | protected List interceptors; 15 | 16 | protected ZOperationExecutor() {} 17 | 18 | public ZOperationExecutor(OperationExecutor proxy, List interceptors) { 19 | this.proxy = proxy; 20 | this.interceptors = interceptors; 21 | } 22 | 23 | 24 | 25 | public T execute(ReadOperation operation, ReadPreference readPreference) { 26 | if (interceptors == null) 27 | return proxy.execute(operation, readPreference); 28 | else { 29 | MongoInterceptorChain chain = new MongoInterceptorChain(); 30 | chain.interceptors = new ArrayList(interceptors); 31 | chain.proxy = proxy; 32 | chain.readOperation = operation; 33 | chain.readPreference = readPreference; 34 | chain.doChain(); 35 | return chain.result; 36 | } 37 | } 38 | 39 | public T execute(WriteOperation operation) { 40 | if (interceptors == null) 41 | return proxy.execute(operation); 42 | else { 43 | MongoInterceptorChain chain = new MongoInterceptorChain(); 44 | chain.interceptors = new ArrayList(interceptors); 45 | chain.proxy = proxy; 46 | chain.writeOperation = operation; 47 | chain.doChain(); 48 | return chain.result; 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /java/build/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Nutz-mongo library build file 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 52 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/adaptor/ZMoDBObjectAdaptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.adaptor; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.nutz.lang.Lang; 7 | import org.nutz.mongo.ZMo; 8 | import org.nutz.mongo.ZMoAdaptor; 9 | import org.nutz.mongo.ZMoDoc; 10 | import org.nutz.mongo.entity.ZMoField; 11 | 12 | import com.mongodb.DBObject; 13 | 14 | /** 15 | * 如果面对的值的类型是个 DBObject 我们有下面两个策略: 16 | *
    17 | *
  1. 如果是 List,那么就变 ArrayList 18 | *
  2. 否则变成 Map 19 | *
20 | * 转成 mongo 的值则不予考虑,直接转换就是了 21 | * 22 | * @author zozoh(zozohtnt@gmail.com) 23 | */ 24 | public class ZMoDBObjectAdaptor implements ZMoAdaptor { 25 | 26 | @SuppressWarnings({"rawtypes", "unchecked"}) 27 | @Override 28 | public Object toJava(ZMoField fld, Object obj) { 29 | // if(obj instanceof ArrayList){ 30 | // return obj; 31 | // } 32 | // 可能是 BasicDBList or LazyDBList 33 | if (obj instanceof List) { 34 | List list = (List) obj; 35 | ArrayList arr = new ArrayList(list.size()); 36 | int i = 0; 37 | for (Object o : list) { 38 | if (o == null) { 39 | arr.add(i++, o); 40 | } else if (o instanceof DBObject) { 41 | arr.add(i++, ZMoAs.dbo().toJava(null, o)); 42 | } else { 43 | arr.add(o); 44 | } 45 | } 46 | 47 | return arr; 48 | 49 | } 50 | // 普通 DBObject 变 map 51 | else if (obj instanceof DBObject) { 52 | return ZMo.me().fromDocToMap(ZMoDoc.WRAP((DBObject) obj)); 53 | } 54 | // 不可忍受,抛吧 >:D 55 | throw Lang.makeThrow("toJava error: %s", obj.getClass()); 56 | } 57 | 58 | @Override 59 | public Object toMongo(ZMoField fld, Object obj) { 60 | if (obj instanceof DBObject) { 61 | return obj; 62 | } 63 | throw Lang.makeThrow("toMongo error: %s", obj.getClass()); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/entity/ZMoGeneralMapEntity.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.entity; 2 | 3 | import java.util.Map; 4 | import java.util.Set; 5 | 6 | import org.nutz.lang.util.NutMap; 7 | 8 | import com.mongodb.DBObject; 9 | 10 | public class ZMoGeneralMapEntity extends ZMoEntity { 11 | 12 | public ZMoGeneralMapEntity() { 13 | super(); 14 | setDefaultField(new ZMoGeneralMapField()); 15 | setType(NutMap.class); 16 | setBorning(this.getMirror().getBorning()); 17 | } 18 | 19 | @Override 20 | public ZMoEntity forMap() { 21 | return this; 22 | } 23 | 24 | @Override 25 | public ZMoEntity forPojo() { 26 | return this; 27 | } 28 | 29 | @Override 30 | public boolean isForMap() { 31 | return true; 32 | } 33 | 34 | @Override 35 | public boolean isForPojo() { 36 | return false; 37 | } 38 | 39 | @SuppressWarnings("unchecked") 40 | @Override 41 | public Set getJavaNames(Object obj) { 42 | Map map = (Map) obj; 43 | return map.keySet(); 44 | } 45 | 46 | @Override 47 | public Set getMongoNames(Object obj) { 48 | if (obj instanceof DBObject) { 49 | return ((DBObject) obj).keySet(); 50 | } 51 | return getJavaNames(obj); 52 | } 53 | 54 | @Override 55 | public String getJavaNameFromMongo(String mongoName) { 56 | return mongoName; 57 | } 58 | 59 | @Override 60 | public String getMongoNameFromJava(String javaName) { 61 | return javaName; 62 | } 63 | 64 | @Override 65 | public Object getValue(Object obj, String javaName) { 66 | return ((Map) obj).get(javaName); 67 | } 68 | 69 | @SuppressWarnings("unchecked") 70 | @Override 71 | public void setValue(Object obj, String javaName, Object value) { 72 | ((Map) obj).put(javaName, value); 73 | } 74 | 75 | @Override 76 | public ZMoEntity clone() { 77 | return new ZMoGeneralMapEntity(); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /java/test/org/nutz/mongo/ZMoDocTest.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.bson.types.ObjectId; 6 | import org.junit.Test; 7 | import org.nutz.lang.Lang; 8 | import org.nutz.lang.util.Closer; 9 | import org.nutz.mongo.fieldfilter.ZMoFF; 10 | import org.nutz.mongo.fieldfilter.ZMoRegexFF; 11 | import org.nutz.mongo.fieldfilter.ZMoSimpleFF; 12 | import org.nutz.mongo.pojo.Pet; 13 | import org.nutz.mongo.pojo.PetType; 14 | 15 | import com.mongodb.BasicDBList; 16 | 17 | public class ZMoDocTest { 18 | 19 | @Test 20 | public void test_simple_field_filter() { 21 | final Pet pet = Pet.NEW("xiaobai").setAge(10).setType(PetType.CAT); 22 | ZMoSimpleFF ff = new ZMoSimpleFF("name"); 23 | ZMoDoc doc = ff.run(new Closer() { 24 | public ZMoDoc invoke() { 25 | return ZMo.me().toDoc(pet); 26 | } 27 | }); 28 | assertEquals(1, doc.size()); 29 | assertEquals("xiaobai", doc.get("nm").toString()); 30 | } 31 | 32 | @Test 33 | public void test_regex_field_filter() { 34 | final Pet pet = Pet.NEW("xiaobai").setAge(10).setType(PetType.CAT); 35 | ZMoFF ff = new ZMoRegexFF("nm|tp").byJava(false); 36 | ZMoDoc doc = ff.run(new Closer() { 37 | public ZMoDoc invoke() { 38 | return ZMo.me().toDoc(pet); 39 | } 40 | }); 41 | assertEquals(2, doc.size()); 42 | assertEquals("xiaobai", doc.get("nm").toString()); 43 | assertEquals(PetType.CAT, doc.getAs("tp", PetType.class)); 44 | } 45 | 46 | @Test 47 | public void test_fld_is_ObjectIdArray() { 48 | ZMoDoc d2 = ZMoDoc.NEW("nm", "B"); 49 | ObjectId[] ids = Lang.array(new ObjectId()); 50 | 51 | d2.putv("frs", ids); 52 | 53 | BasicDBList frs = (BasicDBList) d2.get("frs"); 54 | assertEquals(1, frs.size()); 55 | ObjectId theId = (ObjectId) frs.get(0); 56 | assertEquals(ids[0], theId); 57 | } 58 | 59 | @Test 60 | public void test_fld_is_ObjectId() { 61 | ZMoDoc doc = ZMoDoc.NEW("abc", new ObjectId("521c6ffa3004c3c9cbfe59d3")); 62 | ObjectId id = doc.getAsId("abc"); 63 | assertEquals("521c6ffa3004c3c9cbfe59d3", id.toString()); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/mr/ZMoMapReduceManager.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.mr; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.nutz.lang.Files; 10 | import org.nutz.lang.Lang; 11 | import org.nutz.lang.Streams; 12 | import org.nutz.lang.Strings; 13 | 14 | public class ZMoMapReduceManager { 15 | 16 | private Map map; 17 | 18 | private String home; 19 | 20 | public ZMoMapReduceManager(String home) { 21 | this.home = (home.endsWith("/") ? home.substring(0, home.length() - 1) 22 | : home).replaceAll("[.\\\\]", "/"); 23 | this.map = new HashMap(); 24 | } 25 | 26 | public ZMoMapReduce get(String key) { 27 | ZMoMapReduce mr = map.get(key); 28 | if (null == mr) { 29 | mr = syncGet(key); 30 | } 31 | return mr; 32 | } 33 | 34 | private synchronized ZMoMapReduce syncGet(String key) { 35 | ZMoMapReduce mr; 36 | mr = map.get(key); 37 | if (null == mr) { 38 | File f = Files.findFile(home + "/" + key + ".js"); 39 | if (null != f) { 40 | try { 41 | StringBuilder sb = new StringBuilder(); 42 | mr = new ZMoMapReduce(); 43 | mr.setKey(key); 44 | BufferedReader br = Streams.buffr(Streams.fileInr(f)); 45 | String line; 46 | // 首先得到 init obj 47 | while (null != (line = br.readLine())) { 48 | // 如果是 function 开头退出 49 | if (line.startsWith("function(")) 50 | break; 51 | // 去掉注释符 52 | if (line.startsWith("//")) 53 | line = line.substring(2); 54 | // 累加 55 | sb.append(line).append('\n'); 56 | } 57 | mr.setInit(Strings.trim(sb)); 58 | // 继续读取函数 59 | sb = new StringBuilder(line); 60 | while (null != (line = br.readLine())) { 61 | sb.append('\n').append(line); 62 | } 63 | mr.setReduceFunc(sb.toString()); 64 | // 加入缓存 65 | map.put(key, mr); 66 | } 67 | catch (IOException e) { 68 | throw Lang.wrapThrow(e); 69 | } 70 | } 71 | } 72 | return mr; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/ZMoDB.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import java.util.Set; 4 | 5 | import org.nutz.lang.Lang; 6 | 7 | import com.mongodb.DB; 8 | 9 | /** 10 | * 对于 DB 对象的薄封装 11 | * 12 | * @author zozoh(zozohtnt@gmail.com) 13 | */ 14 | public class ZMoDB { 15 | 16 | private DB db; 17 | 18 | public ZMoDB(DB db) { 19 | this.db = db; 20 | } 21 | 22 | /** 23 | * 获取集合,如果集合不存在,则抛错 24 | * 25 | * @param name 26 | * 集合名称 27 | * @return 集合薄封装 28 | */ 29 | public ZMoCo c(String name) { 30 | if (!db.collectionExists(name)) 31 | throw Lang.makeThrow("Colection noexitst: %s.%s", db.getName(), name); 32 | return new ZMoCo(db.getCollection(name)); 33 | } 34 | 35 | /** 36 | * 获取一个集合,如果集合不存在,就创建它 37 | * 38 | * @param name 39 | * 集合名 40 | * @param dropIfExists 41 | * true 如果存在就清除 42 | * @return 集合薄封装 43 | */ 44 | public ZMoCo cc(String name, boolean dropIfExists) { 45 | // 不存在则创建 46 | if (!db.collectionExists(name)) { 47 | return createCollection(name, null); 48 | } 49 | // 固定清除 50 | else if (dropIfExists) { 51 | db.getCollection(name).drop(); 52 | return createCollection(name, null); 53 | } 54 | // 已经存在 55 | return new ZMoCo(db.getCollection(name)); 56 | } 57 | 58 | /** 59 | * 是否存在某个集合 60 | * 61 | * @param name 62 | * 集合名 63 | * @return 是否存在 64 | */ 65 | public boolean cExists(String name) { 66 | return db.collectionExists(name); 67 | } 68 | 69 | /** 70 | * 创建一个集合 71 | * 72 | * @param name 73 | * 集合名 74 | * @param options 75 | * 集合配置信息 76 | * @return 集合薄封装 77 | */ 78 | public ZMoCo createCollection(String name, ZMoDoc options) { 79 | if (db.collectionExists(name)) { 80 | throw Lang.makeThrow("Colection exitst: %s.%s", db.getName(), name); 81 | } 82 | 83 | // 创建默认配置信息 84 | if (null == options) { 85 | options = ZMoDoc.NEW("capped:false"); 86 | } 87 | 88 | return new ZMoCo(db.createCollection(name, options)); 89 | } 90 | 91 | /** 92 | * 清除数据库的游标 93 | * 94 | * @param force 95 | * 是否强制 96 | */ 97 | @Deprecated 98 | public void cleanCursors(boolean force) { 99 | //db.cleanCursors(force); 100 | } 101 | 102 | /** 103 | * @return 当前数据库所有可用集合名称 104 | */ 105 | public Set cNames() { 106 | return db.getCollectionNames(); 107 | } 108 | 109 | public DB getNativeDB() { 110 | return this.db; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/interceptor/impl/LogMongoInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.interceptor.impl; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | import org.bson.BsonDocument; 6 | import org.nutz.log.Log; 7 | import org.nutz.log.Logs; 8 | import org.nutz.mongo.interceptor.MongoInterceptor; 9 | import org.nutz.mongo.interceptor.MongoInterceptorChain; 10 | 11 | import com.mongodb.operation.CommandReadOperation; 12 | import com.mongodb.operation.CommandWriteOperation; 13 | 14 | public class LogMongoInterceptor implements MongoInterceptor { 15 | 16 | protected static final Log log = Logs.get(); 17 | 18 | protected static Field cr_command; 19 | protected static Field cr_databaseName; 20 | protected static Field cw_command; 21 | protected static Field cw_databaseName; 22 | static { 23 | try { 24 | cr_command = CommandReadOperation.class.getDeclaredField("command"); 25 | cw_command = CommandWriteOperation.class.getDeclaredField("command"); 26 | cr_databaseName = CommandReadOperation.class.getDeclaredField("databaseName"); 27 | cw_databaseName = CommandWriteOperation.class.getDeclaredField("databaseName"); 28 | 29 | cr_command.setAccessible(true); 30 | cw_command.setAccessible(true); 31 | cr_databaseName.setAccessible(true); 32 | cw_databaseName.setAccessible(true); 33 | } 34 | catch (Exception e) { 35 | throw new RuntimeException(e); 36 | } 37 | } 38 | 39 | @SuppressWarnings("rawtypes") 40 | public void filter(MongoInterceptorChain chain) { 41 | if (log.isDebugEnabled()) { 42 | try { 43 | BsonDocument command = null; 44 | String databaseName = ""; 45 | String tag = ""; 46 | if (chain.getReadOperation() != null && chain.getReadOperation() instanceof CommandReadOperation) { 47 | CommandReadOperation cr = (CommandReadOperation)chain.getReadOperation(); 48 | command = (BsonDocument) cr_command.get(cr); 49 | databaseName = (String) cr_databaseName.get(cr); 50 | tag = "R"; 51 | } else if (chain.getWriteOperation() != null && chain.getWriteOperation() instanceof CommandWriteOperation) { 52 | CommandWriteOperation cr = (CommandWriteOperation)chain.getReadOperation(); 53 | command = (BsonDocument) cw_command.get(cr); 54 | databaseName = (String) cw_databaseName.get(cr); 55 | tag = "W"; 56 | } 57 | if (command != null) { 58 | log.debugf("%s : db=%s : cmd=%s", tag, databaseName, command.values().iterator().next()); 59 | } 60 | } 61 | catch (Exception e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | chain.doChain(); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/adaptor/ZMoAs.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.adaptor; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | import org.bson.types.ObjectId; 6 | import org.nutz.lang.Lang; 7 | import org.nutz.lang.Mirror; 8 | import org.nutz.mongo.ZMoAdaptor; 9 | 10 | import com.mongodb.DBObject; 11 | 12 | /** 13 | * 各个适配器的单例工厂方法 14 | * 15 | * @author zozoh(zozohtnt@gmail.com) 16 | */ 17 | public class ZMoAs { 18 | 19 | private static ZMoAdaptor _id = new ZMoIdAdaptor(); 20 | 21 | private static ZMoAdaptor _dbo = new ZMoDBObjectAdaptor(); 22 | 23 | private static ZMoAdaptor _collection = new ZMoCollectionAdaptor(); 24 | 25 | private static ZMoAdaptor _array = new ZMoArrayAdaptor(); 26 | 27 | private static ZMoAdaptor _enum = new ZMoEnumAdaptor(); 28 | 29 | private static ZMoAdaptor _map = new ZMoMapAdaptor(); 30 | 31 | private static ZMoAdaptor _pojo = new ZMoPojoAdaptor(); 32 | 33 | private static ZMoAdaptor _simple = new ZMoSimpleAdaptor(); 34 | 35 | private static ZMoAdaptor _smart = new ZMoSmartAdaptor(); 36 | 37 | public static ZMoAdaptor get(Mirror mi) { 38 | // ID 对象 39 | if (mi.isOf(ObjectId.class)) { 40 | return ZMoAs.id(); 41 | } 42 | // 简单类型 43 | else if (mi.isSimple() || mi.is(Pattern.class)) { 44 | return ZMoAs.simple(); 45 | } 46 | // DBObject 47 | else if (mi.isOf(DBObject.class)) { 48 | return ZMoAs.dbo(); 49 | } 50 | // 集合 51 | else if (mi.isCollection()) { 52 | return ZMoAs.collection(); 53 | } 54 | // 数组 55 | else if (mi.isArray()) { 56 | return ZMoAs.array(); 57 | } 58 | // 枚举 59 | else if (mi.isEnum()) { 60 | return ZMoAs.ENUM(); 61 | } 62 | // Map 63 | else if (mi.isMap()) { 64 | return ZMoAs.map(); 65 | } 66 | // POJO 67 | else if (mi.isPojo()) { 68 | return ZMoAs.pojo(); 69 | } 70 | // 错误 71 | throw Lang.makeThrow("fail to found adaptor for type %s", mi.getType()); 72 | } 73 | 74 | public static ZMoAdaptor id() { 75 | return _id; 76 | } 77 | 78 | public static ZMoAdaptor dbo() { 79 | return _dbo; 80 | } 81 | 82 | public static ZMoAdaptor collection() { 83 | return _collection; 84 | } 85 | 86 | public static ZMoAdaptor array() { 87 | return _array; 88 | } 89 | 90 | public static ZMoAdaptor ENUM() { 91 | return _enum; 92 | } 93 | 94 | public static ZMoAdaptor map() { 95 | return _map; 96 | } 97 | 98 | public static ZMoAdaptor pojo() { 99 | return _pojo; 100 | } 101 | 102 | public static ZMoAdaptor simple() { 103 | return _simple; 104 | } 105 | 106 | public static ZMoAdaptor smart() { 107 | return _smart; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/interceptor/MongoInterceptorChain.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.interceptor; 2 | 3 | import java.util.List; 4 | 5 | import org.nutz.lang.Lang; 6 | import org.nutz.lang.util.Context; 7 | 8 | import com.mongodb.ReadPreference; 9 | import com.mongodb.operation.OperationExecutor; 10 | import com.mongodb.operation.ReadOperation; 11 | import com.mongodb.operation.WriteOperation; 12 | 13 | public class MongoInterceptorChain { 14 | 15 | protected ReadOperation readOperation; 16 | protected ReadPreference readPreference; 17 | protected WriteOperation writeOperation; 18 | protected List interceptors; 19 | protected int index; 20 | protected OperationExecutor proxy; 21 | protected T result; 22 | protected Context context; 23 | 24 | public void doChain() { 25 | if (interceptors.size() > index) 26 | interceptors.get(index++).filter(this); 27 | else { 28 | if (readOperation != null) { 29 | result = proxy.execute(readOperation, readPreference); 30 | } else if (writeOperation != null) { 31 | result = proxy.execute(writeOperation); 32 | } 33 | } 34 | } 35 | 36 | public ReadOperation getReadOperation() { 37 | return readOperation; 38 | } 39 | 40 | public void setReadOperation(ReadOperation readOperation) { 41 | this.readOperation = readOperation; 42 | } 43 | 44 | public ReadPreference getReadPreference() { 45 | return readPreference; 46 | } 47 | 48 | public void setReadPreference(ReadPreference readPreference) { 49 | this.readPreference = readPreference; 50 | } 51 | 52 | public WriteOperation getWriteOperation() { 53 | return writeOperation; 54 | } 55 | 56 | public void setWriteOperation(WriteOperation writeOperation) { 57 | this.writeOperation = writeOperation; 58 | } 59 | 60 | public List getInterceptors() { 61 | return interceptors; 62 | } 63 | 64 | public void setInterceptors(List interceptors) { 65 | this.interceptors = interceptors; 66 | } 67 | 68 | public int getIndex() { 69 | return index; 70 | } 71 | 72 | public void setIndex(int index) { 73 | this.index = index; 74 | } 75 | 76 | public OperationExecutor getProxy() { 77 | return proxy; 78 | } 79 | 80 | public void setProxy(OperationExecutor proxy) { 81 | this.proxy = proxy; 82 | } 83 | 84 | public T getResult() { 85 | return result; 86 | } 87 | 88 | public void setResult(T result) { 89 | this.result = result; 90 | } 91 | 92 | public Context getContext() { 93 | if (context == null) 94 | context = Lang.context(); 95 | return context; 96 | } 97 | 98 | public void setContext(Context context) { 99 | this.context = context; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/fieldfilter/ZMoFF.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.fieldfilter; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.nutz.lang.util.Closer; 7 | import org.nutz.mongo.ZMo; 8 | import org.nutz.mongo.ZMoDoc; 9 | import org.nutz.mongo.entity.ZMoField; 10 | 11 | /** 12 | * 字段过滤器,在 toDoc 的时候生效,通过 ZMo.setFilterFilter 设置 13 | * 14 | * @author zozoh(zozohtnt@gmail.com) 15 | */ 16 | public abstract class ZMoFF { 17 | 18 | private static ThreadLocal _field_filters_ = new ThreadLocal(); 19 | 20 | public static void set(ZMoFF ff) { 21 | if (null != ff) { 22 | _field_filters_.set(ff); 23 | } 24 | } 25 | 26 | public static ZMoFF get() { 27 | return _field_filters_.get(); 28 | } 29 | 30 | public static void remove() { 31 | _field_filters_.remove(); 32 | } 33 | 34 | public T run(Closer closer) { 35 | set(this); 36 | try { 37 | return closer.invoke(); 38 | } 39 | finally { 40 | remove(); 41 | } 42 | } 43 | 44 | public ZMoDoc toDoc(final Object obj) { 45 | return run(new Closer() { 46 | public ZMoDoc invoke() { 47 | return ZMo.me().toDoc(obj); 48 | } 49 | }); 50 | } 51 | 52 | /** 53 | * true 表示匹配上的字段忽略,false 表示匹配上的字段不忽略 54 | */ 55 | private boolean asIgnore; 56 | 57 | /** 58 | * true 表示匹配Java字段,false 表示匹配Mongo字段 59 | */ 60 | private boolean byJava; 61 | 62 | /** 63 | * 是否忽略 null 值 64 | */ 65 | private boolean ignoreNull; 66 | 67 | /** 68 | * 对于特殊字段,指定为特殊值的时候忽略 69 | */ 70 | private Map ignoreNumber; 71 | 72 | protected ZMoFF() { 73 | asIgnore = false; 74 | byJava = true; 75 | ignoreNull = false; 76 | ignoreNumber = new HashMap(); 77 | } 78 | 79 | /** 80 | * @param fld 81 | * 当前字段 82 | * @return 是否忽略这个字段 83 | */ 84 | public boolean isIgnore(ZMoField fld, Object v) { 85 | if (null == v && ignoreNull) 86 | return true; 87 | 88 | // 得到名称 89 | String key = byJava ? fld.getJavaName() : fld.getMongoName(); 90 | 91 | // 如果是数字,那么看看是否需要忽略 92 | if (null != v && !ignoreNumber.isEmpty() && v instanceof Number) { 93 | Number n = ignoreNumber.get(key); 94 | if (null != n && n.doubleValue() == ((Number) v).doubleValue()) 95 | return true; 96 | } 97 | 98 | // 如果匹配上了 99 | if (match(key)) { 100 | return asIgnore; 101 | } 102 | return !asIgnore; 103 | } 104 | 105 | public ZMoFF asIgnore(boolean asActive) { 106 | this.asIgnore = asActive; 107 | return this; 108 | } 109 | 110 | public ZMoFF byJava(boolean byJava) { 111 | this.byJava = byJava; 112 | return this; 113 | } 114 | 115 | public ZMoFF ignoreNull(boolean ignoreNull) { 116 | this.ignoreNull = ignoreNull; 117 | return this; 118 | } 119 | 120 | /** 121 | * @param key 122 | * 根据 byJava 的设定 123 | * @param n 124 | * 值 125 | * @return 自身 126 | */ 127 | public ZMoFF ignoreNumber(String key, Number n) { 128 | ignoreNumber.put(key, n); 129 | return this; 130 | } 131 | 132 | /** 133 | * 子类的抽象实现 134 | * 135 | * @param fld 136 | * 字段名 137 | * @return 是否匹配上 138 | */ 139 | protected abstract boolean match(String fld); 140 | 141 | } 142 | -------------------------------------------------------------------------------- /java/test/org/nutz/mongo/pojo/Pet.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.pojo; 2 | 3 | import java.util.Date; 4 | 5 | import org.bson.types.ObjectId; 6 | import org.nutz.castor.Castors; 7 | import org.nutz.lang.Times; 8 | import org.nutz.lang.random.R; 9 | import org.nutz.mongo.annotation.*; 10 | 11 | public class Pet { 12 | 13 | public static Pet NEW(String name) { 14 | return new Pet().setName(name); 15 | } 16 | 17 | public static Pet[] ARR(String... names) { 18 | Pet[] pets = new Pet[names.length]; 19 | for (int i = 0; i < names.length; i++) { 20 | pets[i] = NEW(names[i]).setAge(R.random(2, 20)) 21 | .setBornAt(Times.now()) 22 | .setColor(Castors.me() 23 | .castTo(R.random(0, 6), 24 | PetColor.class)) 25 | .setType(Castors.me().castTo(R.random(0, 4), 26 | PetType.class)); 27 | } 28 | return pets; 29 | } 30 | 31 | public static final String CNAME = "pet"; 32 | 33 | private String _id; 34 | 35 | @MoField("nm") 36 | private String name; 37 | 38 | private int age; 39 | 40 | @MoField("ba") 41 | private Date bornAt; 42 | 43 | @MoField("tp") 44 | private PetType type; 45 | 46 | @MoEnum(str = false) 47 | private PetColor color; 48 | 49 | @MoIgnore 50 | private String comment; 51 | 52 | @MoField("ma") 53 | private Human master; 54 | 55 | private String[] labels; 56 | 57 | @MoField("frs") 58 | private ObjectId[] friends; 59 | 60 | public String[] getLabels() { 61 | return labels; 62 | } 63 | 64 | public Pet setLabels(String[] labels) { 65 | this.labels = labels; 66 | return this; 67 | } 68 | 69 | public String get_id() { 70 | return _id; 71 | } 72 | 73 | public void set_id(String _id) { 74 | this._id = _id; 75 | } 76 | 77 | public String getName() { 78 | return name; 79 | } 80 | 81 | public Pet setName(String name) { 82 | this.name = name; 83 | return this; 84 | } 85 | 86 | public int getAge() { 87 | return age; 88 | } 89 | 90 | public Pet setAge(int age) { 91 | this.age = age; 92 | return this; 93 | } 94 | 95 | public Date getBornAt() { 96 | return bornAt; 97 | } 98 | 99 | public Pet setBornAt(Date bornAt) { 100 | this.bornAt = bornAt; 101 | return this; 102 | } 103 | 104 | public PetType getType() { 105 | return type; 106 | } 107 | 108 | public Pet setType(PetType type) { 109 | this.type = type; 110 | return this; 111 | } 112 | 113 | public PetColor getColor() { 114 | return color; 115 | } 116 | 117 | public Pet setColor(PetColor color) { 118 | this.color = color; 119 | return this; 120 | } 121 | 122 | public String getComment() { 123 | return comment; 124 | } 125 | 126 | public Pet setComment(String comment) { 127 | this.comment = comment; 128 | return this; 129 | } 130 | 131 | public Human getMaster() { 132 | return master; 133 | } 134 | 135 | public void setMaster(Human master) { 136 | this.master = master; 137 | } 138 | 139 | public ObjectId[] getFriends() { 140 | return friends; 141 | } 142 | 143 | public Pet setFriends(ObjectId[] friends) { 144 | this.friends = friends; 145 | return this; 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/adaptor/ZMoCollectionAdaptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.adaptor; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.Iterator; 6 | 7 | import org.bson.types.ObjectId; 8 | import org.nutz.lang.Lang; 9 | import org.nutz.lang.Mirror; 10 | import org.nutz.mongo.ZMo; 11 | import org.nutz.mongo.ZMoAdaptor; 12 | import org.nutz.mongo.entity.ZMoEntity; 13 | import org.nutz.mongo.entity.ZMoField; 14 | 15 | import com.mongodb.BasicDBList; 16 | import com.mongodb.DBObject; 17 | 18 | public class ZMoCollectionAdaptor implements ZMoAdaptor { 19 | 20 | ZMoCollectionAdaptor() {} 21 | 22 | @SuppressWarnings("unchecked") 23 | @Override 24 | public Object toJava(ZMoField fld, Object obj) { 25 | if (obj instanceof BasicDBList) { 26 | BasicDBList list = (BasicDBList) obj; 27 | 28 | // 获取元素的实体 29 | ZMoEntity en = null; 30 | 31 | // 创建数组 32 | Collection coll = null; 33 | if (fld == null) { 34 | coll = new ArrayList(list.size()); 35 | } else { 36 | coll = (Collection) fld.getBorning().born(); 37 | } 38 | 39 | // 开始循环数组 40 | Iterator it = list.iterator(); 41 | while (it.hasNext()) { 42 | Object eleMongo = it.next(); 43 | Object elePojo; 44 | 45 | // 如果元素是个 Mongo 类型 46 | if (eleMongo instanceof DBObject) { 47 | // 确保已经获得过实体过了,这里这个代码考虑到效率 48 | // 就是说一个集合或者数组,映射方式总是一样的 49 | // 如果有不一样的,那么就完蛋了 50 | if (null == en) { 51 | en = ZMo.me().getEntity(fld.getEleType()); 52 | } 53 | // 转换 54 | elePojo = ZMo.me().fromDoc((DBObject) eleMongo, en); 55 | } 56 | // 如果 fld 有 adaptor 57 | else if (null != fld && null != fld.getEleAdaptor()) { 58 | elePojo = fld.getEleAdaptor().toJava(null, eleMongo); 59 | } 60 | // 其他情况,直接上 smart 咯 61 | else { 62 | elePojo = ZMoAs.smart().toJava(null, eleMongo); 63 | } 64 | // 加入到数组中 65 | coll.add(elePojo); 66 | } 67 | 68 | return coll; 69 | } 70 | throw Lang.makeThrow("toJava error: %s", obj.getClass()); 71 | } 72 | 73 | @Override 74 | public Object toMongo(ZMoField fld, Object obj) { 75 | if (Mirror.me(obj).isCollection()) { 76 | Collection coll = (Collection) obj; 77 | BasicDBList list = new BasicDBList(); 78 | for (Object objPojo : coll) { 79 | Object objMongo; 80 | Mirror mi = Mirror.me(objPojo); 81 | // null 82 | if (null == objPojo) { 83 | objMongo = null; 84 | } 85 | // 对于 ObjectId 86 | else if (objPojo instanceof ObjectId) { 87 | objMongo = objPojo; 88 | } 89 | // 普通的 DBObject 90 | else if (objPojo instanceof DBObject) { 91 | objMongo = obj; 92 | } 93 | // Map 或者 POJO 94 | else if (mi.isMap() || mi.isPojo()) { 95 | objMongo = ZMo.me().toDoc(objPojo); 96 | } 97 | // 其他类型用 smart 转一下咯 98 | else { 99 | objMongo = ZMoAs.smart().toMongo(null, objPojo); 100 | } 101 | // 加入到列表 102 | list.add(objMongo); 103 | } 104 | 105 | return list; 106 | } 107 | throw Lang.makeThrow("toMongo error: %s", obj.getClass()); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/adaptor/ZMoArrayAdaptor.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.adaptor; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | import org.bson.types.ObjectId; 8 | import org.nutz.lang.Lang; 9 | import org.nutz.lang.Mirror; 10 | import org.nutz.mongo.ZMo; 11 | import org.nutz.mongo.ZMoAdaptor; 12 | import org.nutz.mongo.entity.ZMoEntity; 13 | import org.nutz.mongo.entity.ZMoField; 14 | 15 | import com.mongodb.BasicDBList; 16 | import com.mongodb.DBObject; 17 | 18 | public class ZMoArrayAdaptor implements ZMoAdaptor { 19 | 20 | ZMoArrayAdaptor() {} 21 | 22 | @Override 23 | public Object toJava(ZMoField fld, Object obj) { 24 | if (obj instanceof List) { 25 | List list = (List) obj; 26 | 27 | // 获取元素的实体 28 | ZMoEntity en = null; 29 | 30 | // 创建数组 31 | Object arr = null; 32 | if (fld == null) { 33 | arr = Array.newInstance(Object.class, list.size()); 34 | } 35 | // 让 fld 的 Borning 来创建 36 | else { 37 | arr = fld.getBorning().born(list.size()); 38 | } 39 | 40 | // 开始循环数组 41 | int i = 0; 42 | Iterator it = list.iterator(); 43 | while (it.hasNext()) { 44 | Object eleMongo = it.next(); 45 | Object elePojo; 46 | 47 | // 如果元素是个 Mongo 类型 48 | if (eleMongo instanceof DBObject) { 49 | // 确保已经获得过实体过了,这里这个代码考虑到效率 50 | // 就是说一个集合或者数组,映射方式总是一样的 51 | // 如果有不一样的,那么就完蛋了 52 | if (null == en) { 53 | en = ZMo.me().getEntity(eleMongo.getClass()); 54 | } 55 | // 转换 56 | elePojo = ZMo.me().fromDoc((DBObject) eleMongo, en); 57 | } 58 | // 如果 fld 有 adaptor 59 | else if (null != fld && null != fld.getEleAdaptor()) { 60 | elePojo = fld.getEleAdaptor().toJava(fld, eleMongo); 61 | } 62 | // 其他情况,直接上 smart 咯 63 | else { 64 | elePojo = ZMoAs.smart().toJava(null, eleMongo); 65 | } 66 | // 加入到数组中 67 | Array.set(arr, i++, elePojo); 68 | } 69 | 70 | return arr; 71 | } 72 | throw Lang.makeThrow("toJava error: %s", obj.getClass()); 73 | } 74 | 75 | @Override 76 | public Object toMongo(ZMoField fld, Object obj) { 77 | if (obj.getClass().isArray()) { 78 | BasicDBList list = new BasicDBList(); 79 | int len = Array.getLength(obj); 80 | for (int i = 0; i < len; i++) { 81 | Object objPojo = Array.get(obj, i); 82 | Object objMongo; 83 | Mirror mi = Mirror.me(objPojo); 84 | // null 85 | if (null == objPojo) { 86 | objMongo = null; 87 | } 88 | // 对于 ObjectId 89 | else if (objPojo instanceof ObjectId) { 90 | objMongo = objPojo; 91 | } 92 | // 普通的 DBObject 93 | else if (objPojo instanceof DBObject) { 94 | objMongo = obj; 95 | } 96 | // Map 或者 POJO 97 | else if (mi.isMap() || mi.isPojo()) { 98 | objMongo = ZMo.me().toDoc(objPojo); 99 | } 100 | // 其他类型用 smart 转一下咯 101 | else { 102 | objMongo = ZMoAs.smart().toMongo(null, objPojo); 103 | } 104 | // 加入到列表 105 | list.add(objMongo); 106 | } 107 | 108 | return list; 109 | } 110 | throw Lang.makeThrow("toMongo error: %s", obj.getClass()); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/entity/ZMoField.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.entity; 2 | 3 | import org.nutz.lang.Mirror; 4 | import org.nutz.lang.born.Borning; 5 | import org.nutz.lang.eject.Ejecting; 6 | import org.nutz.lang.inject.Injecting; 7 | import org.nutz.mongo.ZMoAdaptor; 8 | import org.nutz.mongo.adaptor.ZMoAs; 9 | 10 | /** 11 | * 封装了一个 Java 对象字段映射以及存取值操作 12 | * 13 | * @author zozoh(zozohtnt@gmail.com) 14 | */ 15 | public class ZMoField { 16 | 17 | public ZMoField() {} 18 | 19 | private String javaName; 20 | 21 | private String mongoName; 22 | 23 | /** 24 | * 字段的类型 25 | */ 26 | private Class type; 27 | 28 | private Mirror mirror; 29 | 30 | /** 31 | * 元素类型,仅为数组或者容器使用 32 | */ 33 | private Class eleType; 34 | 35 | private Mirror eleMirror; 36 | 37 | /** 38 | * 元素适配器,仅为数组或者容器使用 39 | */ 40 | private ZMoAdaptor eleAdaptor; 41 | 42 | /** 43 | * 字段值的创建方式,通常是针对容器类或者POJO类 44 | */ 45 | private Borning borning; 46 | 47 | /** 48 | * 字段所属的映射实体 49 | */ 50 | private ZMoEntity parent; 51 | 52 | /** 53 | * 对于字段值的处理方式 54 | */ 55 | private ZMoAdaptor adaptor; 56 | 57 | /** 58 | * 从字段中取出值的方法 59 | */ 60 | private Ejecting ejecting; 61 | 62 | /** 63 | * 向字段赋值的方法 64 | */ 65 | private Injecting injecting; 66 | 67 | /** 68 | * 仅对枚举字段有效,指明枚举字段是要保存成整数还是字符串 69 | */ 70 | private boolean enum_is_str; 71 | 72 | public boolean isID() { 73 | return "_id".equals(javaName); 74 | } 75 | 76 | public String getJavaName() { 77 | return javaName; 78 | } 79 | 80 | public void setJavaName(String javaName) { 81 | this.javaName = javaName; 82 | } 83 | 84 | public String getMongoName() { 85 | return mongoName; 86 | } 87 | 88 | public void setMongoName(String mongoName) { 89 | this.mongoName = mongoName; 90 | } 91 | 92 | public boolean isEnumStr() { 93 | return enum_is_str; 94 | } 95 | 96 | public void setEnumStr(boolean isEnumString) { 97 | this.enum_is_str = isEnumString; 98 | } 99 | 100 | public Borning getBorning() { 101 | return borning; 102 | } 103 | 104 | public void setBorning(Borning borning) { 105 | this.borning = borning; 106 | } 107 | 108 | public Class getType() { 109 | return type; 110 | } 111 | 112 | public void setType(Class type) { 113 | this.type = type; 114 | this.mirror = Mirror.me(type); 115 | } 116 | 117 | public Mirror getMirror() { 118 | return mirror; 119 | } 120 | 121 | public Class getEleType() { 122 | return eleType; 123 | } 124 | 125 | public void setEleType(Class eleType) { 126 | this.eleType = eleType; 127 | this.eleMirror = Mirror.me(eleType); 128 | this.eleAdaptor = ZMoAs.get(eleMirror); 129 | } 130 | 131 | public Mirror getEleMirror() { 132 | return eleMirror; 133 | } 134 | 135 | public ZMoAdaptor getEleAdaptor() { 136 | return eleAdaptor; 137 | } 138 | 139 | public void setEleAdaptor(ZMoAdaptor eleAdaptor) { 140 | this.eleAdaptor = eleAdaptor; 141 | } 142 | 143 | public ZMoEntity getParent() { 144 | return parent; 145 | } 146 | 147 | public void setParent(ZMoEntity parent) { 148 | this.parent = parent; 149 | } 150 | 151 | public ZMoAdaptor getAdaptor() { 152 | return adaptor; 153 | } 154 | 155 | public void setAdaptor(ZMoAdaptor adaptor) { 156 | this.adaptor = adaptor; 157 | } 158 | 159 | public Ejecting getEjecting() { 160 | return ejecting; 161 | } 162 | 163 | public void setEjecting(Ejecting ejecting) { 164 | this.ejecting = ejecting; 165 | } 166 | 167 | public Injecting getInjecting() { 168 | return injecting; 169 | } 170 | 171 | public void setInjecting(Injecting injecting) { 172 | this.injecting = injecting; 173 | } 174 | 175 | public ZMoField clone() { 176 | ZMoField fld = new ZMoField(); 177 | fld.setEjecting(ejecting); 178 | fld.setInjecting(injecting); 179 | fld.setBorning(borning); 180 | fld.setEnumStr(enum_is_str); 181 | fld.setEleType(eleType); 182 | return fld; 183 | } 184 | 185 | } 186 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.nutz 5 | nutzmongo 6 | jar 7 | Nutzmongo 8 | 1.r.65-SNAPSHOT 9 | 10 | UTF-8 11 | 12 | nutz wtih mongodb 13 | 14 | http://nutzam.com 15 | 16 | Github Issue 17 | http://github.com/nutzam/nutzmongo/issues 18 | 19 | 20 | 21 | The Apache Software License, Version 2.0 22 | http://apache.org/licenses/LICENSE-2.0.txt 23 | 24 | 25 | 26 | 27 | zozoh 28 | zozoh 29 | zozohtnt@gmail.com 30 | http://weibo.com/zozoh 31 | 32 | 33 | wendal 34 | Wendal Chen 35 | wendal1985@gmail.com 36 | http://wendal.net/ 37 | 38 | 39 | juqkai 40 | Juqkai 41 | Bird.Wyatt@gmail.com 42 | https://github.com/juqkai 43 | 44 | 45 | 46 | scm:git:git://github.com/nutzam/nutzmongo.git 47 | scm:git:git://github.com/nutzam/nutzmongo.git 48 | https://github.com/nutzam/nutzmongo 49 | 50 | 51 | 52 | 53 | junit 54 | junit 55 | 4.8.2 56 | test 57 | 58 | 59 | org.mongodb 60 | mongo-java-driver 61 | 3.5.0 62 | 63 | 64 | org.nutz 65 | nutz 66 | 1.r.63 67 | provided 68 | 69 | 70 | org.slf4j 71 | slf4j-log4j12 72 | 1.7.24 73 | provided 74 | 75 | 76 | 77 | 78 | java/src 79 | java/test 80 | 81 | 82 | 83 | java/src 84 | false 85 | 86 | **/*.java 87 | 88 | 89 | 90 | 91 | 92 | java/test 93 | false 94 | 95 | **/*.java 96 | 97 | 98 | 99 | 100 | 101 | org.apache.maven.plugins 102 | maven-compiler-plugin 103 | 3.2 104 | 105 | 1.6 106 | 1.6 107 | 108 | 109 | 110 | org.apache.maven.plugins 111 | maven-surefire-plugin 112 | 2.18.1 113 | 114 | once 115 | -Dfile.encoding=UTF-8 116 | 117 | 118 | 119 | org.apache.maven.plugins 120 | maven-javadoc-plugin 121 | 122 | -Xdoclint:none 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | nutzcn-snapshots 131 | NutzCN snapshot repository 132 | https://jfrog.nutz.cn/artifactory/snapshots 133 | 134 | 135 | 136 | sonatype-release-staging 137 | Sonatype Nexus release repository 138 | https://oss.sonatype.org/service/local/staging/deploy/maven2 139 | 140 | 141 | 142 | 143 | nutz-snapshots 144 | https://jfrog.nutz.cn/artifactory/snapshots 145 | 146 | true 147 | always 148 | 149 | 150 | false 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/ZMongo.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.bson.Document; 7 | import org.nutz.lang.Lang; 8 | import org.nutz.lang.Mirror; 9 | import org.nutz.lang.Strings; 10 | import org.nutz.mongo.interceptor.MongoInterceptor; 11 | import org.nutz.mongo.interceptor.ZOperationExecutor; 12 | 13 | import com.mongodb.DB; 14 | import com.mongodb.MongoClient; 15 | import com.mongodb.MongoClientOptions; 16 | import com.mongodb.MongoClientURI; 17 | import com.mongodb.MongoCredential; 18 | import com.mongodb.ServerAddress; 19 | import com.mongodb.client.MongoCollection; 20 | import com.mongodb.operation.OperationExecutor; 21 | 22 | /** 23 | * 维持了一个与 MongoDB 的连接方式,包括用户名密码等 24 | * 25 | * @author zozoh(zozohtnt@gmail.com) 26 | */ 27 | public class ZMongo { 28 | 29 | public static ServerAddress NEW_SA(String host, int port) { 30 | try { 31 | return new ServerAddress(host, 32 | port <= 0 ? ServerAddress.defaultPort() 33 | : port); 34 | } 35 | catch (Exception e) { 36 | throw Lang.wrapThrow(e); 37 | } 38 | } 39 | 40 | public static ZMongo me() { 41 | return me("localhost", ServerAddress.defaultPort()); 42 | } 43 | 44 | public static ZMongo me(String host) { 45 | return me(host, ServerAddress.defaultPort()); 46 | } 47 | 48 | public static ZMongo me(String host, int port) { 49 | return me(NEW_SA(host, port), null); 50 | } 51 | 52 | public static ZMongo me(ServerAddress sa, MongoCredential cred) { 53 | return me(sa, cred, null); 54 | } 55 | 56 | public static ZMongo me(ServerAddress sa, 57 | MongoCredential cred, 58 | MongoClientOptions mopt) { 59 | return new ZMongo(sa == null ? null : Lang.list(sa), 60 | cred == null ? new ArrayList() : Lang.list(cred), 61 | mopt); 62 | } 63 | 64 | public static ZMongo me(List sas, 65 | List creds, 66 | MongoClientOptions mopt) { 67 | return new ZMongo(sas, creds, mopt); 68 | } 69 | 70 | public static ZMongo me(MongoClient mc) { 71 | return new ZMongo(mc); 72 | } 73 | 74 | public static ZMongo me(String userName, 75 | String password, 76 | String host, 77 | int port) { 78 | return me(userName, password, host, port, null); 79 | } 80 | 81 | public static ZMongo me(String userName, 82 | String password, 83 | String host, 84 | int port, 85 | String database) { 86 | return me(NEW_SA(host, port), 87 | MongoCredential.createScramSha1Credential(userName, 88 | database, 89 | password.toCharArray())); 90 | } 91 | 92 | public static ZMongo uri(String uri) { 93 | return new ZMongo(new MongoClient(new MongoClientURI(uri))); 94 | } 95 | 96 | /** 97 | * 保持一个连接实例 98 | */ 99 | private MongoClient moclient; 100 | 101 | private ZMongo(MongoClient mc) { 102 | this.moclient = mc; 103 | } 104 | 105 | public void close() { 106 | moclient.close(); 107 | } 108 | 109 | /** 110 | * 创建一个 MongoDB 的连接 111 | * 112 | * @param sas 113 | * 候选服务器连接地址 114 | * @param creds 115 | * 认证信息 116 | * @param mopt 117 | * 连接配置信息 118 | */ 119 | private ZMongo(List sas, 120 | List creds, 121 | MongoClientOptions mopt) { 122 | // 确保默认配置 123 | if (null == mopt) 124 | mopt = new MongoClientOptions.Builder().build(); 125 | this.moclient = new MongoClient(sas, creds, mopt); 126 | } 127 | 128 | /** 129 | * 获取数据库访问对象 130 | * 131 | * @param dbname 132 | * 数据库名称 133 | * @return 数据库封装对象 134 | */ 135 | public ZMoDB db(String dbname) { 136 | return db(dbname, null); 137 | } 138 | 139 | public ZMoDB db(String dbname, List interceptors) { 140 | DB db = new ZMongoDB2(moclient, dbname); 141 | if (interceptors != null && interceptors.size() > 0) { 142 | OperationExecutor proxy = (OperationExecutor) Mirror.me(DB.class).getValue(db, "executor"); 143 | ZOperationExecutor executor = new ZOperationExecutor(proxy, interceptors); 144 | Mirror.me(DB.class).setValue(db, "executor", executor); 145 | } 146 | return new ZMoDB(db); 147 | } 148 | 149 | /** 150 | * @return 当前服务器的数据库名称列表 151 | */ 152 | public List dbnames() { 153 | return moclient.listDatabaseNames().into(new ArrayList()); 154 | } 155 | 156 | 157 | /** 158 | * 获取collection对象 - 指定Collection 159 | * @param dbName 160 | * @param collName 161 | * @return 162 | */ 163 | public MongoCollection getMongoCollection(String dbName,String collName){ 164 | if (Strings.isBlank(dbName)) { 165 | return null; 166 | } 167 | if (Strings.isBlank(collName)) { 168 | return null; 169 | } 170 | return moclient.getDatabase(dbName).getCollection(collName); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/entity/ZMoEntity.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.entity; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | import org.nutz.lang.Lang; 8 | import org.nutz.lang.Mirror; 9 | import org.nutz.lang.Strings; 10 | import org.nutz.lang.born.Borning; 11 | import org.nutz.lang.eject.Ejecting; 12 | 13 | /** 14 | * 描述了一个对象字段到 Mongo Document 之间的字段映射关系 15 | * 16 | * @author zozoh(zozohtnt@gmail.com) 17 | */ 18 | public class ZMoEntity { 19 | 20 | enum Mode { 21 | MAP, POJO 22 | } 23 | 24 | /** 25 | * 在 holder 中保存的唯一键值 26 | */ 27 | private String key; 28 | 29 | /** 30 | * 指定了这个映射是 Map 还是 Pojo 31 | */ 32 | private Mode mode; 33 | 34 | /** 35 | * 对应的 Java 类型,如果是 Map 则表示 Map 的实现类 36 | */ 37 | private Class type; 38 | 39 | private Mirror mirror; 40 | 41 | /** 42 | * 保存了对象的实例生成方法,以便能较快速的生成对象 43 | */ 44 | private Borning borning; 45 | 46 | /** 47 | * 以 java 字段名为索引的映射字段表 48 | */ 49 | private Map byJava; 50 | 51 | /** 52 | * 以 mongoDB 字段名为索引的映射字段表 53 | */ 54 | private Map byMongo; 55 | 56 | /** 57 | * 默认的字段映射方法,这个字段,并不会在 getXXXXNames() 时出现 58 | */ 59 | private ZMoField defaultField; 60 | 61 | public ZMoEntity() { 62 | byJava = new HashMap(); 63 | byMongo = new HashMap(); 64 | defaultField = null; 65 | } 66 | 67 | public String getKey() { 68 | return key; 69 | } 70 | 71 | public void setKey(String key) { 72 | this.key = key; 73 | } 74 | 75 | public void setDefaultField(ZMoField defaultField) { 76 | this.defaultField = defaultField; 77 | } 78 | 79 | public ZMoEntity forMap() { 80 | mode = Mode.MAP; 81 | return this; 82 | } 83 | 84 | public ZMoEntity forPojo() { 85 | mode = Mode.POJO; 86 | return this; 87 | } 88 | 89 | public boolean isForMap() { 90 | return Mode.MAP == mode; 91 | } 92 | 93 | public boolean isForPojo() { 94 | return Mode.POJO == mode; 95 | } 96 | 97 | public Class getType() { 98 | return type; 99 | } 100 | 101 | public ZMoEntity setType(Class type) { 102 | this.type = type; 103 | this.mirror = Mirror.me(type); 104 | return this; 105 | } 106 | 107 | public Mirror getMirror() { 108 | return mirror; 109 | } 110 | 111 | public Object born(Object... args) { 112 | return borning.born(args); 113 | } 114 | 115 | public ZMoEntity setBorning(Borning borning) { 116 | this.borning = borning; 117 | return this; 118 | } 119 | 120 | public void addField(ZMoField fld) { 121 | fld.setParent(this); 122 | if (!Strings.isBlank(fld.getJavaName())) 123 | byJava.put(fld.getJavaName(), fld); 124 | if (!Strings.isBlank(fld.getMongoName())) 125 | byMongo.put(fld.getMongoName(), fld); 126 | } 127 | 128 | public Set getJavaNames(Object obj) { 129 | return byJava.keySet(); 130 | } 131 | 132 | public Set getMongoNames(Object obj) { 133 | return byMongo.keySet(); 134 | } 135 | 136 | public String getJavaNameFromMongo(String mongoName) { 137 | return mongoField(mongoName).getJavaName(); 138 | } 139 | 140 | public String getMongoNameFromJava(String javaName) { 141 | return javaField(javaName).getMongoName(); 142 | } 143 | 144 | /** 145 | * 获取实体字段 146 | * 147 | * @param name 148 | * 字段名 149 | * @return 实体字段,如果没找到回 defaultField 150 | */ 151 | public ZMoField getJavaField(String name) { 152 | ZMoField fld = byJava.get(name); 153 | return fld == null ? defaultField : fld; 154 | } 155 | 156 | /** 157 | * 获取实体字段 158 | * 159 | * @param name 160 | * 字段名 161 | * @return 实体字段,如果是 null 则抛错 162 | * @see #getField(String) 163 | */ 164 | public ZMoField javaField(String name) { 165 | ZMoField fld = getJavaField(name); 166 | if (null == fld) { 167 | throw Lang.makeThrow("no such field! %s->%s", type, name); 168 | } 169 | return fld; 170 | } 171 | 172 | /** 173 | * 获取实体字段 174 | * 175 | * @param name 176 | * 字段名 177 | * @return 实体字段,如果没找到回 defaultField 178 | */ 179 | public ZMoField getMongoField(String name) { 180 | ZMoField fld = byMongo.get(name); 181 | return fld == null ? defaultField : fld; 182 | } 183 | 184 | /** 185 | * 获取实体字段 186 | * 187 | * @param name 188 | * 字段名 189 | * @return 实体字段,如果是 null 则抛错 190 | * @see #getField(String) 191 | */ 192 | public ZMoField mongoField(String name) { 193 | ZMoField fld = getMongoField(name); 194 | if (null == fld) { 195 | throw Lang.makeThrow("no such field! %s->%s", type, name); 196 | } 197 | return fld; 198 | } 199 | 200 | /** 201 | * 获取对象某一特殊字段名称 202 | * 203 | * @param obj 204 | * 对象 205 | * @param javaName 206 | * 字段名 207 | * @return 字段值 208 | */ 209 | public Object getValue(Object obj, String javaName) { 210 | ZMoField fld = javaField(javaName); 211 | Ejecting ejecting = fld.getEjecting(); 212 | return ejecting.eject(obj); 213 | } 214 | 215 | /** 216 | * 为对象某特殊字段设置值 217 | * 218 | * @param obj 219 | * 对象 220 | * @param javaName 221 | * 字段名 222 | * @param value 223 | * 字段值 224 | */ 225 | public void setValue(Object obj, String javaName, Object value) { 226 | javaField(javaName).getInjecting().inject(obj, value); 227 | } 228 | 229 | public ZMoEntity clone() { 230 | ZMoEntity en = new ZMoEntity(); 231 | en.setType(type); 232 | en.setBorning(borning); 233 | en.mode = this.mode; 234 | for (Map.Entry fld : byJava.entrySet()) { 235 | ZMoField f2 = fld.getValue().clone(); 236 | f2.setParent(en); 237 | en.byJava.put(fld.getKey(), f2); 238 | } 239 | for (Map.Entry fld : byMongo.entrySet()) { 240 | ZMoField f2 = fld.getValue().clone(); 241 | f2.setParent(en); 242 | en.byMongo.put(fld.getKey(), f2); 243 | } 244 | return en; 245 | } 246 | 247 | } 248 | -------------------------------------------------------------------------------- /java/test/org/nutz/mongo/ZMoPetTest.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | import org.bson.types.ObjectId; 10 | import org.junit.Test; 11 | import org.nutz.mongo.pojo.Pet2; 12 | import org.nutz.lang.Lang; 13 | import org.nutz.lang.Times; 14 | import org.nutz.lang.random.R; 15 | import org.nutz.mongo.pojo.Human; 16 | import org.nutz.mongo.pojo.Pet; 17 | import org.nutz.mongo.pojo.PetColor; 18 | import org.nutz.mongo.pojo.PetType; 19 | 20 | import com.mongodb.BasicDBList; 21 | import com.mongodb.DBCursor; 22 | 23 | public class ZMoPetTest extends ZMoBaseTest { 24 | 25 | private ZMoCo c; 26 | 27 | @Override 28 | protected void prepare() { 29 | c = db.cc(Pet.CNAME, false); 30 | c.remove(ZMoDoc.NEW()); 31 | } 32 | 33 | @Test 34 | public void test_friends() { 35 | ZMoDoc doc = ZMoDoc.NEW("nm", "A").genID(); 36 | c.insert(doc); 37 | 38 | ZMoDoc d2 = ZMoDoc.NEW("nm", "B").putv("frs", Lang.array(doc.getId())); 39 | BasicDBList frs = (BasicDBList) d2.get("frs"); 40 | assertEquals(1, frs.size()); 41 | ObjectId theId = (ObjectId) frs.get(0); 42 | assertEquals(doc.getId(), theId); 43 | 44 | c.insert(d2); 45 | 46 | ZMoDoc d = c.findOne(ZMoDoc.NEW("nm", "B")); 47 | frs = (BasicDBList) d.get("frs"); 48 | assertEquals(1, frs.size()); 49 | theId = (ObjectId) frs.get(0); 50 | assertEquals(doc.getId(), theId); 51 | 52 | Pet pet = mo.fromDocToObj(d, Pet.class); 53 | assertEquals("B", pet.getName()); 54 | assertEquals(1, pet.getFriends().length); 55 | assertEquals(doc.getId(), pet.getFriends()[0]); 56 | } 57 | 58 | @Test 59 | public void test_dft_enum_should_be_str() { 60 | c.save(mo.toDoc(Pet.NEW("A").setType(PetType.CAT))); 61 | 62 | ZMoDoc doc = c.findOne(ZMoDoc.NEW("nm", "A")); 63 | assertEquals("CAT", doc.getString("tp")); 64 | } 65 | 66 | @Test 67 | public void test_query_by_age() { 68 | c.save(mo.toDoc(Pet.NEW("A").setAge(10))); 69 | c.save(mo.toDoc(Pet.NEW("B").setAge(11))); 70 | c.save(mo.toDoc(Pet.NEW("D").setAge(13))); 71 | c.save(mo.toDoc(Pet.NEW("C").setAge(12))); 72 | 73 | ZMoDoc q = ZMoDoc.NEW("{age:{$gt:12}}"); 74 | ZMoDoc doc = c.findOne(q); 75 | Pet pet = mo.fromDocToObj(doc, Pet.class); 76 | assertEquals("D", pet.getName()); 77 | assertEquals(13, pet.getAge()); 78 | } 79 | 80 | @Test 81 | public void test_update_inner_obj() { 82 | // 初始数据 83 | c.save(mo.toDoc(Pet.NEW("xiaobai"))); 84 | 85 | // 条件 86 | ZMoDoc q = ZMoDoc.NEW("nm", "xiaobai"); 87 | 88 | // 查出来看看 89 | Pet pet = mo.fromDocToObj(c.findOne(q), Pet.class); 90 | assertEquals(0, pet.getAge()); 91 | assertNull(pet.getMaster()); 92 | 93 | // 记录 ID 94 | String _id = pet.get_id(); 95 | 96 | // 改值 & 保存 97 | pet.setMaster(Human.NEW("zozoh")); 98 | c.save(mo.toDoc(pet)); 99 | 100 | // 再查出来看看 101 | ZMoDoc doc = c.findOne(q); 102 | pet = mo.fromDocToObj(doc, Pet.class); 103 | assertEquals(_id, pet.get_id()); 104 | assertEquals("zozoh", pet.getMaster().getName()); 105 | } 106 | 107 | @Test 108 | public void test_update_string_array() { 109 | // 初始数据 110 | c.save(mo.toDoc(Pet.NEW("xiaobai"))); 111 | 112 | // 条件 113 | ZMoDoc q = ZMoDoc.NEW("nm", "xiaobai"); 114 | 115 | // 查出来看看 116 | Pet pet = mo.fromDocToObj(c.findOne(q), Pet.class); 117 | assertEquals(0, pet.getAge()); 118 | assertNull(pet.getLabels()); 119 | 120 | // 记录 ID 121 | String _id = pet.get_id(); 122 | 123 | // 改值 & 保存 124 | pet.setAge(10); 125 | pet.setLabels(Lang.array("x", "y", "z")); 126 | c.save(mo.toDoc(pet)); 127 | 128 | // 再查出来看看 129 | ZMoDoc doc = c.findOne(q); 130 | pet = mo.fromDocToObj(doc, Pet.class); 131 | assertEquals(_id, pet.get_id()); 132 | assertEquals(10, pet.getAge()); 133 | assertArray(Lang.array("x", "y", "z"), pet.getLabels()); 134 | } 135 | 136 | @Test 137 | public void test_simple_query() { 138 | Pet[] pets = Pet.ARR("A", "B", "C"); 139 | c.insert(mo.toDocArray(pets)); 140 | 141 | assertEquals(3, c.count()); 142 | List list = new ArrayList(pets.length); 143 | DBCursor cur = c.find().sort(ZMoDoc.NEW("nm", -1)); 144 | while (cur.hasNext()) { 145 | list.add(mo.fromDocToObj(cur.next(), Pet.class)); 146 | } 147 | assertEquals(3, list.size()); 148 | assertEquals("C", list.get(0).getName()); 149 | assertEquals("B", list.get(1).getName()); 150 | assertEquals("A", list.get(2).getName()); 151 | 152 | c.remove(ZMoDoc.NEW("nm", "B")); 153 | 154 | assertEquals(2, c.count()); 155 | list = new ArrayList(pets.length); 156 | cur = c.find().sort(ZMoDoc.NEW("nm", -1)); 157 | while (cur.hasNext()) { 158 | list.add(mo.fromDocToObj(cur.next(), Pet.class)); 159 | } 160 | assertEquals(2, list.size()); 161 | assertEquals("C", list.get(0).getName()); 162 | assertEquals("A", list.get(1).getName()); 163 | 164 | } 165 | 166 | @Test 167 | public void test_findOne() { 168 | Pet p0 = Pet.NEW("wendal") 169 | .setAge(28) 170 | .setBornAt(Times.D("1985-04-21 12:45:21")) 171 | .setColor(PetColor.BLUE) 172 | .setType(PetType.HAMSTER) 173 | .setComment("V4 animal"); 174 | ZMoDoc d0 = mo.toDoc(p0); 175 | c.save(d0); 176 | 177 | ZMoDoc d1 = c.findOne(); 178 | Pet p1 = mo.fromDocToObj(d1, Pet.class); 179 | 180 | assertEquals(p0.getName(), p1.getName()); 181 | assertEquals(Times.sD(p0.getBornAt()), Times.sD(p1.getBornAt())); 182 | assertEquals(p0.getAge(), p1.getAge()); 183 | assertEquals(p0.getColor(), p1.getColor()); 184 | assertEquals(p0.getType(), p1.getType()); 185 | assertTrue(ZMo.isObjectId(p1.get_id())); 186 | assertNull(p1.getComment()); 187 | } 188 | 189 | @Test 190 | public void test_issue8() { 191 | // 初始数据 192 | Pet2 pet2 = new Pet2(); 193 | 194 | // 改值 & 保存 195 | pet2.setName(R.UU32()); 196 | pet2.setAge(10); 197 | pet2.setPets(Arrays.asList(Pet.NEW(R.UU32()), Pet.NEW(R.UU32()))); 198 | c.save(mo.toDoc(pet2)); 199 | 200 | // 再查出来看看 201 | ZMoDoc doc = c.findOne(ZMoDoc.NEW("nm", pet2.getName())); 202 | Pet2 pet = mo.fromDocToObj(doc, Pet2.class); 203 | //assertEquals(pet2.get_id(), pet.get_id()); 204 | assertEquals(10, pet.getAge()); 205 | for (Pet p : pet.getPets()) { 206 | assertNotNull(p.getName()); 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/entity/ZMoEntityMaker.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo.entity; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Modifier; 5 | import java.util.Collection; 6 | import java.util.HashMap; 7 | import java.util.LinkedHashSet; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.Queue; 12 | import java.util.Set; 13 | 14 | import org.nutz.lang.Lang; 15 | import org.nutz.lang.Mirror; 16 | import org.nutz.lang.Strings; 17 | import org.nutz.lang.born.ArrayBorning; 18 | import org.nutz.lang.eject.EjectFromMap; 19 | import org.nutz.lang.inject.InjectToMap; 20 | import org.nutz.mongo.adaptor.ZMoAs; 21 | import org.nutz.mongo.annotation.MoEnum; 22 | import org.nutz.mongo.annotation.MoField; 23 | import org.nutz.mongo.annotation.MoIgnore; 24 | 25 | /** 26 | * 一个 ZMoEntity 字段映射关系的生成器,可以给一个 Map 来自由的描述这个映射关系:
27 | * Map 的格式定义如下 28 | * 29 | *
 30 |  * {
 31 |  *      _class: 'org.nutz.pojo.Pet',   // [选]对象的实现类,如果是 Map 也会指定实现类
 32 |  *      
 33 |  *      'name': 'nm',     // 下面就是数据库映射,  "Java名" : "数据库字段名"
 34 |  *      ...
 35 |  * }
 36 |  * 
37 | *
    38 | *
  • 如果一个 map 必选字段是非法的 39 | *
  • 指定了 _class 或者 _type 任何一个,都有办法来确认另外一个值 40 | *
41 | * 42 | * @author zozoh(zozohtnt@gmail.com) 43 | */ 44 | public class ZMoEntityMaker { 45 | 46 | /** 47 | * 根据传入的参考对象,构建一个映射实体。 48 | * 49 | * @param obj 50 | * 实体参考对象,可以是 POJO, Class, 或者 Map 51 | * @return 映射实体 52 | */ 53 | @SuppressWarnings("unchecked") 54 | public ZMoEntity make(Object obj) { 55 | Mirror mi = Mirror.me(obj); 56 | if (mi.isMap()) { 57 | // 如果传入的就是 Map 的 Class 58 | if (obj instanceof Class) { 59 | ZMoGeneralMapEntity en = new ZMoGeneralMapEntity(); 60 | // 如果传入的类不是抽象类,那么必然是一个可实例化的 Map 61 | if (!Modifier.isAbstract(((Class) obj).getModifiers())) { 62 | en.setType(mi.getType()); 63 | en.setBorning(mi.getBorning()); 64 | } 65 | return en; 66 | } 67 | 68 | // 否则传入的一定是个 Map 实例,根据内容来构建实体咯 69 | return makeMapEntity((Map) obj); 70 | } 71 | return makePojoEntity(mi.getType()); 72 | } 73 | 74 | /** 75 | * 根据一个特殊的 Map 来构建 POJO-ZMoDoc 映射关系 76 | * 77 | * @param pojoType 78 | * 对象类型 79 | * @return 映射关系对象 80 | */ 81 | private ZMoEntity makePojoEntity(Class pojoType) { 82 | Mirror mi = Mirror.me(pojoType); 83 | // 保证给的是个 POJO 类型 84 | if (!mi.isPojo()) { 85 | throw Lang.makeThrow("!! %s is NOT a kind of POJO", pojoType); 86 | } 87 | // 开始创建实体 88 | ZMoEntity en = new ZMoEntity().forPojo(); 89 | en.setType(pojoType); 90 | en.setBorning(mi.getBorning()); 91 | 92 | // 构建映射字段 93 | for (Field fld : mi.getFields()) { 94 | // 临时字段忽略 95 | if (Modifier.isTransient(fld.getModifiers())) 96 | continue; 97 | // 特殊指明要忽略的字段也要忽略 98 | if (null != fld.getAnnotation(MoIgnore.class)) 99 | continue; 100 | 101 | // 创建实体 102 | ZMoField mof = new ZMoField(); 103 | 104 | // 设置映射关系 105 | mof.setJavaName(fld.getName()); 106 | MoField anFld = fld.getAnnotation(MoField.class); 107 | if (null == anFld || Strings.isBlank(anFld.value())) { 108 | mof.setMongoName(fld.getName()); 109 | } else { 110 | mof.setMongoName(anFld.value()); 111 | } 112 | 113 | // 对枚举的特殊配置 114 | MoEnum anEnum = fld.getAnnotation(MoEnum.class); 115 | if (null != anEnum) { 116 | mof.setEnumStr(anEnum.str()); 117 | } 118 | // 没声明,默认用 string 表示 ENUM 119 | else { 120 | mof.setEnumStr(true); 121 | } 122 | 123 | // 处理字段类型相关的适配方法 124 | mof.setType(fld.getType()); 125 | Mirror fmi = Mirror.me(fld.getType()); 126 | mof.setAdaptor(ZMoAs.get(fmi)); 127 | mof.setEjecting(mi.getEjecting(fld)); 128 | mof.setInjecting(mi.getInjecting(fld.getName())); 129 | 130 | /* 131 | * 处理字段对象的生成方式,只有容器或者数组比较特殊 132 | */ 133 | // Collection 134 | if (fmi.isCollection()) { 135 | // 获得元素类型 136 | mof.setEleType(Mirror.getGenericTypes(fld, 0)); 137 | if (null == mof.getEleType()) { 138 | throw Lang.makeThrow("can not fould eleType for fld %s of %s", 139 | fld.getName(), 140 | mi.getType()); 141 | } 142 | 143 | // 如果不是抽象的,那么就用这个类型来生成对象实例 144 | if (!Modifier.isAbstract(fmi.getType().getModifiers())) { 145 | mof.setBorning(fmi.getBorning()); 146 | } 147 | // 抽象类型 Collection 148 | // 抽象类型 List 149 | // 抽象类型 Queue 150 | else if (fmi.is(Collection.class) || fmi.is(List.class) || fmi.is(Queue.class)) { 151 | mof.setBorning(Mirror.me(LinkedList.class).getBorning()); 152 | } 153 | // 抽象类型 Set 154 | else if (fmi.is(Set.class)) { 155 | mof.setBorning(Mirror.me(LinkedHashSet.class).getBorning()); 156 | } 157 | // 其他类型,抛错 158 | else { 159 | throw Lang.makeThrow("can not found borning for %s", fmi.getType()); 160 | } 161 | 162 | } 163 | // 数组 164 | else if (fmi.isArray()) { 165 | // 获得元素类型 166 | mof.setEleType(fld.getType().getComponentType()); 167 | // 为数组创建一个生成方式 168 | mof.setBorning(new ArrayBorning(mof.getEleType())); 169 | } 170 | 171 | // 加入到实体中 172 | en.addField(mof); 173 | } 174 | 175 | // 返回 176 | return en; 177 | } 178 | 179 | /** 180 | * 根据一个特殊的 Map 来构建 Map-ZMoDoc 映射关系 181 | * 182 | * @param map 183 | * 一个描述映射关系的 Map 对象 184 | * @return 映射关系对象 185 | */ 186 | public ZMoEntity makeMapEntity(Map map) { 187 | Mirror mi = null; 188 | // 看看是不是指定了实体的特殊实现类名称 189 | if (map.containsKey("_class")) { 190 | try { 191 | mi = Mirror.me(Class.forName(map.get("_class").toString())); 192 | } 193 | catch (ClassNotFoundException e) { 194 | throw Lang.wrapThrow(e); 195 | } 196 | } 197 | 198 | // 准备创建实体 199 | ZMoEntity en = null; 200 | 201 | /* 202 | * 如果指定的实现类是个 POJO,那么就先根据类定义构建它 203 | */ 204 | if (null != mi && mi.isPojo()) { 205 | en = makePojoEntity(mi.getType()); 206 | } 207 | // 如果不是 POJO 那就是 Map 咯,创建一个 Map 实体 208 | else { 209 | en = new ZMoEntity().forMap(); 210 | // 设置实体的 Java 实现类类型 211 | if (null == mi) 212 | en.setType(HashMap.class); 213 | else 214 | en.setType(mi.getType()); 215 | // 设置实体需要其他字段 216 | en.setBorning(en.getMirror().getBorning()); 217 | 218 | en.setDefaultField(new ZMoGeneralMapField()); 219 | } 220 | 221 | /* 222 | * 处理纯 Map 的映射 223 | */ 224 | for (String key : map.keySet()) { 225 | // 忽略空值 226 | String val = Strings.sNull(map.get(key), null); 227 | if (null == val) 228 | continue; 229 | // 忽略隐藏属性 230 | if (key.startsWith("_")) 231 | continue; 232 | // 逐个处理每个字段 233 | ZMoField fld = new ZMoField(); 234 | fld.setType(Object.class); 235 | fld.setJavaName(key); 236 | fld.setMongoName(val); 237 | fld.setAdaptor(ZMoAs.smart()); 238 | fld.setBorning(Mirror.me(HashMap.class).getBorning()); 239 | fld.setEjecting(new EjectFromMap(key)); 240 | fld.setInjecting(new InjectToMap(key)); 241 | en.addField(fld); 242 | } 243 | return en; 244 | } 245 | 246 | } 247 | -------------------------------------------------------------------------------- /mvn_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 46 | 49 | 55 | 56 | 64 | 65 | 72 | 73 | 78 | 79 | 83 | 84 | 85 | 90 | 91 | 105 | 106 | 107 | 111 | 112 | 125 | 126 | 127 | nutzcn-snapshots 128 | ${env.S_NUTZMAVEN_USER_ID} 129 | ${env.S_NUTZMAVEN_USER_PWD} 130 | 131 | 132 | 139 | 140 | 141 | 152 | 153 | 157 | 158 | 159 | 160 | 181 | 182 | 211 | 212 | 246 | 247 | 248 | 256 | 257 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/ZMo.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.regex.Pattern; 11 | 12 | import org.bson.types.ObjectId; 13 | import org.nutz.json.Json; 14 | import org.nutz.json.JsonFormat; 15 | import org.nutz.json.entity.JsonCallback; 16 | import org.nutz.lang.Lang; 17 | import org.nutz.lang.Mirror; 18 | import org.nutz.lang.util.NutMap; 19 | import org.nutz.mongo.adaptor.ZMoAs; 20 | import org.nutz.mongo.entity.ZMoEntity; 21 | import org.nutz.mongo.entity.ZMoEntityHolder; 22 | import org.nutz.mongo.entity.ZMoEntityMaker; 23 | import org.nutz.mongo.entity.ZMoField; 24 | import org.nutz.mongo.entity.ZMoGeneralMapEntity; 25 | import org.nutz.mongo.fieldfilter.ZMoFF; 26 | 27 | import com.mongodb.Cursor; 28 | import com.mongodb.DBObject; 29 | 30 | /** 31 | * 一个工厂类,用来转换普通 JavaObject 与 ZMoDoc 对象 32 | * 33 | * @author zozoh(zozohtnt@gmail.com) 34 | */ 35 | public class ZMo { 36 | 37 | /** 38 | * @return 一个新创建的文档 39 | */ 40 | public ZMoDoc newDoc() { 41 | return ZMoDoc.NEW(); 42 | } 43 | 44 | /** 45 | * @return 对象映射生成器 46 | */ 47 | public ZMoEntityMaker maker() { 48 | return maker; 49 | } 50 | 51 | /** 52 | * 将任何 Java 对象(也包括 ZMoDoc)转换成 ZMoDoc 53 | * 54 | * @param obj 55 | * Java 对象,可以是 Pojo 或者 Map 56 | * @return 文档对象 57 | */ 58 | public ZMoDoc toDoc(Object obj) { 59 | ZMoEntity en; 60 | // 如果 NULL 直接返回咯 61 | if (null == obj) { 62 | return null; 63 | } 64 | // 本身就是 DBObject 65 | else if (obj instanceof DBObject) { 66 | return ZMoDoc.WRAP((DBObject) obj); 67 | } 68 | // 普通 Map 69 | else if (obj instanceof Map) { 70 | Map map = (Map) obj; 71 | // 获取 Map 的 KEY 72 | String _key = (String) map.get("_key"); 73 | // 获取映射关系 74 | if (null == _key) { 75 | en = getEntity(obj.getClass()); 76 | } else { 77 | en = holder.get(_key); 78 | } 79 | // 确定一定会有映射关系 80 | if (null == en) { 81 | throw Lang.makeThrow("Map[%s] without define!", _key); 82 | } 83 | } 84 | // POJO 85 | else { 86 | Class objType = obj.getClass(); 87 | // 数组不可以 88 | if (objType.isArray()) { 89 | throw Lang.makeThrow("Array can not toDoc : %s", objType.getName()); 90 | } 91 | // 集合不可以 92 | else if (obj instanceof Collection) { 93 | throw Lang.makeThrow("Collection can not toDoc : %s", objType.getName()); 94 | } 95 | // POJO 96 | else { 97 | en = getEntity(objType); 98 | } 99 | } 100 | // 执行转换 101 | return toDoc(obj, en); 102 | } 103 | 104 | /** 105 | * 根据一个 JSON 字符串生成的 Map 对象来生成 ZMoDoc 对象 106 | * 107 | * @param json 108 | * JSON 字符串,可以省略前后的大括号,即,可以是 "x:100,y:'23'" 109 | * @param args 110 | * 如果参数 json 为一个格式化字符串模板,那么这里给出参数 111 | * @return 文档对象 112 | */ 113 | public ZMoDoc toDoc(String json, Object... args) { 114 | return toDoc(Lang.mapf(json, args)); 115 | } 116 | 117 | /** 118 | * 将任何一个对象转换成 ZMoDoc,并强制指定映射关系 119 | * 120 | * @param obj 121 | * Java 对象,可以是 Pojo 或者 Map 122 | * @param en 123 | * 映射关系,如果为 null 相当于 toDoc(obj) 124 | * @return 文档对象 125 | */ 126 | public ZMoDoc toDoc(Object obj, ZMoEntity en) { 127 | ZMoDoc doc = ZMoDoc.NEW(); 128 | Set javaNames = en.getJavaNames(obj); 129 | // 获取字段过滤器 130 | ZMoFF ff = ZMoFF.get(); 131 | 132 | // 循环每个字段 133 | for (String javaName : javaNames) { 134 | Object v = en.getValue(obj, javaName); 135 | ZMoField fld = en.javaField(javaName); 136 | /* 137 | * 是否需要过滤 138 | */ 139 | if (null != ff && ff.isIgnore(fld, v)) { 140 | continue; 141 | } 142 | /* 143 | * 适配值 144 | */ 145 | String mongoName = en.getMongoNameFromJava(javaName); 146 | // 空值 147 | if (null == v) { 148 | doc.put(mongoName, v); 149 | } 150 | // _id 151 | else if ("_id".equals(mongoName)) { 152 | if (v instanceof ObjectId || v instanceof Boolean || v instanceof Integer || v instanceof Long) { 153 | doc.put(mongoName, v); 154 | } else { 155 | try { 156 | doc.put(mongoName, new ObjectId(v.toString())); 157 | } 158 | catch (IllegalArgumentException e) { 159 | doc.put(mongoName, v); 160 | } 161 | } 162 | } 163 | // 其他值适配 164 | else { 165 | Object dbv = fld.getAdaptor().toMongo(fld, v); 166 | doc.put(mongoName, dbv); 167 | } 168 | } 169 | return doc; 170 | } 171 | 172 | /** 173 | * 将一组 Java 对象变成文档数组 174 | * 175 | * @param objs 176 | * Java 对象数组 177 | * @return 文档数组 178 | */ 179 | public ZMoDoc[] toDocArray(Object[] objs) { 180 | return toDocArray(null, objs); 181 | } 182 | 183 | /** 184 | * 将一组 Java 对象变成文档数组 185 | * 186 | * @param objs 187 | * Java 对象数组 188 | * @return 文档数组 189 | */ 190 | public ZMoDoc[] toDocArray(List objs) { 191 | return toDocArray(null, objs); 192 | } 193 | 194 | /** 195 | * 将一组 Java 对象变成文档数组,并强制指定映射关系,以便提高速度 196 | * 197 | * @param en 198 | * 映射关系,如果为 null 则自动判断如何映射 199 | * @param objs 200 | * Java 对象数组 201 | * @return 文档数组 202 | */ 203 | public ZMoDoc[] toDocArray(ZMoEntity en, Object[] objs) { 204 | ZMoDoc[] docs = new ZMoDoc[objs.length]; 205 | if (objs.length > 0) 206 | en = this.getEntity(objs[0].getClass()); 207 | int i = 0; 208 | for (Object obj : objs) 209 | docs[i++] = toDoc(obj, en); 210 | return docs; 211 | } 212 | 213 | /** 214 | * 将一组 Java 对象变成文档数组,并强制指定映射关系,以便提高速度 215 | * 216 | * @param en 217 | * 映射关系,如果为 null 则自动判断如何映射 218 | * @param objs 219 | * Java 对象数组 220 | * @return 文档数组 221 | */ 222 | public ZMoDoc[] toDocArray(ZMoEntity en, List objs) { 223 | ZMoDoc[] docs = new ZMoDoc[objs.size()]; 224 | if (!objs.isEmpty()) 225 | en = this.getEntity(objs.get(0).getClass()); 226 | int i = 0; 227 | for (Object obj : objs) 228 | docs[i++] = toDoc(obj, en); 229 | return docs; 230 | } 231 | 232 | /** 233 | * 将一组 Java 对象变成文档列表 234 | * 235 | * @param objs 236 | * Java 对象数组 237 | * @return 文档列表 238 | */ 239 | public List toDocList(Object[] objs) { 240 | return toDocList(null, objs); 241 | } 242 | 243 | /** 244 | * 将一组 Java 对象变成文档列表 245 | * 246 | * @param objs 247 | * Java 对象数组 248 | * @return 文档列表 249 | */ 250 | public List toDocList(List objs) { 251 | return toDocList(null, objs); 252 | } 253 | 254 | /** 255 | * 将一组 Java 对象变成文档列表,并强制指定映射关系,以便提高速度 256 | * 257 | * @param en 258 | * 映射关系,如果为 null 则自动判断如何映射 259 | * @param objs 260 | * Java 对象数组 261 | * @return 文档列表 262 | */ 263 | public List toDocList(ZMoEntity en, Object[] objs) { 264 | List docs = new ArrayList(objs.length); 265 | for (Object obj : objs) 266 | docs.add(toDoc(obj, null)); 267 | return docs; 268 | } 269 | 270 | /** 271 | * 将一组 Java 对象变成文档列表,并强制指定映射关系,以便提高速度 272 | * 273 | * @param en 274 | * 映射关系,如果为 null 则自动判断如何映射 275 | * @param objs 276 | * Java 对象数组 277 | * @return 文档列表 278 | */ 279 | public List toDocList(ZMoEntity en, List objs) { 280 | List docs = new ArrayList(objs.size()); 281 | for (Object obj : objs) 282 | docs.add(toDoc(obj, null)); 283 | return docs; 284 | } 285 | 286 | /** 287 | * 将任何一个文档对象转换成 ZMoDoc,
288 | * 根据传入的映射关系来决定是变成 Pojo还是Map 289 | * 290 | * @param dbobj 291 | * 文档对象 292 | * @param en 293 | * 映射关系,如果为 null,则变成普通 Map 294 | * @return 普通Java对象 295 | */ 296 | public Object fromDoc(DBObject dbobj, ZMoEntity en) { 297 | if (null == dbobj) 298 | return null; 299 | ZMoDoc doc = ZMoDoc.WRAP(dbobj); 300 | if (null == en) { 301 | en = holder.get(DFT_MAP_KEY); 302 | } 303 | Object obj = en.born(); 304 | Set keys = en.getMongoNames(doc); 305 | for (String key : keys) { 306 | try { 307 | // 获得映射关系 308 | ZMoField fld = en.mongoField(key); 309 | String javaName = en.getJavaNameFromMongo(key); 310 | String mongoName = en.getMongoNameFromJava(javaName); 311 | 312 | // 获取值 313 | Object v = doc.get(mongoName); 314 | Object pojov; 315 | 316 | // 空值 317 | if (null == v) { 318 | pojov = null; 319 | } 320 | // _id 321 | else if ("_id".equals(key)) { 322 | pojov = ZMoAs.id().toJava(fld, v); 323 | } 324 | // 其他值适配 325 | else { 326 | pojov = fld.getAdaptor().toJava(fld, v); 327 | } 328 | // 设置值 329 | 330 | en.setValue(obj, javaName, pojov); 331 | } 332 | catch (Exception e) { 333 | throw Lang.wrapThrow(e, "fail to set field %s#%s", en.getType(), key); 334 | } 335 | } 336 | return obj; 337 | } 338 | 339 | /** 340 | * 将任何一个文档对象转换成指定 Java 对象(不可以是 Map 等容器) 341 | * 342 | * @param 343 | * 对象的类型参数 344 | * @param dbobj 345 | * 文档对象 346 | * @param classOfT 347 | * 对象类型,根据这个类型可以自动获得映射关系 348 | * @return 特定的Java对象 349 | */ 350 | @SuppressWarnings("unchecked") 351 | public T fromDocToObj(DBObject dbobj, Class classOfT) { 352 | return (T) (fromDoc(dbobj, getEntity(classOfT))); 353 | } 354 | 355 | /** 356 | * 将任何一个文档对象转换成一个 Map 对象 357 | * 358 | * @param dbobj 359 | * 文档对象 360 | * @return Map 对象 361 | */ 362 | @SuppressWarnings("unchecked") 363 | public Map fromDocToMap(DBObject dbobj) { 364 | return (Map) fromDoc(dbobj, null); 365 | } 366 | 367 | /** 368 | * 将任何一个文档对象转换成一个指定类型的 Map 对象 369 | * 370 | * @param 371 | * Map 对象的类型参数 372 | * @param dbobj 373 | * 文档对象 374 | * @return Map 对象 375 | */ 376 | @SuppressWarnings("unchecked") 377 | public > T fromDocToMap(DBObject dbobj, 378 | Class classOfMap) { 379 | return (T) fromDoc(dbobj, getEntity(classOfMap)); 380 | } 381 | 382 | /** 383 | * 根据对象类型,得到一个映射关系(懒加载) 384 | * 385 | * @param type 386 | * 对象类型可以是 POJO 或者 Map 387 | * @return 映射关系 388 | */ 389 | public ZMoEntity getEntity(Class type) { 390 | ZMoEntity en = holder.get(type.getName()); 391 | // 如果木有加载过,那么尝试加载 392 | if (null == en) { 393 | synchronized (this) { 394 | en = holder.get(type.getName()); 395 | if (null == en) { 396 | // 如果是 Map 或者 DBObject 用默认Map映射对象来搞 397 | if (Map.class.isAssignableFrom(type) 398 | || DBObject.class.isAssignableFrom(type)) { 399 | en = holder.get(DFT_MAP_KEY).clone(); 400 | en.setType(type); 401 | en.setBorning(en.getMirror().getBorning()); 402 | holder.add(type.getName(), en); 403 | } 404 | // 普通 POJO 405 | else { 406 | en = maker.make(type); 407 | holder.add(type.getName(), en); 408 | } 409 | } 410 | } 411 | } 412 | return en; 413 | } 414 | 415 | /** 416 | * @return 对象映射持有器 417 | */ 418 | public ZMoEntityHolder holder() { 419 | return holder; 420 | } 421 | 422 | // ------------------------------------------------------------ 423 | // 下面是这个类的字段和单例方法 424 | private static ZMo _me_ = new ZMo(); 425 | 426 | /** 427 | * 默认的 Map 映射实体键值 428 | */ 429 | public static final String DFT_MAP_KEY = "$nutz-mongo-dftmap-key$"; 430 | 431 | // 这里创建一个默认的 Map 实体 432 | static { 433 | _me_.holder.add(DFT_MAP_KEY, new ZMoGeneralMapEntity()); 434 | } 435 | 436 | /** 437 | * @return 单例 438 | */ 439 | public static ZMo me() { 440 | return _me_; 441 | } 442 | 443 | private ZMoEntityHolder holder; 444 | 445 | private ZMoEntityMaker maker; 446 | 447 | private ZMo() { 448 | holder = new ZMoEntityHolder(); 449 | maker = new ZMoEntityMaker(); 450 | } 451 | 452 | // 453 | // 下面是一下常用的帮助函数 454 | // 455 | 456 | private static final Pattern OBJ_ID = Pattern.compile("^[0-9a-f]{24}$"); 457 | 458 | /** 459 | * 判断给定的字符串是否是 MongoDB 默认的 ID 格式 460 | * 461 | * @param ID 462 | * 给定 ID 463 | * @return true or false 464 | */ 465 | public static boolean isObjectId(String ID) { 466 | if (null == ID || ID.length() != 24) 467 | return false; 468 | return OBJ_ID.matcher(ID).find(); 469 | } 470 | 471 | static { 472 | try { 473 | Json.getEntity(Mirror.me(ObjectId.class)).setJsonCallback(new JsonCallback() { 474 | public boolean toJson(Object obj, JsonFormat jf, Writer writer) throws IOException { 475 | writer.write("\"" + ((ObjectId)obj).toHexString()+"\""); 476 | return true; 477 | } 478 | public Object fromJson(Object obj) { 479 | return null; 480 | } 481 | }); 482 | } 483 | catch (Exception e) { 484 | // 不可能吧? 485 | } 486 | } 487 | 488 | public List fromDoc(Cursor cursor, ZMoEntity en) { 489 | List list = new ArrayList(); 490 | while (cursor.hasNext()) { 491 | list.add(fromDoc(cursor.next(), en)); 492 | } 493 | return list; 494 | } 495 | } 496 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/ZMoDoc.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.ArrayList; 5 | import java.util.Date; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | import org.bson.BSONObject; 11 | import org.bson.types.ObjectId; 12 | import org.nutz.castor.Castors; 13 | import org.nutz.lang.Each; 14 | import org.nutz.lang.Lang; 15 | import org.nutz.lang.Strings; 16 | import org.nutz.lang.util.NutMap; 17 | import org.nutz.mongo.adaptor.ZMoAs; 18 | 19 | import com.mongodb.BasicDBObject; 20 | import com.mongodb.DBObject; 21 | 22 | /** 23 | * 包裹了 DBObject,并提供了一些更便利的方法 24 | * 25 | * @author zozoh(zozohtnt@gmail.com) 26 | */ 27 | public class ZMoDoc implements DBObject { 28 | 29 | private DBObject DBobj; 30 | 31 | public static ZMoDoc NEW() { 32 | return new ZMoDoc().setDBobj(new BasicDBObject()); 33 | } 34 | 35 | public static ZMoDoc NEW(int size) { 36 | return NEW().setDBobj(new BasicDBObject(size)); 37 | } 38 | 39 | public static ZMoDoc NEW(Map m) { 40 | ZMoDoc doc = NEW(); 41 | doc.putAll(m); 42 | return doc; 43 | } 44 | 45 | public static ZMoDoc NEW(String key, Object v) { 46 | return NEW().putv(key, v); 47 | } 48 | 49 | public static ZMoDoc ID(Object id) { 50 | return NEW().putv("_id", id); 51 | } 52 | 53 | public static ZMoDoc IN(String key, T[] vs) { 54 | return NEW().in(key, vs); 55 | } 56 | 57 | public static ZMoDoc ALL(String key, T[] vs) { 58 | return NEW().all(key, vs); 59 | } 60 | 61 | public static ZMoDoc NOID() { 62 | return NEW().putv("_id", 0); 63 | } 64 | 65 | public static ZMoDoc NOID(String key, int v) { 66 | return NOID().putv(key, v); 67 | } 68 | 69 | public static ZMoDoc SET(String key, Object v) { 70 | return NEW().set(key, v); 71 | } 72 | 73 | public static ZMoDoc SET(DBObject dbo) { 74 | return NEW().set(dbo); 75 | } 76 | 77 | public static ZMoDoc M(String mnm, String key, Object v) { 78 | return NEW().m(mnm, key, v); 79 | } 80 | 81 | public static ZMoDoc NEW(String json) { 82 | return NEW(Lang.map(json)); 83 | } 84 | 85 | public static ZMoDoc NEWf(String jsonf, Object... args) { 86 | return NEW(Lang.mapf(jsonf, args)); 87 | } 88 | 89 | public static ZMoDoc WRAP(DBObject obj) { 90 | if (null == obj) 91 | return null; 92 | if (obj instanceof ZMoDoc) 93 | return (ZMoDoc) obj; 94 | return new ZMoDoc().setDBobj(obj); 95 | } 96 | 97 | /** 98 | * 重新生成 _id 99 | * 100 | * @return 自身以便链式赋值 101 | */ 102 | public ZMoDoc genID() { 103 | DBobj.put("_id", new ObjectId()); 104 | return this; 105 | } 106 | 107 | /** 108 | * 删除自身的 _id 字段,以便作为一个新对象插入到数据库中 109 | */ 110 | public ZMoDoc asNew() { 111 | DBobj.removeField("_id"); 112 | return this; 113 | } 114 | 115 | public DBObject getDBobj() { 116 | return DBobj; 117 | } 118 | 119 | public ZMoDoc setDBobj(DBObject dBobj) { 120 | DBobj = dBobj; 121 | return this; 122 | } 123 | 124 | public ZMoDoc putv(String key, Object v) { 125 | put(key, v); 126 | return this; 127 | } 128 | 129 | public ZMoDoc rm(String... keys) { 130 | for (String key : keys) 131 | this.removeField(key); 132 | return this; 133 | } 134 | 135 | public ZMoDoc in(String key, T[] vs) { 136 | put(key, NEW("$in", vs)); 137 | return this; 138 | } 139 | 140 | public ZMoDoc nin(String key, T[] vs) { 141 | put(key, NEW("$nin", vs)); 142 | return this; 143 | } 144 | 145 | public ZMoDoc all(String key, T[] vs) { 146 | put(key, NEW("$all", vs)); 147 | return this; 148 | } 149 | 150 | // ------------------------------------------------------------ 151 | // 下面是一些便捷的方法用来设置常用的值 152 | /** 153 | * 本函数会设置 "$set" : {...} ,如果没有 "$set" 键,会添加 154 | * 155 | * @param key 156 | * 要设置字段的名称 157 | * @param v 158 | * 要设置字段的值 159 | * @return 自身以便链式赋值 160 | */ 161 | public ZMoDoc set(String key, Object v) { 162 | return m("$set", key, v); 163 | } 164 | 165 | /** 166 | * 本函数会将一个字段对象变为 $set,如果已经有了 $set 则合并 167 | * 168 | * @param dbo 169 | * 文档对象 170 | * @return 自身以便链式赋值 171 | */ 172 | public ZMoDoc set(DBObject dbo) { 173 | DBObject o = getAs("$set", DBObject.class); 174 | if (null == o) { 175 | put("$set", dbo); 176 | } else { 177 | o.putAll(dbo); 178 | } 179 | return this; 180 | } 181 | 182 | /** 183 | * 删除一组字段。 相当于 $unset : {a:1,b:1...} 184 | * 185 | * @param keys 186 | * 字段名 187 | * @return 自身以便链式赋值 188 | */ 189 | public ZMoDoc unset(String... keys) { 190 | for (String key : keys) { 191 | m("$unset", key, 1); 192 | } 193 | return this; 194 | } 195 | 196 | /** 197 | * 本函数会设置 "mnm" : {...} ,如果没有修改器的键,会添加这个对象,如果有,合并 198 | * 199 | * @param mnm 200 | * 修改器名称 201 | * @param key 202 | * 键 203 | * @param v 204 | * 值 205 | * @return 自身以便链式赋值 206 | */ 207 | public ZMoDoc m(String mnm, String key, Object v) { 208 | DBObject o = getAs(mnm, DBObject.class); 209 | if (null == o) { 210 | o = ZMoDoc.NEW(); 211 | put(mnm, o); 212 | } 213 | o.put(key, v); 214 | return this; 215 | } 216 | 217 | public ZMoDoc exists(String nm, boolean exists) { 218 | put(nm, NEW("$exists", exists)); 219 | return this; 220 | } 221 | 222 | public ZMoDoc eq(String nm, Object v) { 223 | put(nm, NEW("$eq", v)); 224 | return this; 225 | } 226 | 227 | public ZMoDoc ne(String nm, Object v) { 228 | put(nm, NEW("$ne", v)); 229 | return this; 230 | } 231 | 232 | public ZMoDoc gte(String nm, Object v) { 233 | put(nm, NEW("$gte", v)); 234 | return this; 235 | } 236 | 237 | public ZMoDoc gt(String nm, Object v) { 238 | put(nm, NEW("$gt", v)); 239 | return this; 240 | } 241 | 242 | public ZMoDoc lte(String nm, Object v) { 243 | put(nm, NEW("$lte", v)); 244 | return this; 245 | } 246 | 247 | public ZMoDoc lt(String nm, Object v) { 248 | put(nm, NEW("$lt", v)); 249 | return this; 250 | } 251 | 252 | public NutMap toNutMap() { 253 | NutMap map = new NutMap(); 254 | for (String key : this.keySet()) 255 | map.put(key, this.get(key)); 256 | return map; 257 | } 258 | 259 | // ------------------------------------------------------------ 260 | // 下面是一些便捷的方法赖访问字段的值 261 | public ObjectId getId() { 262 | return this.getAs("_id", ObjectId.class); 263 | } 264 | 265 | public ObjectId getAsId(String key) { 266 | Object obj = this.get(key); 267 | if (null == obj) 268 | return null; 269 | if (obj instanceof ObjectId) 270 | return (ObjectId) obj; 271 | return new ObjectId(obj.toString()); 272 | } 273 | 274 | public int getInt(String key) { 275 | return getInt(key, -1); 276 | } 277 | 278 | public int getInt(String key, int dft) { 279 | Object v = get(key); 280 | return null == v ? dft : Castors.me().castTo(v, int.class); 281 | } 282 | 283 | public float getFloat(String key) { 284 | return getFloat(key, Float.NaN); 285 | } 286 | 287 | public float getFloat(String key, float dft) { 288 | Object v = get(key); 289 | return null == v ? dft : Castors.me().castTo(v, float.class); 290 | } 291 | 292 | public long getLong(String key) { 293 | return getLong(key, -1L); 294 | } 295 | 296 | public long getLong(String key, long dft) { 297 | Object v = get(key); 298 | return null == v ? dft : Castors.me().castTo(v, long.class); 299 | } 300 | 301 | public double getDouble(String key) { 302 | return getDouble(key, Double.NaN); 303 | } 304 | 305 | public double getDouble(String key, double dft) { 306 | Object v = get(key); 307 | return null == v ? dft : Castors.me().castTo(v, double.class); 308 | } 309 | 310 | public boolean getBoolean(String key) { 311 | return getBoolean(key, false); 312 | } 313 | 314 | public boolean getBoolean(String key, boolean dft) { 315 | Object v = get(key); 316 | return null == v ? dft : Castors.me().castTo(v, boolean.class); 317 | } 318 | 319 | public String getString(String key) { 320 | return getString(key, null); 321 | } 322 | 323 | public String getString(String key, String dft) { 324 | Object v = get(key); 325 | return null == v ? dft : Castors.me().castTo(v, String.class); 326 | } 327 | 328 | public Date getTime(String key) { 329 | return getTime(key, null); 330 | } 331 | 332 | public Date getTime(String key, Date dft) { 333 | Object v = get(key); 334 | return null == v ? dft : Castors.me().castTo(v, Date.class); 335 | } 336 | 337 | public > T getEnum(String key, Class classOfEnum) { 338 | return getEnum(key, classOfEnum, null); 339 | } 340 | 341 | public > T getEnum(String key, Class classOfEnum, T dft) { 342 | String s = getString(key); 343 | if (Strings.isBlank(s)) 344 | return dft; 345 | return Castors.me().castTo(s, classOfEnum); 346 | } 347 | 348 | public boolean isEnum(String key, Enum... eus) { 349 | if (null == eus || eus.length == 0) 350 | return false; 351 | try { 352 | Enum v = getEnum(key, eus[0].getClass()); 353 | for (Enum eu : eus) 354 | if (!v.equals(eu)) 355 | return false; 356 | return true; 357 | } 358 | catch (Exception e) { 359 | return false; 360 | } 361 | } 362 | 363 | public T getAs(String key, Class classOfT) { 364 | return getAs(key, classOfT, null); 365 | } 366 | 367 | public T getAs(String key, Class classOfT, T dft) { 368 | Object v = get(key); 369 | return null == v ? dft : Castors.me().castTo(v, classOfT); 370 | } 371 | 372 | /** 373 | * 将一个字段转换成列表。因为返回的是容器,所以本函数永远不会返回 null 374 | * 375 | * @param 376 | * @param key 377 | * @param eleType 378 | * @return 列表对象,如果字段不存在或者为空,则返回一个空列表 379 | */ 380 | @SuppressWarnings("unchecked") 381 | public List getList(String key, final Class eleType) { 382 | Object v = get(key); 383 | if (null == v) 384 | return new ArrayList(); 385 | 386 | if (v instanceof CharSequence) { 387 | return Lang.list(Castors.me().castTo(v, eleType)); 388 | } 389 | 390 | int len = Lang.eleSize(v); 391 | final List list = new ArrayList(len); 392 | Lang.each(v, new Each() { 393 | public void invoke(int index, Object ele, int length) { 394 | list.add(Castors.me().castTo(ele, eleType)); 395 | } 396 | }); 397 | 398 | return list; 399 | 400 | } 401 | 402 | /** 403 | * 将一个字段转换成数组。因为返回的是容器,所以本函数永远不会返回 null 404 | * 405 | * @param 406 | * @param key 407 | * @param eleType 408 | * @return 数组对象,如果字段不存在或者为空,则返回一个空数组 409 | */ 410 | @SuppressWarnings("unchecked") 411 | public T[] getArray(String key, final Class eleType) { 412 | Object v = get(key); 413 | if (null == v) 414 | return (T[]) Array.newInstance(eleType, 0); 415 | 416 | if (v instanceof CharSequence) { 417 | return Lang.array(Castors.me().castTo(v, eleType)); 418 | } 419 | 420 | int len = Lang.eleSize(v); 421 | final Object arr = Array.newInstance(eleType, len); 422 | final int[] i = new int[]{0}; 423 | Lang.each(v, new Each() { 424 | public void invoke(int index, Object ele, int length) { 425 | Array.set(arr, i[0]++, Castors.me().castTo(ele, eleType)); 426 | } 427 | }); 428 | 429 | return (T[]) arr; 430 | 431 | } 432 | 433 | /** 434 | * 将自己包含的 DBObject 作为一个 List 435 | * 436 | * @param 437 | * @param classOfT 438 | * @return 439 | */ 440 | @SuppressWarnings("unchecked") 441 | public List asList(Class classOfT) { 442 | List list = asList(); 443 | ArrayList re = new ArrayList(list.size()); 444 | for (Object obj : list) { 445 | // NULL 446 | if (obj == null) { 447 | re.add((T) obj); 448 | continue; 449 | } 450 | Class objType = obj.getClass(); 451 | // 正好可以转型 452 | if (classOfT.isAssignableFrom(objType)) { 453 | re.add((T) obj); 454 | } 455 | // 如果是 DBObject 可以包裹成 ZMoDoc 456 | else if (classOfT == ZMoDoc.class && DBObject.class.isAssignableFrom(objType)) { 457 | re.add((T) ZMoDoc.WRAP((DBObject) obj)); 458 | } 459 | // 其他情况,试图强转一下 460 | else { 461 | re.add(Castors.me().castTo(obj, classOfT)); 462 | } 463 | } 464 | return re; 465 | } 466 | 467 | public List asList() { 468 | if (DBobj instanceof List) 469 | return (List) DBobj; 470 | throw Lang.makeThrow("wrapping DBobj not instanceof List : %s", DBobj.getClass()); 471 | } 472 | 473 | // ------------------------------------------------------------ 474 | // 下面都是委托方法 475 | 476 | public Object put(String key, Object v) { 477 | // 检查一下错误,防止 _id 输入错误 478 | if ("_id".equals(key)) { 479 | // 空值,表示移除 480 | if (v == null) { 481 | DBobj.removeField("_id"); 482 | return null; 483 | } 484 | // 普通的 ID 485 | else if (v instanceof ObjectId) { 486 | DBobj.put(key, v); 487 | return v; 488 | } 489 | // 如果是字符串,尝试转换 490 | else if (v instanceof CharSequence) { 491 | try { 492 | ObjectId id = new ObjectId(v.toString()); 493 | DBobj.put(key, id); 494 | return id; 495 | } 496 | catch (Exception e) { 497 | DBobj.put(key, v); // 容忍非法的ObjectId 498 | } 499 | } 500 | // 如果是 boolean 或者整数表示过滤 501 | else if (v instanceof Boolean || v instanceof Integer || v instanceof Long) { 502 | DBobj.put(key, v); 503 | return v; 504 | } 505 | // 否则不能接受 506 | else { 507 | throw Lang.makeThrow("doc._id should be ObjectID(), but '%s'", 508 | v.getClass().getName()); 509 | } 510 | } 511 | // 空值,直接压入 512 | else if (null == v) { 513 | DBobj.put(key, null); 514 | return null; 515 | } 516 | // 对于 ObjectId 517 | else if (v instanceof ObjectId) { 518 | DBobj.put(key, v); 519 | return v; 520 | } 521 | // 如果是枚举 522 | else if (v instanceof Enum) { 523 | DBobj.put(key, v.toString()); 524 | return v; 525 | } 526 | /* 527 | * 确定值不是空 528 | */ 529 | // 如果是 DBObject 就允许 530 | if (v instanceof DBObject) { 531 | return DBobj.put(key, v); 532 | } 533 | 534 | // 其他情况,适配一下 535 | Object o = ZMoAs.smart().toMongo(null, v); 536 | DBobj.put(key, o); 537 | return o; 538 | } 539 | 540 | public void markAsPartialObject() { 541 | DBobj.markAsPartialObject(); 542 | } 543 | 544 | public boolean isPartialObject() { 545 | return DBobj.isPartialObject(); 546 | } 547 | 548 | public void putAll(BSONObject o) { 549 | for (String key : o.keySet()) { 550 | put(key, o.get(key)); 551 | } 552 | } 553 | 554 | @SuppressWarnings("rawtypes") 555 | public void putAll(Map m) { 556 | for (Object key : m.keySet()) { 557 | if (null != key) 558 | put(key.toString(), m.get(key)); 559 | } 560 | } 561 | 562 | public Object get(String key) { 563 | return DBobj.get(key); 564 | } 565 | 566 | @SuppressWarnings("rawtypes") 567 | public Map toMap() { 568 | return DBobj.toMap(); 569 | } 570 | 571 | public Object removeField(String key) { 572 | return DBobj.removeField(key); 573 | } 574 | 575 | public boolean containsKey(String s) { 576 | return DBobj.containsField(s); 577 | } 578 | 579 | public boolean containsField(String s) { 580 | return DBobj.containsField(s); 581 | } 582 | 583 | public Set keySet() { 584 | return DBobj.keySet(); 585 | } 586 | 587 | public int size() { 588 | return DBobj.keySet().size(); 589 | } 590 | 591 | public boolean isEmpty() { 592 | return size() == 0; 593 | } 594 | 595 | public String toString() { 596 | return DBobj.toString(); 597 | } 598 | 599 | public ZMoDoc clone() { 600 | ZMoDoc doc = ZMoDoc.NEW(); 601 | for (String key : keySet()) 602 | doc.put(key, get(key)); 603 | return doc; 604 | } 605 | } 606 | -------------------------------------------------------------------------------- /java/src/org/nutz/mongo/ZMoCo.java: -------------------------------------------------------------------------------- 1 | package org.nutz.mongo; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collection; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import org.nutz.dao.pager.Pager; 10 | import org.nutz.json.Json; 11 | import org.nutz.json.JsonFormat; 12 | import org.nutz.lang.util.Callback; 13 | import org.nutz.log.Log; 14 | import org.nutz.log.Logs; 15 | import org.nutz.mongo.entity.ZMoEntity; 16 | 17 | import com.mongodb.AggregationOptions; 18 | import com.mongodb.AggregationOutput; 19 | import com.mongodb.CommandResult; 20 | import com.mongodb.Cursor; 21 | import com.mongodb.DBCollection; 22 | import com.mongodb.DBCursor; 23 | import com.mongodb.DBDecoderFactory; 24 | import com.mongodb.DBEncoder; 25 | import com.mongodb.DBEncoderFactory; 26 | import com.mongodb.DBObject; 27 | import com.mongodb.GroupCommand; 28 | import com.mongodb.MapReduceCommand; 29 | import com.mongodb.MapReduceCommand.OutputType; 30 | import com.mongodb.MapReduceOutput; 31 | import com.mongodb.MongoNamespace; 32 | import com.mongodb.ReadPreference; 33 | import com.mongodb.WriteConcern; 34 | import com.mongodb.WriteResult; 35 | import com.mongodb.operation.AggregateOperation; 36 | 37 | /** 38 | * 对于集合类的薄封装 39 | * 40 | * @author zozoh(zozohtnt@gmail.com) 41 | */ 42 | public class ZMoCo { 43 | 44 | private DBCollection dbc; 45 | 46 | private static final Log log = Logs.get(); 47 | 48 | public ZMoCo(DBCollection c) { 49 | this.dbc = c; 50 | } 51 | 52 | public WriteResult insert(ZMoDoc[] arr, WriteConcern concern) { 53 | if (log.isDebugEnabled()) 54 | log.debug(log_format("insert", arr, concern)); 55 | return dbc.insert(arr, concern); 56 | } 57 | 58 | public WriteResult insert(ZMoDoc[] arr, WriteConcern concern, DBEncoder encoder) { 59 | if (log.isDebugEnabled()) 60 | log.debug(log_format("insert", arr, concern, encoder)); 61 | return dbc.insert(arr, concern, encoder); 62 | } 63 | 64 | public WriteResult insert(ZMoDoc o, WriteConcern concern) { 65 | if (log.isDebugEnabled()) 66 | log.debug(log_format("insert", o, concern)); 67 | return dbc.insert(o, concern); 68 | } 69 | 70 | public WriteResult insert(ZMoDoc... arr) { 71 | if (log.isDebugEnabled()) 72 | log.debug(log_format("insert", (Object)arr)); 73 | return dbc.insert(arr); 74 | } 75 | 76 | public WriteResult insert(WriteConcern concern, ZMoDoc... arr) { 77 | if (log.isDebugEnabled()) 78 | log.debug(log_format("insert", concern, (Object)arr)); 79 | return dbc.insert(concern, arr); 80 | } 81 | 82 | @SuppressWarnings({"unchecked", "rawtypes"}) 83 | public WriteResult insert(List list) { 84 | if (log.isDebugEnabled()) 85 | log.debug(log_format("insert", list)); 86 | return dbc.insert((List) list); 87 | } 88 | 89 | @SuppressWarnings({"unchecked", "rawtypes"}) 90 | public WriteResult insert(List list, WriteConcern concern) { 91 | if (log.isDebugEnabled()) 92 | log.debug(log_format("insert", list, concern)); 93 | return dbc.insert((List) list, concern); 94 | } 95 | 96 | @SuppressWarnings({"unchecked", "rawtypes"}) 97 | public WriteResult insert(List list, WriteConcern concern, DBEncoder encoder) { 98 | if (log.isDebugEnabled()) 99 | log.debug(log_format("insert", list, concern, encoder)); 100 | return dbc.insert((List) list, concern, encoder); 101 | } 102 | 103 | public WriteResult update(ZMoDoc q, 104 | ZMoDoc o, 105 | boolean upsert, 106 | boolean multi, 107 | WriteConcern concern) { 108 | if (log.isDebugEnabled()) 109 | log.debug(log_format("update", q, o, upsert, multi, concern)); 110 | return dbc.update(q, o, upsert, multi, concern); 111 | } 112 | 113 | public WriteResult update(ZMoDoc q, 114 | ZMoDoc o, 115 | boolean upsert, 116 | boolean multi, 117 | WriteConcern concern, 118 | DBEncoder encoder) { 119 | if (log.isDebugEnabled()) 120 | log.debug(log_format("update", q, o, upsert, multi, concern, encoder)); 121 | return dbc.update(q, o, upsert, multi, concern, encoder); 122 | } 123 | 124 | public WriteResult update(ZMoDoc q, ZMoDoc o, boolean upsert, boolean multi) { 125 | if (log.isDebugEnabled()) 126 | log.debug(log_format("update", q, o, upsert, multi)); 127 | return dbc.update(q, o, upsert, multi); 128 | } 129 | 130 | public WriteResult update(ZMoDoc q, ZMoDoc o) { 131 | if (log.isDebugEnabled()) 132 | log.debug(log_format("update", q, o)); 133 | return dbc.update(q, o); 134 | } 135 | 136 | public WriteResult updateMulti(ZMoDoc q, ZMoDoc o) { 137 | if (log.isDebugEnabled()) 138 | log.debug(log_format("updateMulti", q, o)); 139 | return dbc.updateMulti(q, o); 140 | } 141 | 142 | public WriteResult remove(ZMoDoc o, WriteConcern concern) { 143 | if (log.isDebugEnabled()) 144 | log.debug(log_format("remove", o, concern)); 145 | return dbc.remove(o, concern); 146 | } 147 | 148 | public WriteResult remove(ZMoDoc o, WriteConcern concern, DBEncoder encoder) { 149 | if (log.isDebugEnabled()) 150 | log.debug(log_format("remove", o, concern, encoder)); 151 | return dbc.remove(o, concern, encoder); 152 | } 153 | 154 | public WriteResult remove(ZMoDoc o) { 155 | if (log.isDebugEnabled()) 156 | log.debug(log_format("remove", o)); 157 | return dbc.remove(o); 158 | } 159 | 160 | public ZMoDoc findAndModify(ZMoDoc query, 161 | ZMoDoc fields, 162 | ZMoDoc sort, 163 | boolean remove, 164 | ZMoDoc update, 165 | boolean returnNew, 166 | boolean upsert) { 167 | if (log.isDebugEnabled()) 168 | log.debug(log_format("findAndModify", query, fields, sort, remove, update, returnNew, upsert)); 169 | return ZMoDoc.WRAP(dbc.findAndModify(query, 170 | fields, 171 | sort, 172 | remove, 173 | update, 174 | returnNew, 175 | upsert)); 176 | } 177 | 178 | public ZMoDoc findAndModify(ZMoDoc query, ZMoDoc sort, ZMoDoc update) { 179 | if (log.isDebugEnabled()) 180 | log.debug(log_format("findAndModify", query, sort, update)); 181 | return ZMoDoc.WRAP(dbc.findAndModify(query, sort, update)); 182 | } 183 | 184 | public ZMoDoc findAndModify(ZMoDoc query, ZMoDoc update) { 185 | if (log.isDebugEnabled()) 186 | log.debug(log_format("findAndModify", query,update)); 187 | return ZMoDoc.WRAP(dbc.findAndModify(query, update)); 188 | } 189 | 190 | public ZMoDoc findAndRemove(ZMoDoc query) { 191 | if (log.isDebugEnabled()) 192 | log.debug(log_format("findAndRemove", query)); 193 | return ZMoDoc.WRAP(dbc.findAndRemove(query)); 194 | } 195 | 196 | public void createIndex(ZMoDoc keys) { 197 | if (log.isDebugEnabled()) 198 | log.debug(log_format("createIndex", keys)); 199 | dbc.createIndex(keys); 200 | } 201 | 202 | public void createIndex(ZMoDoc keys, ZMoDoc options) { 203 | if (log.isDebugEnabled()) 204 | log.debug(log_format("createIndex", keys, options)); 205 | dbc.createIndex(keys, options); 206 | } 207 | 208 | @SuppressWarnings({"unchecked", "rawtypes"}) 209 | public void setHintFields(List lst) { 210 | if (log.isDebugEnabled()) 211 | log.debug(log_format("setHintFields", lst)); 212 | dbc.setHintFields((List) lst); 213 | } 214 | 215 | public DBCursor find(ZMoDoc ref) { 216 | if (log.isDebugEnabled()) 217 | log.debug(log_format("find", ref)); 218 | return dbc.find(ref); 219 | } 220 | 221 | public DBCursor find(ZMoDoc ref, ZMoDoc keys) { 222 | if (log.isDebugEnabled()) 223 | log.debug(log_format("find", ref, keys)); 224 | return dbc.find(ref, keys); 225 | } 226 | 227 | public DBCursor find() { 228 | if (log.isDebugEnabled()) 229 | log.debug(log_format("find")); 230 | return dbc.find(); 231 | } 232 | 233 | public ZMoDoc findOne() { 234 | if (log.isDebugEnabled()) 235 | log.debug(log_format("findOne")); 236 | return ZMoDoc.WRAP(dbc.findOne()); 237 | } 238 | 239 | public ZMoDoc findOne(ZMoDoc o) { 240 | if (log.isDebugEnabled()) 241 | log.debug(log_format("findOne", o)); 242 | return ZMoDoc.WRAP(dbc.findOne(o)); 243 | } 244 | 245 | public ZMoDoc findOne(ZMoDoc o, ZMoDoc fields) { 246 | if (log.isDebugEnabled()) 247 | log.debug(log_format("findOne", o, fields)); 248 | return ZMoDoc.WRAP(dbc.findOne(o, fields)); 249 | } 250 | 251 | public ZMoDoc findOne(ZMoDoc o, ZMoDoc fields, ZMoDoc orderBy) { 252 | if (log.isDebugEnabled()) 253 | log.debug(log_format("findOne", o, fields, orderBy)); 254 | return ZMoDoc.WRAP(dbc.findOne(o, fields, orderBy)); 255 | } 256 | 257 | public ZMoDoc findOne(ZMoDoc o, ZMoDoc fields, ReadPreference readPref) { 258 | if (log.isDebugEnabled()) 259 | log.debug(log_format("findOne", o, fields, readPref)); 260 | return ZMoDoc.WRAP(dbc.findOne(o, fields, readPref)); 261 | } 262 | 263 | public ZMoDoc findOne(ZMoDoc o, ZMoDoc fields, ZMoDoc orderBy, ReadPreference readPref) { 264 | if (log.isDebugEnabled()) 265 | log.debug(log_format("findOne", o, fields, orderBy, readPref)); 266 | return ZMoDoc.WRAP(dbc.findOne(o, fields, orderBy, readPref)); 267 | } 268 | 269 | public WriteResult save(ZMoDoc jo) { 270 | if (log.isDebugEnabled()) 271 | log.debug(log_format("save", jo)); 272 | return dbc.save(jo); 273 | } 274 | 275 | public WriteResult save(ZMoDoc jo, WriteConcern concern) { 276 | if (log.isDebugEnabled()) 277 | log.debug(log_format("save", jo, concern)); 278 | return dbc.save(jo, concern); 279 | } 280 | 281 | public void dropIndexes() { 282 | if (log.isDebugEnabled()) 283 | log.debug(log_format("dropIndexes")); 284 | dbc.dropIndexes(); 285 | } 286 | 287 | public void dropIndexes(String name) { 288 | if (log.isDebugEnabled()) 289 | log.debug(log_format("dropIndexes", name)); 290 | dbc.dropIndexes(name); 291 | } 292 | 293 | public void drop() { 294 | if (log.isDebugEnabled()) 295 | log.debug(log_format("drop")); 296 | dbc.drop(); 297 | } 298 | 299 | public long count() { 300 | if (log.isDebugEnabled()) 301 | log.debug(log_format("count")); 302 | return dbc.count(); 303 | } 304 | 305 | public long count(ZMoDoc query) { 306 | if (log.isDebugEnabled()) 307 | log.debug(log_format("count", query)); 308 | return dbc.count(query); 309 | } 310 | 311 | public long count(ZMoDoc query, ReadPreference readPrefs) { 312 | if (log.isDebugEnabled()) 313 | log.debug(log_format("count", query, readPrefs)); 314 | return dbc.count(query, readPrefs); 315 | } 316 | 317 | public long getCount() { 318 | if (log.isDebugEnabled()) 319 | log.debug(log_format("getCount")); 320 | return dbc.getCount(); 321 | } 322 | 323 | public long getCount(ReadPreference readPrefs) { 324 | if (log.isDebugEnabled()) 325 | log.debug(log_format("getCount", readPrefs)); 326 | return dbc.getCount(readPrefs); 327 | } 328 | 329 | public long getCount(ZMoDoc query) { 330 | if (log.isDebugEnabled()) 331 | log.debug(log_format("getCount", query)); 332 | return dbc.getCount(query); 333 | } 334 | 335 | public long getCount(ZMoDoc query, ZMoDoc fields) { 336 | if (log.isDebugEnabled()) 337 | log.debug(log_format("getCount", query, fields)); 338 | return dbc.getCount(query, fields); 339 | } 340 | 341 | public long getCount(ZMoDoc query, ZMoDoc fields, ReadPreference readPrefs) { 342 | if (log.isDebugEnabled()) 343 | log.debug(log_format("getCount", query, fields, readPrefs)); 344 | return dbc.getCount(query, fields, readPrefs); 345 | } 346 | 347 | public long getCount(ZMoDoc query, ZMoDoc fields, long limit, long skip) { 348 | if (log.isDebugEnabled()) 349 | log.debug(log_format("getCount", query, fields, limit, skip)); 350 | return dbc.getCount(query, fields, limit, skip); 351 | } 352 | 353 | public long getCount(ZMoDoc query, 354 | ZMoDoc fields, 355 | long limit, 356 | long skip, 357 | ReadPreference readPrefs) { 358 | if (log.isDebugEnabled()) 359 | log.debug(log_format("getCount", query, fields, limit, skip, readPrefs)); 360 | return dbc.getCount(query, fields, limit, skip, readPrefs); 361 | } 362 | 363 | public DBCollection rename(String newName) { 364 | if (log.isDebugEnabled()) 365 | log.debug(log_format("rename", newName)); 366 | return dbc.rename(newName); 367 | } 368 | 369 | public DBCollection rename(String newName, boolean dropTarget) { 370 | if (log.isDebugEnabled()) 371 | log.debug(log_format("rename", newName, dropTarget)); 372 | return dbc.rename(newName, dropTarget); 373 | } 374 | 375 | public ZMoDoc group(ZMoDoc key, ZMoDoc cond, ZMoDoc initial, String reduce) { 376 | if (log.isDebugEnabled()) 377 | log.debug(log_format("group", key, cond, initial, reduce)); 378 | return ZMoDoc.WRAP(dbc.group(key, cond, initial, reduce)); 379 | } 380 | 381 | public ZMoDoc group(ZMoDoc key, ZMoDoc cond, ZMoDoc initial, String reduce, String finalize) { 382 | if (log.isDebugEnabled()) 383 | log.debug(log_format("group", key, cond, initial, reduce, finalize)); 384 | return ZMoDoc.WRAP(dbc.group(key, cond, initial, reduce, finalize)); 385 | } 386 | 387 | public ZMoDoc group(ZMoDoc key, 388 | ZMoDoc cond, 389 | ZMoDoc initial, 390 | String reduce, 391 | String finalize, 392 | ReadPreference readPrefs) { 393 | if (log.isDebugEnabled()) 394 | log.debug(log_format("group", key, cond, initial, reduce, finalize, readPrefs)); 395 | return ZMoDoc.WRAP(dbc.group(key, cond, initial, reduce, finalize, readPrefs)); 396 | } 397 | 398 | public ZMoDoc group(GroupCommand cmd) { 399 | if (log.isDebugEnabled()) 400 | log.debug(log_format("group", cmd)); 401 | return ZMoDoc.WRAP(dbc.group(cmd)); 402 | } 403 | 404 | public ZMoDoc group(GroupCommand cmd, ReadPreference readPrefs) { 405 | if (log.isDebugEnabled()) 406 | log.debug(log_format("group", cmd, readPrefs)); 407 | return ZMoDoc.WRAP(dbc.group(cmd, readPrefs)); 408 | } 409 | 410 | public List distinct(String key) { 411 | if (log.isDebugEnabled()) 412 | log.debug(log_format("distinct", key)); 413 | return dbc.distinct(key); 414 | } 415 | 416 | public List distinct(String key, ReadPreference readPrefs) { 417 | if (log.isDebugEnabled()) 418 | log.debug(log_format("distinct", key, readPrefs)); 419 | return dbc.distinct(key, readPrefs); 420 | } 421 | 422 | public List distinct(String key, ZMoDoc query) { 423 | if (log.isDebugEnabled()) 424 | log.debug(log_format("distinct", key, query)); 425 | return dbc.distinct(key, query); 426 | } 427 | 428 | public List distinct(String key, ZMoDoc query, ReadPreference readPrefs) { 429 | if (log.isDebugEnabled()) 430 | log.debug(log_format("distinct", key, query, readPrefs)); 431 | return dbc.distinct(key, query, readPrefs); 432 | } 433 | 434 | public MapReduceOutput mapReduce(String map, String reduce, String outputTarget, ZMoDoc query) { 435 | if (log.isDebugEnabled()) 436 | log.debug(log_format("mapReduce", map, reduce, outputTarget, query)); 437 | return dbc.mapReduce(map, reduce, outputTarget, query); 438 | } 439 | 440 | public MapReduceOutput mapReduce(String map, 441 | String reduce, 442 | String outputTarget, 443 | OutputType outputType, 444 | ZMoDoc query) { 445 | if (log.isDebugEnabled()) 446 | log.debug(log_format("mapReduce", map, reduce, outputTarget, query)); 447 | return dbc.mapReduce(map, reduce, outputTarget, outputType, query); 448 | } 449 | 450 | public MapReduceOutput mapReduce(String map, 451 | String reduce, 452 | String outputTarget, 453 | OutputType outputType, 454 | ZMoDoc query, 455 | ReadPreference readPrefs) { 456 | if (log.isDebugEnabled()) 457 | log.debug(log_format("mapReduce", map, reduce, outputTarget, query, readPrefs)); 458 | return dbc.mapReduce(map, reduce, outputTarget, outputType, query, readPrefs); 459 | } 460 | 461 | public MapReduceOutput mapReduce(MapReduceCommand command) { 462 | if (log.isDebugEnabled()) 463 | log.debug(log_format("mapReduce", command)); 464 | return dbc.mapReduce(command); 465 | } 466 | 467 | public AggregationOutput aggregate(final List pipeline) { 468 | if (log.isDebugEnabled()) 469 | log.debug(log_format("aggregate", pipeline)); 470 | return dbc.aggregate(pipeline); 471 | } 472 | 473 | public Cursor aggregate(final List pipeline, final AggregationOptions options) { 474 | if (log.isDebugEnabled()) 475 | log.debug(log_format("aggregate", pipeline)); 476 | return dbc.aggregate(pipeline, options); 477 | } 478 | 479 | public void aggregate(final List pipeline, final AggregationOptions options, Callback callback) { 480 | Cursor cursor = aggregate(pipeline, options); 481 | try { 482 | callback.invoke(cursor); 483 | } finally { 484 | cursor.close(); 485 | } 486 | } 487 | 488 | public List getIndexInfo() { 489 | List dbobjs = dbc.getIndexInfo(); 490 | List list = new ArrayList(dbobjs.size()); 491 | for (DBObject dbojb : dbobjs) 492 | list.add(ZMoDoc.WRAP(dbojb)); 493 | return list; 494 | } 495 | 496 | public void dropIndex(ZMoDoc keys) { 497 | if (log.isDebugEnabled()) 498 | log.debug(log_format("dropIndex", keys)); 499 | dbc.dropIndex(keys); 500 | } 501 | 502 | public void dropIndex(String name) { 503 | if (log.isDebugEnabled()) 504 | log.debug(log_format("dropIndex", name)); 505 | dbc.dropIndex(name); 506 | } 507 | 508 | public CommandResult getStats() { 509 | if (log.isDebugEnabled()) 510 | log.debug(log_format("getStats")); 511 | return dbc.getStats(); 512 | } 513 | 514 | public boolean isCapped() { 515 | if (log.isDebugEnabled()) 516 | log.debug(log_format("isCapped")); 517 | return dbc.isCapped(); 518 | } 519 | 520 | public ZMoCo getCollection(String n) { 521 | return new ZMoCo(dbc.getCollection(n)); 522 | } 523 | 524 | public String getName() { 525 | return dbc.getName(); 526 | } 527 | 528 | public String getFullName() { 529 | return dbc.getFullName(); 530 | } 531 | 532 | public ZMoDB getDB() { 533 | return new ZMoDB(dbc.getDB()); 534 | } 535 | 536 | public int hashCode() { 537 | return dbc.hashCode(); 538 | } 539 | 540 | public boolean equals(Object o) { 541 | return dbc.equals(o); 542 | } 543 | 544 | public String toString() { 545 | return dbc.toString(); 546 | } 547 | 548 | public void setObjectClass(Class c) { 549 | dbc.setObjectClass(c); 550 | } 551 | 552 | public Class getObjectClass() { 553 | return dbc.getObjectClass(); 554 | } 555 | 556 | public void setInternalClass(String path, Class c) { 557 | dbc.setInternalClass(path, c); 558 | } 559 | 560 | public void setWriteConcern(WriteConcern concern) { 561 | dbc.setWriteConcern(concern); 562 | } 563 | 564 | public WriteConcern getWriteConcern() { 565 | return dbc.getWriteConcern(); 566 | } 567 | 568 | public void setReadPreference(ReadPreference preference) { 569 | dbc.setReadPreference(preference); 570 | } 571 | 572 | public ReadPreference getReadPreference() { 573 | return dbc.getReadPreference(); 574 | } 575 | 576 | public void addOption(int option) { 577 | dbc.addOption(option); 578 | } 579 | 580 | public void setOptions(int options) { 581 | dbc.setOptions(options); 582 | } 583 | 584 | public void resetOptions() { 585 | dbc.resetOptions(); 586 | } 587 | 588 | public int getOptions() { 589 | return dbc.getOptions(); 590 | } 591 | 592 | public void setDBDecoderFactory(DBDecoderFactory fact) { 593 | dbc.setDBDecoderFactory(fact); 594 | } 595 | 596 | public DBDecoderFactory getDBDecoderFactory() { 597 | return dbc.getDBDecoderFactory(); 598 | } 599 | 600 | public void setDBEncoderFactory(DBEncoderFactory fact) { 601 | dbc.setDBEncoderFactory(fact); 602 | } 603 | 604 | public DBEncoderFactory getDBEncoderFactory() { 605 | return dbc.getDBEncoderFactory(); 606 | } 607 | 608 | protected String _to_json(Object obj) { 609 | return Json.toJson(obj, JsonFormat.compact().setIgnoreNull(false)); 610 | } 611 | 612 | protected String log_format(String op, Object...args) { 613 | StringBuilder sb = new StringBuilder("db.").append(getName()).append('.').append(op).append('('); 614 | for (int i = 0; i < args.length; i++) { 615 | Object arg = args[i]; 616 | if (arg != null && (arg instanceof Map || arg.getClass().isArray() || arg instanceof Collection)) 617 | sb.append(_to_json(arg)); 618 | else 619 | sb.append(arg); 620 | if (i != args.length - 1) 621 | sb.append(", "); 622 | } 623 | sb.append(')'); 624 | return sb.toString(); 625 | } 626 | 627 | //---------------------------------------------------------------------------------- 628 | // ORM 相关的方法, 类似的 629 | /** 630 | * 查询符合条件的对象 631 | * @param klass 需要映射的对象 632 | * @param ref 查询条件 633 | * @param keys 需要检出的键,可以是null 634 | * @param pager 分页对象,recordCount会自动设置, 可以是null 635 | * @return 符合条件的对象 636 | */ 637 | public List query(Class klass, ZMoDoc ref, ZMoDoc keys, Pager pager) { 638 | return query(ZMo.me().getEntity(klass), ref, keys, pager); 639 | } 640 | /** 641 | * 查询符合条件的对象 642 | * @param klass 需要映射的对象 643 | * @param ref 查询条件 644 | * @param pager 分页对象,recordCount会自动设置, 可以是null 645 | * @return 符合条件的对象 646 | */ 647 | public List query(Class klass, ZMoDoc ref, Pager pager) { 648 | return query(ZMo.me().getEntity(klass), ref, null, pager); 649 | } 650 | /** 651 | * 查询符合条件的对象 652 | * @param klass 需要映射的对象 653 | * @param ref 查询条件 654 | * @param pageNumber 页数,例如2 655 | * @param pageSize 分页大小,例如10 656 | * @return 符合条件的对象 657 | */ 658 | public List query(Class klass, ZMoDoc ref, int pageNumber, int pageSize) { 659 | return query(ZMo.me().getEntity(klass), ref, null, new Pager(pageNumber, pageSize)); 660 | } 661 | 662 | /** 663 | * 查询符合条件的对象 664 | * @param klass 需要映射的对象 665 | * @param ref 查询条件 666 | * @param keys 需要检出的键,可以是null 667 | * @param pageNumber 页数,例如2 668 | * @param pageSize 分页大小,例如10 669 | * @return 符合条件的对象 670 | */ 671 | public List query(Class klass, ZMoDoc ref, ZMoDoc keys, int pageNumber, int pageSize) { 672 | return query(ZMo.me().getEntity(klass), ref, keys, new Pager(pageNumber, pageSize)); 673 | } 674 | /** 675 | * 查询符合条件的对象ZMoEntity 676 | * @param en 需要映射的实体 677 | * @param ref 查询条件 678 | * @param keys 需要检出的键,可以是null 679 | * @param pager 分页对象 680 | * @return 符合条件的对象 681 | */ 682 | @SuppressWarnings("unchecked") 683 | public List query(ZMoEntity en, ZMoDoc ref, ZMoDoc keys, Pager pager) { 684 | DBCursor cur = find(ref, keys); 685 | if (pager != null) { 686 | pager.setRecordCount(cur.count()); 687 | cur.skip(pager.getOffset()).limit(pager.getPageSize()); 688 | } 689 | List list = new ArrayList(); 690 | while (cur.hasNext()) { 691 | list.add((T)ZMo.me().fromDoc(cur.next(), en)); 692 | } 693 | return list; 694 | } 695 | /** 696 | * 查询符合条件的一个对象 697 | * @param klass 需要映射的类 698 | * @param ref 查询条件 699 | * @param keys 需要检出的键,可以是null 700 | * @return 符合条件的一个对象 701 | */ 702 | public T fetch(Class klass, ZMoDoc ref, ZMoDoc keys) { 703 | return fetch(ZMo.me().getEntity(klass), ref, keys); 704 | } 705 | /** 706 | * 查询符合条件的一个对象 707 | * @param klass 需要映射的类 708 | * @param ref 查询条件 709 | * @return 符合条件的一个对象 710 | */ 711 | public T fetch(Class klass, ZMoDoc keys) { 712 | return fetch(ZMo.me().getEntity(klass), null, keys); 713 | } 714 | /** 715 | * 查询符合条件的一个对象 716 | * @param en 需要映射的实体 717 | * @param ref 查询条件 718 | * @param keys 需要检出的键,可以是null 719 | * @return 符合条件的一个对象 720 | */ 721 | public T fetch(ZMoEntity en, ZMoDoc ref, ZMoDoc keys) { 722 | List list = query(en, ref, keys, new Pager(1, 1)); 723 | if (list.isEmpty()) 724 | return null; 725 | return list.get(0); 726 | } 727 | 728 | } 729 | --------------------------------------------------------------------------------